:root {
  color-scheme: dark;
  --bg: #000000;
  --bg-soft: #1c1c1e;
  --bg-elev: #1c1c1e;
  --text: #f5f5f7;
  --muted: #a1a1a6;
  --muted-2: #8e8e93;
  --accent: #00d95f;
  --accent-2: #00ffa3;
  --border: rgba(255, 255, 255, 0.1);
  --border-strong: rgba(255, 255, 255, 0.18);
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 8px 28px rgba(0, 0, 0, 0.6);
  --radius: 14px;
  --radius-sm: 10px;
  /* One font everywhere — headings use the same Poppins stack as body text. */
  --font-display: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI",
                  system-ui, sans-serif;
  --art-ph: linear-gradient(135deg, #232326, #16161a);
  --focus-ring: 0 0 0 3px rgba(0, 217, 95, 0.45);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  min-height: 100%;
  /* Don't let the browser auto-shift scroll when content above swaps
     (e.g. the centered loader is replaced by a long genre/artist list). */
  overflow-anchor: none;
  scroll-padding-top: 72px;
  background: var(--bg);
  color: var(--text);
  font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI",
               system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  touch-action: pan-x pan-y;
  -webkit-text-size-adjust: 100%;
}

a { color: var(--accent); text-decoration: none; }
::selection { background: rgba(0, 217, 95, 0.2); }

/* Visible focus rings for keyboard users (a11y); pointer clicks stay clean. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}

/* Structural icons: scale to the button's font-size, render crisply. */
.glyph { display: inline-flex; align-items: center; justify-content: center; }
.glyph svg, .card .dl svg { width: 1em; height: 1em; display: block; }
.btn-play svg, .btn-ghost svg { width: 16px; height: 16px; display: block; }
#player-close svg { width: 16px; height: 16px; display: block; }

/* Inline spinner used inside buttons during async actions. */
.btn-spin {
  display: inline-block; width: 1em; height: 1em;
  border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 50%; opacity: 0.75;
  animation: spin 0.65s linear infinite;
}

/* ---------- top bar ---------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--border);
}
.topbar-inner {
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr minmax(0, 520px) 1fr;
  gap: 16px;
  align-items: center;
  padding: 12px 22px;
}
.brand { justify-self: start; }
.topbar-inner .search-wrap { justify-self: stretch; width: 100%; }
.controls { justify-self: end; }

.brand { display: flex; align-items: center; gap: 10px; color: var(--text); }
.logo { display: grid; place-items: center; height: 30px; }
.brand-mark { display: block; height: 30px; width: auto; }
.brand-name {
  font-family: "Righteous", var(--font-display);
  font-size: 22px; font-weight: 400; letter-spacing: 0.2px;
}
.brand-name span { color: var(--accent); }

.controls { display: flex; gap: 10px; align-items: center; }

.search-wrap { position: relative; display: flex; align-items: center; }
.search-icon {
  position: absolute; left: 11px;
  width: 16px; height: 16px; color: var(--muted-2);
  pointer-events: none;
}
.search-wrap input,
.controls select {
  background: var(--bg-soft);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 11px;
  padding: 10px 14px;
  font-size: 14px;
  font-family: inherit;
  outline: none;
  transition: border-color 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
}
.search-wrap input { width: 100%; padding-left: 38px; text-align: center; }
.search-wrap input:focus { text-align: left; }
.search-wrap input::placeholder { color: var(--muted-2); }
.search-wrap input:focus,
.controls select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(0, 217, 95, 0.15);
  background: var(--bg);
}

/* Section tabs (Свежак / Жанры / Топ 100) — plain text with an active underline,
   Beatport-style, no button chrome. */
.controls { gap: 16px; }
.nav-tabs { display: flex; align-items: center; gap: 22px; }
.nav-btn {
  display: inline-flex; align-items: center;
  background: none; border: 0; padding: 6px 1px 8px;
  color: var(--muted); white-space: nowrap; cursor: pointer;
  font-family: var(--font-display); font-size: 15px; letter-spacing: 0.2px;
  position: relative;
  transition: color 0.18s ease;
}
.nav-btn svg { width: 18px; height: 18px; }
/* Underline: a pseudo-element so toggling it never shifts the layout. */
.nav-btn::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px; border-radius: 2px; background: var(--accent);
  transform: scaleX(0); transform-origin: center;
  transition: transform 0.2s cubic-bezier(0.2, 0.9, 0.2, 1);
}
@media (hover: hover) {
  .nav-btn:hover { color: var(--text); }
}

.nav-btn.active { color: var(--accent); }
.nav-btn.active::after { transform: scaleX(1); }

.select-wrap { position: relative; display: flex; align-items: center; }
.controls select {
  appearance: none; -webkit-appearance: none;
  padding-right: 32px; cursor: pointer;
}
.controls select option { background: var(--bg); color: var(--text); }
.chevron {
  position: absolute; right: 9px;
  width: 16px; height: 16px; color: var(--muted-2);
  pointer-events: none;
}

/* ---------- main ---------- */
main { max-width: 1200px; margin: 0 auto; padding: 20px 22px 160px; }
/* Fill at least the viewport so the SEO text below always starts off-screen —
   the user only sees it after scrolling a bit, on any page. */
.content { min-height: calc(100vh - var(--topbar-h, 60px)); }

.status {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  min-height: min(68vh, 560px);
  text-align: center;
  color: var(--muted); font-size: 15px;
}
.status:empty { display: none; }
.spinner {
  width: 28px; height: 28px; border-radius: 50%;
  border: 3px solid var(--border-strong);
  border-top-color: var(--accent);
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.empty {
  display: flex; align-items: center; justify-content: center;
  min-height: min(60vh, 480px);
  text-align: center;
  color: var(--muted); padding: 24px; font-size: 15px;
}

/* ---------- featured banner ---------- */
.featured {
  position: relative;
  border-radius: 20px;
  overflow: hidden;
  margin: 0 0 30px;
  isolation: isolate;
}
.featured-bg {
  position: absolute; inset: 0; z-index: -1;
  background-image: var(--art);
  background-size: cover; background-position: center;
  filter: blur(40px) saturate(160%) brightness(0.8);
  transform: scale(1.3);
}
.featured-bg::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(0,0,0,0.65), rgba(0,0,0,0.35));
}
.featured-inner {
  position: relative;
  display: flex; align-items: center; gap: 26px;
  padding: 32px;
}
.featured-art {
  width: 168px; height: 168px; flex: 0 0 auto;
  border-radius: 14px; object-fit: cover;
  box-shadow: 0 16px 40px rgba(0,0,0,0.45);
}
.featured-art.ph { background: rgba(255,255,255,0.15); }
.featured-info { min-width: 0; color: #fff; }
.featured-eyebrow {
  font-size: 12px; font-weight: 700; letter-spacing: 1px;
  text-transform: uppercase; color: rgba(255,255,255,0.85);
}
.featured-title {
  margin: 8px 0 4px;
  font-size: clamp(24px, 4vw, 40px); font-weight: 800; letter-spacing: -0.5px;
  line-height: 1.05;
}
.featured-title span { font-weight: 500; opacity: 0.7; }
.featured-artist { margin: 0 0 18px; font-size: 16px; color: rgba(255,255,255,0.9); }
.featured-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.btn-play {
  display: inline-flex; align-items: center; gap: 7px;
  background: #fff; color: #000;
  border: 0; border-radius: 999px;
  padding: 10px 22px; font-size: 14px; font-weight: 600;
  cursor: pointer; transition: transform 0.15s ease, background 0.15s ease;
}
.btn-play .glyph { color: var(--accent); }
@media (hover: hover) {
  .btn-play:hover { transform: scale(1.03); }
}

.btn-ghost {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(255,255,255,0.18); color: #fff;
  border: 1px solid rgba(255,255,255,0.3); border-radius: 999px;
  padding: 10px 18px; font-size: 14px; font-weight: 600;
  cursor: pointer; transition: background 0.15s ease;
}
@media (hover: hover) {
  .btn-ghost:hover { background: rgba(255,255,255,0.28); }
}

.btn-ghost:disabled { opacity: 0.6; cursor: default; }

/* White download CTA — clearly visible on the dark banner; states 320 kbps. */
.btn-white {
  display: inline-flex; align-items: center; gap: 8px;
  background: #fff; color: #111;
  border: 0; border-radius: 999px;
  padding: 10px 18px; font-size: 14px; font-weight: 600;
  cursor: pointer; transition: transform 0.15s ease, box-shadow 0.15s ease;
  box-shadow: 0 6px 18px rgba(0,0,0,0.28);
}
@media (hover: hover) {
  .btn-white:hover { transform: scale(1.03); }
}

.btn-white:disabled { opacity: 0.7; cursor: default; }
.kbps { white-space: nowrap; }
.btn-white .kbps {
  font-size: 11px; font-weight: 700; line-height: 1;
  background: var(--accent); color: #fff;
  padding: 3px 6px; border-radius: 6px;
}
.featured-note {
  margin: 14px 0 0; font-size: 12.5px; font-weight: 500;
  color: rgba(255,255,255,0.8);
}

/* ---------- section / shelf headers ---------- */
.section-head, .shelf-head {
  display: flex; align-items: baseline; gap: 10px;
  margin: 26px 0 14px;
}
.section-head h2, .shelf-head h2 {
  margin: 0; font-family: var(--font-display);
  font-size: 22px; font-weight: 400; letter-spacing: 0.2px;
}
.section-head .count {
  font-size: 14px; color: var(--muted-2); font-weight: 500;
}
/* round "+" button in a section header (create playlist / add liked tracks) */
.head-add {
  margin-left: auto; align-self: center; flex: 0 0 auto;
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 1px solid var(--border-strong); border-radius: 50%;
  background: none; color: var(--text); cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
@media (hover: hover) {
  .head-add:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
}

.head-add svg { width: 18px; height: 18px; }

/* ---------- shelf (horizontal scroll) ---------- */
.shelf { margin-bottom: 6px; }
.shelf-track {
  display: flex; gap: 18px;
  overflow-x: auto;
  /* Negative margin + matching padding so the playing card's green outline
     (extends ~4px) isn't clipped at the edges, while cards stay aligned with
     the shelf header. */
  margin: 0 -8px;
  padding: 6px 8px 16px;
  /* Keep snapping from scrolling the side padding out of view, which would
     re-clip the first/last playing card's outline. */
  scroll-padding-inline: 8px;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
}
.shelf-track::-webkit-scrollbar { height: 8px; }
.shelf-track::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 8px; }
.shelf-track .card { flex: 0 0 168px; scroll-snap-align: start; }

/* clickable genre shelf header → drills into that genre's Top 100 */
.shelf-head.shelf-more {
  background: none; border: 0; padding: 0; width: 100%; cursor: pointer;
  text-align: left; color: inherit; font: inherit;
  justify-content: flex-start;
}
.shelf-head.shelf-more h2 svg {
  width: 18px; height: 18px; vertical-align: -2px;
  color: var(--muted); opacity: 0; transform: translateX(-4px);
  transition: opacity 0.15s ease, transform 0.15s ease, color 0.15s ease;
}
@media (hover: hover) {
  .shelf-head.shelf-more:hover h2 { color: var(--accent); }
}
@media (hover: hover) {
  .shelf-head.shelf-more:hover h2 svg { opacity: 1; transform: none; color: var(--accent); }
}

/* on touch the chevron affordance is always visible (no hover) */
@media (hover: none) { .shelf-head.shelf-more h2 svg { opacity: 1; transform: none; } }

/* ---------- artist results row + cards ---------- */
.artist-row {
  display: flex; gap: 18px; overflow-x: auto;
  padding: 4px 2px 16px; scroll-snap-type: x proximity; scrollbar-width: thin;
}
.artist-row::-webkit-scrollbar { height: 8px; }
.artist-row::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 8px; }
.artist-card {
  flex: 0 0 132px; scroll-snap-align: start;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  background: none; border: 0; padding: 4px 0; cursor: pointer;
  color: inherit; font: inherit;
}
.artist-av-wrap {
  width: 124px; height: 124px; border-radius: 50%; overflow: hidden;
  box-shadow: var(--shadow-sm); transition: transform 0.2s ease, box-shadow 0.2s ease;
}
@media (hover: hover) {
  .artist-card:hover .artist-av-wrap { transform: translateY(-3px); box-shadow: var(--shadow-md); }
}

.artist-av { width: 100%; height: 100%; object-fit: cover; display: block; }
.artist-av.ph { background: var(--art-ph); border: 1px solid var(--border); }
.artist-card-name {
  margin-top: 6px; font-size: 14px; font-weight: 600; text-align: center;
  max-width: 124px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.artist-card-sub {
  font-size: 12px; color: var(--muted); text-align: center;
  max-width: 124px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ---------- artist profile hero ---------- */
.artist-hero {
  display: flex; align-items: center; gap: 22px;
  margin: 6px 0 22px;
}
.artist-hero-img {
  width: 132px; height: 132px; border-radius: 50%; object-fit: cover;
  box-shadow: var(--shadow-md); flex: 0 0 auto;
}
.artist-hero-img.ph { background: var(--art-ph); border: 1px solid var(--border); }
.artist-hero-eyebrow {
  font-size: 12px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;
  color: var(--accent);
}
.artist-hero-name {
  margin: 6px 0 4px; font-family: var(--font-display); font-weight: 400;
  font-size: clamp(28px, 6vw, 44px); line-height: 1.05;
}
.artist-hero-sub { margin: 0; color: var(--muted); font-size: 15px; }

@media (max-width: 600px) {
  .artist-hero { gap: 16px; }
  .artist-hero-img { width: 96px; height: 96px; }
}

/* ---------- grid view ---------- */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 20px 18px;
}

/* ---------- card ---------- */
.card { min-width: 0; cursor: default; }
.card-art {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-soft);
  box-shadow: var(--shadow-sm);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
@media (hover: hover) {
  .card:hover .card-art { transform: translateY(-3px); box-shadow: var(--shadow-md); }
}

.card-art-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.card-art-img.ph { background: var(--art-ph); border: 1px solid var(--border); }

.card-rank {
  position: absolute; top: 8px; left: 8px;
  min-width: 22px; height: 22px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; color: #fff;
  background: rgba(0,0,0,0.55); border-radius: 7px;
  backdrop-filter: blur(4px);
}
.card-hype {
  position: absolute; top: 8px; left: 8px;
  font-size: 9.5px; font-weight: 800; letter-spacing: 0.5px; color: #04130a;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  padding: 3px 6px; border-radius: 6px;
}

/* like / add buttons on cards (top-right; reveal on hover, always on touch) */
.card-acts {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  display: flex; gap: 6px;
  opacity: 0; transform: translateY(-4px);
  transition: opacity 0.18s ease, transform 0.18s ease;
}
@media (hover: hover) {
  .card-art:hover .card-acts,
  .card.is-playing .card-acts { opacity: 1; transform: none; }
}

.card-act {
  width: 32px; height: 32px; display: grid; place-items: center;
  border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(0, 0, 0, 0.55); color: #fff;
  backdrop-filter: blur(4px); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
  transition: color 0.15s ease, background 0.15s ease, transform 0.12s ease;
}
.card-act svg { width: 17px; height: 17px; }
@media (hover: hover) {
  .card-act:hover { background: rgba(0, 0, 0, 0.72); }
}

.card-act.like-btn.on { color: var(--accent); }
.card-act:active { transform: scale(0.9); }
@media (hover: none) { .card-acts { opacity: 1; transform: none; } }

.card .play {
  position: absolute; left: 10px; bottom: 10px;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: rgba(255,255,255,0.92); color: #000;
  font-size: 15px; cursor: pointer;
  box-shadow: 0 4px 12px rgba(0,0,0,0.3);
  opacity: 0; transform: translateY(6px);
  transition: opacity 0.18s ease, transform 0.18s ease, background 0.18s ease;
}
.card .play .glyph { color: var(--accent); }
@media (hover: hover) {
  .card-art:hover .play,
  .card.is-playing .play,
  .card.is-loading .play { opacity: 1; transform: translateY(0); }
}
@media (hover: hover) {
  .card .play:hover { background: #fff; }
}


/* White download pill — always visible, clearly readable, labels 320 kbps. */
.card .dl {
  position: absolute; right: 10px; bottom: 10px;
  display: inline-flex; align-items: center; gap: 4px;
  height: 32px; padding: 0 10px;
  border: 0; border-radius: 999px;
  background: rgba(255,255,255,0.96); color: #0a0a0a;
  font-size: 12px; font-weight: 700; cursor: pointer;
  backdrop-filter: blur(4px);
  box-shadow: 0 4px 12px rgba(0,0,0,0.4);
  transition: transform 0.15s ease, background 0.15s ease;
}
.card .dl svg { width: 15px; height: 15px; }
@media (hover: hover) {
  .card .dl:hover { background: #fff; transform: translateY(-1px); }
}

.card .dl:disabled { opacity: 0.6; cursor: default; }

.card.is-playing .card-art { outline: 2px solid var(--accent); outline-offset: 2px; }

.card-title {
  margin-top: 9px; font-size: 14px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.card-artist {
  font-size: 13px; color: var(--muted); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* skeleton cards shown in a genre shelf until its Top 20 loads */
.card.skel { pointer-events: none; }
.card.skel .ph-line {
  height: 11px; border-radius: 5px; margin-top: 8px;
  background: var(--border); animation: skelPulse 1.4s ease-in-out infinite;
}
.card.skel .ph-line.short { width: 60%; }
.card.skel .card-art-img.ph { animation: skelPulse 1.4s ease-in-out infinite; }
@keyframes skelPulse { 0%,100% { opacity: 1; } 50% { opacity: 0.5; } }

/* ---------- Top 100 list view ---------- */
.list-head {
  position: sticky;
  top: var(--topbar-h, 60px);
  z-index: 20;
  display: flex; align-items: center; gap: 14px;
  margin: 0 0 18px;
  padding: 12px 0;
  background: var(--bg);
}
.list-head h2 {
  margin: 0; font-family: var(--font-display);
  font-size: 28px; font-weight: 400; letter-spacing: 0.3px;
}
.list-head .count { color: var(--muted-2); font-size: 14px; }
.back-btn {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--bg-soft); border: 1px solid var(--border); color: var(--text);
  border-radius: 11px; height: 38px; padding: 0 14px 0 10px;
  font-size: 14px; font-weight: 600; cursor: pointer;
  transition: color 0.18s ease, border-color 0.18s ease;
}
.back-btn svg { width: 20px; height: 20px; }
@media (hover: hover) {
  .back-btn:hover { color: var(--accent); border-color: var(--accent); }
}


.tracklist { display: flex; flex-direction: column; }
.track-row {
  display: flex; align-items: center; gap: 14px;
  padding: 8px 10px; border-radius: 12px;
  transition: background 0.15s ease;
}
.track-row + .track-row { border-top: 1px solid var(--border); border-radius: 0; }
@media (hover: hover) {
  .track-row:hover { background: var(--bg-soft); border-color: transparent; }
}

.track-row.is-playing { background: color-mix(in srgb, var(--accent) 12%, transparent); }

.tl-rank {
  width: 30px; flex: 0 0 auto; text-align: center;
  font-variant-numeric: tabular-nums; font-weight: 700;
  font-size: 15px; color: var(--muted-2);
}
.track-row.is-playing .tl-rank { color: var(--accent); }
/* Drag handle (playlist reorder) sits where the rank would be. */
.tl-rank.drag-handle {
  cursor: grab; touch-action: none; color: var(--muted-2);
  display: grid; place-items: center;
}
@media (hover: hover) {
  .tl-rank.drag-handle:hover { color: var(--fg); }
}

.tl-rank.drag-handle:active { cursor: grabbing; }
.tl-rank.drag-handle svg { width: 18px; height: 18px; }
/* The picked-up row: outlined, opaque, lifted (shadow + slight scale), and
   floating under the pointer (position/top set inline by JS). */
.track-row.dragging {
  background: var(--bg-elev);
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: 12px;
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.5);
  transform: scale(1.02);
  z-index: 1000;
  pointer-events: none;
}
/* The gap left behind, showing where the row will drop. */
.drag-placeholder {
  border-radius: 12px;
  box-sizing: border-box;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 2px dashed color-mix(in srgb, var(--accent) 45%, transparent);
}

.tl-art {
  position: relative; width: 52px; height: 52px; flex: 0 0 auto;
  border-radius: 9px; overflow: hidden; background: var(--bg-soft);
  box-shadow: var(--shadow-sm);
}
.tl-art-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tl-art-img.ph { background: var(--art-ph); border: 1px solid var(--border); }
.tl-art .play {
  position: absolute; inset: 0; width: 100%; height: 100%;
  display: grid; place-items: center; border: 0; cursor: pointer;
  background: rgba(0,0,0,0.45); color: #fff; font-size: 18px;
  opacity: 0; transition: opacity 0.15s ease;
}
.tl-art .play .glyph { color: #fff; }
@media (hover: hover) {
  .tl-art:hover .play,
  .track-row.is-playing .tl-art .play,
  .track-row.is-loading .tl-art .play { opacity: 1; }
}


.tl-main { min-width: 0; flex: 1 1 auto; }
.tl-title {
  font-size: 15px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tl-title span { font-weight: 400; color: var(--muted); }
.tl-artist {
  font-size: 13px; color: var(--muted); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tl-meta {
  flex: 0 0 auto; max-width: 220px; color: var(--muted-2);
  font-size: 12.5px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
/* Harmonic mixing: Camelot key sits in the meta line in the SAME style as the
   rest of the meta (no highlight); only the compatibility marker stands out. */
.harm { font-size: 11px; font-weight: 700; white-space: nowrap; }
.harm.ok { color: var(--accent); }
.harm.clash { color: #ff6b6b; }

.track-row .dl {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 5px;
  height: 36px; padding: 0 14px;
  border: 0; border-radius: 999px;
  background: #fff; color: #0a0a0a;
  font-size: 13px; font-weight: 700; cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.track-row .dl svg { width: 16px; height: 16px; }
.track-row .dl .kbps { color: var(--accent); }
@media (hover: hover) {
  .track-row .dl:hover { transform: translateY(-1px); box-shadow: var(--shadow-md); }
}

.track-row .dl:disabled { opacity: 0.6; cursor: default; }

/* Pinned "Микс" row at the top of a playlist (loading spinner → playable). */
.mix-row { background: color-mix(in srgb, var(--accent) 9%, transparent); }
/* Smaller logo cover (padded, contained) instead of a full-bleed image. */
.mix-row .tl-art-img { object-fit: contain; padding: 13px; box-sizing: border-box; }
.mix-row .tl-rank { color: var(--accent); display: grid; place-items: center; }
.mix-row .tl-rank svg { width: 18px; height: 18px; }
/* Always show the control, but keep our logo cover visible behind it: a small
   dark disc holds the play glyph instead of a full-cover dark veil. */
.mix-row .tl-art .play { opacity: 1; background: transparent; }
.mix-row .tl-art .play .glyph {
  width: 26px; height: 26px; border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
}
.mix-row .mix-loading-cell {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(0, 0, 0, 0.4);
}
.mix-row .mix-loading-cell .spinner {
  width: 22px; height: 22px; border-width: 3px;
  border-color: color-mix(in srgb, var(--accent) 30%, transparent);
  border-top-color: var(--accent);
}
/* Generation progress bar along the bottom edge of the mix row. */
.mix-row { position: relative; }
.mix-row .mix-progress {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 3px; border-radius: 0 0 12px 12px;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  overflow: hidden;
}
.mix-row .mix-progress-bar {
  display: block; height: 100%; width: 5%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  box-shadow: 0 0 10px color-mix(in srgb, var(--accent) 70%, transparent);
  transition: width 0.5s ease;
}

/* ---------- genres page (plain list, body font) ---------- */
.genre-list { display: flex; flex-direction: column; }
.genre-tile {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; padding: 16px 6px;
  background: none; border: 0; border-bottom: 1px solid var(--border);
  cursor: pointer; text-align: left; color: var(--text);
  font-family: inherit; font-size: 16px; font-weight: 500;
  transition: color 0.15s ease;
}
@media (hover: hover) {
  .genre-tile:hover { color: var(--accent); }
}

.genre-tile svg { width: 20px; height: 20px; flex: 0 0 auto; color: var(--muted-2); }
@media (hover: hover) {
  .genre-tile:hover svg { color: var(--accent); }
}

.genre-row-name {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- collection cards (releases / DJ charts) ---------- */
.coll-card { cursor: pointer; }
.coll-card .coll-card-go {
  position: absolute; right: 10px; bottom: 10px;
  width: 32px; height: 32px; display: grid; place-items: center;
  border-radius: 50%; background: rgba(255, 255, 255, 0.94); color: #000;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  opacity: 0; transform: translateY(6px);
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.coll-card .coll-card-go svg { width: 18px; height: 18px; color: var(--accent); }
@media (hover: hover) {
  .coll-card:hover .card-art { transform: translateY(-3px); box-shadow: var(--shadow-md); }
}
@media (hover: hover) {
  .coll-card:hover .coll-card-go { opacity: 1; transform: none; }
}

@media (hover: none) { .coll-card .coll-card-go { opacity: 1; transform: none; } }

/* drilled-in release/chart hero (square cover, like the artist hero) */
.coll-hero { display: flex; align-items: center; gap: 22px; margin: 6px 0 22px; }
.coll-hero-img {
  width: 132px; height: 132px; border-radius: 14px; object-fit: cover;
  box-shadow: var(--shadow-md); flex: 0 0 auto;
}
.coll-hero-img.ph { background: var(--art-ph); border: 1px solid var(--border); }
.coll-hero-info { min-width: 0; }
.coll-hero-eyebrow {
  font-size: 12px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;
  color: var(--accent);
}
.coll-hero-name {
  margin: 6px 0 4px; font-family: var(--font-display); font-weight: 400;
  font-size: clamp(24px, 5vw, 40px); line-height: 1.08;
}
.coll-hero-sub { margin: 0; color: var(--muted); font-size: 15px; }
@media (max-width: 600px) {
  .coll-hero { gap: 16px; }
  .coll-hero-img { width: 96px; height: 96px; }
}

/* ---------- accounts / playlists / likes ---------- */
.hidden { display: none !important; }

.account-btn {
  display: inline-grid; place-items: center;
  width: 38px; height: 38px; flex: 0 0 auto;
  border-radius: 50%; cursor: pointer;
  background: var(--bg-soft); border: 1px solid var(--border); color: var(--text);
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
@media (hover: hover) {
  .account-btn:hover { color: var(--accent); border-color: var(--accent); }
}

.account-btn.signed-in { color: var(--accent); border-color: var(--accent); }

/* account dropdown anchored under the profile button */
.account-wrap { position: relative; flex: 0 0 auto; }
.acct-dropdown {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 1000;
  width: 240px;
  background: var(--bg-elev); border: 1px solid var(--border-strong);
  border-radius: 14px; padding: 14px;
  box-shadow: var(--shadow-md);
  transform-origin: top right;
  animation: acctDropIn 0.16s cubic-bezier(0.2, 0.9, 0.2, 1);
}
@keyframes acctDropIn { from { opacity: 0; transform: translateY(-6px) scale(0.97); } to { opacity: 1; transform: none; } }
.acct-dropdown .acct-hello { margin: 2px 2px 12px; }
.acct-dropdown .btn-ghost-row:first-of-type { margin-top: 0; }

/* row action buttons (like / add / remove) on track rows */
.row-act {
  flex: 0 0 auto; width: 38px; height: 38px;
  display: grid; place-items: center; cursor: pointer;
  background: none; border: 0; color: var(--muted-2);
  border-radius: 10px;
  transition: color 0.15s ease, background 0.15s ease, transform 0.12s ease;
}
.row-act svg { width: 20px; height: 20px; display: block; }
@media (hover: hover) {
  .row-act:hover { color: var(--text); background: var(--bg-soft); }
}

.row-act:active { transform: scale(0.9); }
.like-btn.on { color: var(--accent); }
@media (hover: hover) {
  .like-btn.on:hover { color: var(--accent); }
}


/* modals */
.modal {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.modal-scrim {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
.modal-card {
  position: relative; z-index: 1;
  width: 380px; max-width: 100%;
  background: var(--bg-elev); border: 1px solid var(--border-strong);
  border-radius: 18px; padding: 26px 24px 22px;
  box-shadow: var(--shadow-md);
  animation: modalIn 0.22s cubic-bezier(0.2, 0.9, 0.2, 1);
}
.modal-card-sm { width: 300px; }
@keyframes modalIn { from { opacity: 0; transform: translateY(12px) scale(0.98); } to { opacity: 1; transform: none; } }
.modal-x {
  position: absolute; top: 12px; right: 12px;
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 0; border-radius: 9px; cursor: pointer;
  background: var(--bg-soft); color: var(--muted);
  transition: color 0.15s ease, background 0.15s ease;
}
@media (hover: hover) {
  .modal-x:hover { color: var(--text); }
}

.modal-title { margin: 0 0 18px; font-size: 22px; font-weight: 700; }

.field-label { display: block; font-size: 13px; color: var(--muted); margin: 0 0 6px; }
.field {
  width: 100%; height: 46px; padding: 0 14px; margin: 0 0 14px;
  background: var(--bg-soft); border: 1px solid var(--border);
  border-radius: 11px; color: var(--text); font-size: 16px; font-family: inherit;
  outline: none; transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.field:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(0, 217, 95, 0.15); }

/* A <select> using .field must not rely on the browser's own arrow: it sits hard
   against the border and its offset differs per engine. Draw our own chevron at a
   fixed 16px inset and reserve room for it on the right. */
select.field {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  padding-right: 42px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%23a1a1a6' d='M1.4 0 6 4.6 10.6 0 12 1.4 6 7.4 0 1.4z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 12px 8px;
}
select.field::-ms-expand { display: none; }
/* --- consent checkbox + legal footer --- */
.consent {
  display: flex; gap: 10px; align-items: flex-start;
  /* Clear space above: the gender segment ends flush, and a consent line glued
     to it reads as part of that control instead of a separate decision. */
  margin: 34px 0 22px; cursor: pointer;
}
.consent input {
  /* 20px box inside a 44px-tall hit area: the whole label is clickable. */
  width: 20px; height: 20px; margin: 2px 0 0; flex: 0 0 auto;
  accent-color: var(--accent); cursor: pointer;
}
.consent span { font-size: 13.5px; line-height: 1.45; color: var(--muted); }
.consent a { color: var(--accent); }
.site-foot {
  display: flex; gap: 10px; justify-content: center; align-items: center;
  flex-wrap: wrap; padding: 28px 16px calc(28px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--border); margin-top: 40px;
}
.site-foot a { color: var(--muted-2); font-size: 13px; text-decoration: none; }
.site-foot a:hover { color: var(--text); }
.site-foot span { color: var(--muted-2); font-size: 13px; }

/* --- email confirmation step --- */
.code-lead {
  margin: -4px 0 18px; font-size: 14.5px; line-height: 1.45; color: var(--muted);
  overflow-wrap: anywhere;                 /* long addresses must not overflow */
}
.code-lead strong { color: var(--text); font-weight: 600; }
/* The code itself is the content: big, monospaced-by-tracking, centred. */
.code-field {
  height: 62px; margin-bottom: 16px; text-align: center;
  font-size: 30px; font-weight: 700; letter-spacing: 10px; text-indent: 10px;
  font-variant-numeric: tabular-nums;
}
.code-wait { font-size: 13px; color: var(--muted-2); }
.link-btn[disabled] { opacity: 0.45; cursor: default; }

.field-error { color: #ff7b7b; font-size: 13.5px; min-height: 18px; margin: -6px 0 10px; }
.btn-primary {
  width: 100%; height: 46px; border: 0; border-radius: 11px; cursor: pointer;
  background: var(--accent); color: #04130a; font-size: 15px; font-weight: 700;
  font-family: inherit; transition: filter 0.15s ease, transform 0.12s ease;
}
@media (hover: hover) {
  .btn-primary:hover { filter: brightness(1.06); }
}

.btn-primary:active { transform: scale(0.99); }
.btn-primary:disabled { opacity: 0.6; cursor: default; }
/* Not yet actionable: the green fill is this site's "you may proceed" signal,
   so it stays off until consent is ticked. The button is genuinely disabled, so
   :disabled's opacity is cancelled here — dimming an already-grey button just
   makes the label hard to read. */
.btn-primary.is-off,
.btn-primary.is-off:disabled {
  background: var(--bg-soft); color: var(--muted);
  border: 1px solid var(--border); opacity: 1; cursor: not-allowed;
}
@media (hover: hover) { .btn-primary.is-off:hover { filter: none; } }
.btn-primary.danger { background: #e5484d; color: #fff; }

.confirm-card { width: 340px; }
.confirm-card .modal-title { margin-bottom: 8px; }
.confirm-actions { display: flex; gap: 10px; margin-top: 20px; }
.confirm-actions .btn-ghost-row,
.confirm-actions .btn-primary { margin-top: 0; flex: 1; }
.modal-switch { margin: 16px 0 0; font-size: 14px; color: var(--muted); text-align: center; }
.link-btn { background: none; border: 0; color: var(--accent); cursor: pointer; font: inherit; padding: 0 4px; }
@media (hover: hover) {
  .link-btn:hover { text-decoration: underline; }
}


.acct-hello { margin: 0 0 16px; font-size: 14px; color: var(--muted); }
.acct-hello b { color: var(--text); }
.btn-ghost-row {
  width: 100%; height: 44px; margin-top: 8px; border-radius: 11px; cursor: pointer;
  background: var(--bg-soft); border: 1px solid var(--border); color: var(--text);
  font-size: 15px; font-family: inherit; font-weight: 600;
  transition: border-color 0.15s ease, color 0.15s ease;
}
@media (hover: hover) {
  .btn-ghost-row:hover { border-color: var(--accent); color: var(--accent); }
}

.btn-ghost-row.danger { color: #ff9b9b; }
@media (hover: hover) {
  .btn-ghost-row.danger:hover { border-color: #ff7b7b; color: #ff7b7b; }
}


/* Account-page actions (change password / log out), pinned at the bottom. */
.account-actions {
  margin: 48px auto 0; padding-top: 24px; border-top: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 8px; max-width: 320px;
  text-align: center;
}

.addpl-list { margin: 0 0 16px; max-height: 52vh; overflow-y: auto; }
.addpl-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(108px, 1fr)); gap: 14px;
  padding: 2px;
}
.addpl-item .pl-cover { margin-bottom: 6px; }
.addpl-item .pl-name { font-size: 13px; }
.muted-note { color: var(--muted); font-size: 14px; margin: 4px 0 16px; }

/* playlist grid + cards on the "Моё" page */
.pl-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 16px;
}
.pl-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  background: none; border: 0; padding: 0; cursor: pointer; color: inherit;
  text-align: left; font-family: inherit;
  /* Let the card shrink to its grid column instead of being widened by a long,
     nowrap playlist name — otherwise the cell overflows on narrow screens and
     the cover (width:100%) stretches past 1:1 and "zooms in". */
  min-width: 0;
}
.pl-cover {
  position: relative;
  width: 100%; aspect-ratio: 1/1; border-radius: var(--radius); overflow: hidden;
  background: var(--bg-soft); box-shadow: var(--shadow-sm); margin-bottom: 8px;
  display: grid; place-items: center;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.pl-del {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  background: rgba(0,0,0,0.55); color: #fff;
  opacity: 0; transform: scale(0.85);
  transition: opacity 0.15s ease, transform 0.15s ease, background 0.15s ease;
}
.pl-del svg { width: 16px; height: 16px; }
@media (hover: hover) {
  .pl-del:hover { background: var(--danger, #e5484d); }
}
@media (hover: hover) {
  .pl-card:hover .pl-del, .pl-del:focus-visible { opacity: 1; transform: scale(1); }
}

@media (hover: none) { .pl-del { opacity: 1; transform: scale(1); } }
@media (hover: hover) {
  .pl-card:hover .pl-cover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
}

.pl-cover-img { width: 100%; height: 100%; object-fit: cover; }
.pl-cover-img.ph, .pl-cover-ph { color: var(--muted-2); }
.pl-cover-ph svg { width: 38px; height: 38px; }
/* Mosaic cover: 1 / 2-split / 2×2 grid of track artworks. */
.pl-mosaic { width: 100%; height: 100%; display: grid; gap: 1px; }
.pl-mosaic img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pl-mosaic-1 { grid-template-columns: 1fr; }
.pl-mosaic-2 { grid-template-columns: 1fr 1fr; }
/* 3 covers: first image spans the whole left column (2 cells, 50%), the other
   two stack in the right column (25% each). */
.pl-mosaic-3 { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
.pl-mosaic-3 img:first-child { grid-row: 1 / span 2; }
.pl-mosaic-4 { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
.pl-name { font-size: 14px; font-weight: 600; width: 100%; min-width: 0; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-count { font-size: 12.5px; color: var(--muted); }
.pl-new .pl-cover { border: 1px dashed var(--border-strong); color: var(--muted-2); flex-direction: column; gap: 4px; }
.pl-new .pl-cover svg { width: 30px; height: 30px; }
.pl-new span:last-child { color: var(--muted); font-size: 13px; }

/* small square icon button (e.g. delete playlist) */
.icon-btn {
  flex: 0 0 auto; width: 40px; height: 40px; display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: 11px; cursor: pointer;
  background: var(--bg-soft); color: var(--muted);
  transition: color 0.15s ease, border-color 0.15s ease;
}
.icon-btn svg { width: 20px; height: 20px; }
@media (hover: hover) {
  .icon-btn.danger:hover { color: #ff7b7b; border-color: #ff7b7b; }
}


/* DJ mix button + modal */
.mix-btn {
  margin-left: auto; flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 7px;
  height: 40px; padding: 0 16px; border: 0; border-radius: 999px; cursor: pointer;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #04130a; font-size: 14px; font-weight: 700; font-family: inherit;
  box-shadow: var(--shadow-sm); transition: transform 0.15s ease, filter 0.15s ease;
}
.mix-btn svg { width: 18px; height: 18px; }
/* Feedback on TOUCH. :hover is gated behind (hover: hover) above, because on a
   phone it sticks — the button stayed lit after a tap. :active is the correct
   touch equivalent: it lasts exactly as long as the finger is down. */
.mix-btn:active { transform: scale(0.97); filter: brightness(0.95); }
.key-sort-btn:active,
.mix-btn-2nd:active { border-color: var(--accent); color: var(--accent); }
@media (hover: hover) {
  .mix-btn:hover { transform: translateY(-1px); filter: brightness(1.05); }
}

/* Secondary (outline) variant of .mix-btn, so the gradient "Свести микс" stays the
   single primary action wherever several of these sit together. Used by the
   harmonic-sort button and by "Сохранить к себе" on a producer playlist — two
   green buttons side by side left it unclear which one was the main thing to do. */
.key-sort-btn,
.mix-btn-2nd {
  background: var(--bg-soft); color: var(--text);
  border: 1px solid var(--border); box-shadow: none; font-weight: 600;
}
@media (hover: hover) {
  .key-sort-btn:hover,
  .mix-btn-2nd:hover { filter: none; border-color: var(--accent); color: var(--accent); }
}

/* Icon-only variants of .mix-btn: a square target instead of a text pill. 44px so
   they clear the touch-target floor, and the SVG is sized up because a 18px glyph
   inside a 44px circle looks lost. Their names live in aria-label/title. */
/* Square icon variant of .mix-btn. Sized to the height of the text button it sits
   next to (40px here, 46px in the mobile block below), so the row lines up. */
.mix-btn-icon {
  width: 40px; height: 40px; padding: 0; border-radius: 50%;
  justify-content: center; gap: 0; flex: 0 0 auto;
}
.mix-btn-icon svg { width: 22px; height: 22px; }

/* "Свести микс" button + "Доступно N треков для сведения" caption, stacked. */
.mix-head {
  margin-left: auto; flex: 0 0 auto;
  display: flex; flex-direction: column; align-items: flex-end; gap: 5px;
}
.mix-head .mix-btn { margin-left: 0; }
.mix-avail { font-size: 12.5px; font-weight: 600; color: var(--accent); }
/* In a chart's hero, the mix control sits under the title (left-aligned). */
.coll-hero-mix { margin-top: 12px; }
/* In a chart hero the head becomes a wrapping ROW: button, then the icon tools
   right beside it, and the caption pushed onto its own line by flex-basis:100%.
   As a column it was the caption — wider than the button — that set the width, and
   the icons ended up stranded far to the right. */
.coll-hero-mix .mix-head {
  flex-direction: row; flex-wrap: wrap; align-items: center;
  justify-content: flex-start; gap: 10px;
}
.coll-hero-mix .mix-avail { flex: 1 0 100%; }
.coll-tools { display: flex; gap: 10px; flex: 0 0 auto; }
.coll-tools .mix-btn { margin-left: 0; flex: 0 0 auto; }
.coll-hero-mix .mix-head { margin-left: 0; align-items: flex-start; }

/* The first N (mixable) tracks are outlined as one group: side borders on every
   row, the top row rounds the top, the bottom row rounds the bottom. */
.track-row.mix-in {
  border-left: 1.5px solid color-mix(in srgb, var(--accent) 55%, transparent);
  border-right: 1.5px solid color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: 0;
  background: color-mix(in srgb, var(--accent) 4%, transparent);
}
.track-row.mix-in-first {
  border-top: 1.5px solid color-mix(in srgb, var(--accent) 55%, transparent);
  border-top-left-radius: 12px; border-top-right-radius: 12px;
}
.track-row.mix-in-last {
  border-bottom: 1.5px solid color-mix(in srgb, var(--accent) 55%, transparent);
  border-bottom-left-radius: 12px; border-bottom-right-radius: 12px;
}
/* Keep the loaded/playing highlight readable on outlined rows. */
.track-row.mix-in.is-playing { background: color-mix(in srgb, var(--accent) 12%, transparent); }

/* Language toggle in the top bar. */
/* Segmented RU|EN language toggle. */
.lang-switch {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 2px;
  height: 34px; padding: 3px;
  border: 1px solid var(--border); border-radius: 999px; background: var(--bg-soft);
  transition: border-color 0.15s ease;
}
@media (hover: hover) {
  .lang-switch:hover { border-color: var(--border-strong); }
}

.lang-opt {
  border: 0; background: transparent; color: var(--muted); cursor: pointer;
  font-family: inherit; font-size: 12px; font-weight: 700; letter-spacing: 0.5px;
  height: 26px; padding: 0 11px; border-radius: 999px; line-height: 1;
  transition: color 0.15s ease, background 0.2s ease, box-shadow 0.2s ease;
}
@media (hover: hover) {
  .lang-opt:hover { color: var(--text); }
}

.lang-opt.active {
  color: #04240f; cursor: default;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  box-shadow: 0 2px 10px rgba(0, 217, 95, 0.35);
}
.mix-mode {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px; margin-bottom: 10px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 12px;
  transition: border-color 0.15s ease, background 0.15s ease;
}
@media (hover: hover) {
  .mix-mode:hover { border-color: var(--border-strong); }
}

.mix-mode input { margin-top: 3px; accent-color: var(--accent); width: 18px; height: 18px; flex: 0 0 auto; }
.mix-mode span { font-size: 14px; color: var(--muted); line-height: 1.4; }
.mix-mode span b { color: var(--text); font-weight: 600; }
.mix-mode:has(input:checked) { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
/* toast */
.toast {
  position: fixed; left: 50%; top: 24px; transform: translate(-50%, -16px);
  z-index: 1100; background: var(--bg-elev); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: 12px;
  padding: 11px 18px; font-size: 14px; box-shadow: var(--shadow-md);
  opacity: 0; pointer-events: none; transition: opacity 0.2s ease, transform 0.2s ease;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }

@media (max-width: 600px) {
  .track-row { gap: 8px; }
  .row-act { width: 34px; height: 34px; }
  /* All popups stay centered on mobile too (no bottom-sheet). */
  .modal { padding: 16px; }
  .toast { top: 16px; }
}

/* ---------- footer ---------- */
.footer {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 25;
  display: flex; justify-content: space-between; gap: 12px;
  padding: 8px 22px; font-size: 12px; color: var(--muted-2);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--border);
}

/* ---------- SEO intro (видимый текст для поисковиков) ---------- */
.seo-intro {
  max-width: 760px;
  margin: 56px auto 96px;   /* нижний отступ, чтобы не уезжало под плеер/футер */
  padding: 36px 22px 0;
  border-top: 1px solid var(--border);   /* разделительная линия перед текстом */
  color: var(--muted);
  font-size: 14px;
  line-height: 1.6;
}
.seo-intro h1 {
  font-size: 18px;
  font-weight: 600;
  color: var(--muted-2);
  margin: 0 0 14px;
}
.seo-intro p { margin: 0 0 12px; }
.seo-intro strong { color: var(--muted); font-weight: 600; }

/* ---------- hover only where a real pointer exists ----------
   On a touch screen :hover STICKS: the browser keeps the hover state on the last
   element you tapped until you tap somewhere else. That is why "sort by key" lit
   up and stayed lit. Guarding every hover rule with (hover: hover) means the
   highlight simply never appears on a phone, instead of appearing and lingering.
   Rules inside @media blocks are left alone — none of them are hover rules. */

/* ---------- player ---------- */
/* Full-width dock flush with the bottom edge of the window — no gap. It sits
   ABOVE the fixed .footer (z-index 35 vs 25), which only holds the "Y2TRACKS"
   caption, so covering that while something is playing is fine and is what every
   player does. The footer is visible again as soon as the player closes. */
.player {
  position: fixed; bottom: 0; left: 0; right: 0;
  background: var(--bg-elev);
  border-top: 1px solid var(--border-strong);
  z-index: 35;
  box-shadow: var(--shadow-md);
  overflow: hidden;
  animation: playerIn 0.3s cubic-bezier(0.2, 0.9, 0.2, 1);
}
@keyframes playerIn {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}
.player.hidden { display: none; }
/* 22px matches main's side padding, so the player lines up with the content.
   The safe-area inset matters now that the player is flush with bottom:0 and the
   page uses viewport-fit=cover: without it the controls sit under the iPhone home
   indicator. It resolves to 0 everywhere else. */
.player-main {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 22px;
  padding-bottom: calc(11px + env(safe-area-inset-bottom, 0px));
}

/* Like / add-to-playlist inside the player. Same visual weight as .row-act. */
.player-act {
  flex: 0 0 auto; width: 36px; height: 36px;
  display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: 10px;
  background: transparent; color: var(--muted-2);
  cursor: pointer; transition: color .15s, border-color .15s, transform .15s;
}
@media (hover: hover) {
  .player-act:hover { color: var(--fg); border-color: var(--border-strong); }
}

.player-act:active { transform: scale(0.94); }
.player-act.on { color: var(--accent); border-color: var(--accent); }
.player-act svg { width: 17px; height: 17px; display: block; }
.player-act[hidden] { display: none; }

/* round play/pause control inside the player */
.player-toggle {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: 50%;
  border: none; cursor: pointer; color: #fff;
  display: grid; place-items: center;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s ease, filter 0.15s ease;
}
@media (hover: hover) {
  .player-toggle:hover { transform: scale(1.06); filter: brightness(1.06); }
}

.player-toggle:active { transform: scale(0.95); }
.player-toggle svg { width: 20px; height: 20px; display: block; }
.player-toggle .glyph { display: grid; place-items: center; }

/* the native audio element is fully replaced by the custom controls */
.player audio { display: none; }

/* interactive seek bar */
.player-seek { flex: 1 1 auto; display: flex; align-items: center; gap: 10px; min-width: 0; }
.player-time {
  flex: 0 0 auto; min-width: 36px; text-align: center;
  font-size: 11px; font-weight: 500; color: var(--muted);
  font-variant-numeric: tabular-nums; user-select: none;
}
.player-track {
  position: relative; flex: 1 1 auto; height: 34px;
  display: flex; align-items: center; cursor: pointer; touch-action: none;
}
.player-track:focus-visible { outline: none; }

/* waveform: a row of bars that doubles as the scrubber */
.player-wave {
  position: absolute; inset: 0; display: flex; align-items: center;
  /* 1px gap: the bar count is derived from the width at ~3px per bar, so a 2px
     gap would eat most of each bar and the waveform would read as stripes. */
  gap: 1px; width: 100%; height: 100%;
}
.player-wave i {
  flex: 1 1 0; min-width: 0; height: 30%;
  background: var(--border-strong); border-radius: 1px;
  transition: height 0.08s linear, background-color 0.15s ease;
}
.player-wave i.on { background: linear-gradient(var(--accent), var(--accent-2)); }

/* thin playhead line over the waveform (shown on hover/drag/focus) */
.player-thumb {
  position: absolute; left: 0%; top: 4px; bottom: 4px; width: 2px;
  margin-left: -1px; transform: scaleY(0); transform-origin: center;
  border-radius: 2px; background: var(--text);
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.35);
  transition: transform 0.12s ease; pointer-events: none;
}
@media (hover: hover) {
  .player-track:hover .player-thumb,
  .player-track:focus-visible .player-thumb,
  .player-track.dragging .player-thumb { transform: scaleY(1); }
}

.player-art-wrap { position: relative; width: 48px; height: 48px; flex: 0 0 auto; }
.player img { width: 48px; height: 48px; border-radius: 9px; object-fit: cover; box-shadow: var(--shadow-sm); }
.player-eq {
  position: absolute; bottom: 4px; right: 4px;
  display: none; align-items: flex-end; gap: 2px; height: 13px;
  padding: 2px; border-radius: 4px; background: rgba(0,0,0,0.55);
}
.player.is-playing .player-eq { display: flex; }
.player-eq i {
  width: 2.5px; background: #fff; border-radius: 2px;
  animation: eq 0.9s ease-in-out infinite;
}
.player-eq i:nth-child(1) { height: 40%; animation-delay: 0s; }
.player-eq i:nth-child(2) { height: 100%; animation-delay: 0.2s; }
.player-eq i:nth-child(3) { height: 60%; animation-delay: 0.4s; }
.player-eq i:nth-child(4) { height: 85%; animation-delay: 0.1s; }
@keyframes eq { 0%,100% { transform: scaleY(0.4); } 50% { transform: scaleY(1); } }

/* Grows with the window now that the player spans it: 190px keeps the layout
   intact on a laptop, and a wide screen gives the title room to breathe instead
   of handing every spare pixel to the seek bar. Mobile overrides this below. */
.player-info { min-width: 0; flex: 0 1 clamp(190px, 20vw, 320px); }
.player-title { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.player-artist { font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---------- clickable artist names ---------- */
/* A <button> so it is keyboard-focusable and announced as an action, but it has
   to look like the plain text it replaced — hence the full chrome reset. It
   inherits font and colour from whichever container it sits in (.tl-artist,
   .card-artist, .featured-artist, .player-artist), so one rule covers them all. */
.artist-link {
  appearance: none; background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: inherit; letter-spacing: inherit;
  cursor: pointer; text-align: left;
  /* display:inline (not the button default inline-block) so the containers'
     `text-overflow: ellipsis` still truncates a long artist list as text —
     an inline-block child would get cut off with no ellipsis instead. */
  display: inline; vertical-align: baseline;
  text-decoration-color: transparent;
  text-underline-offset: 2px;
  transition: color .15s, text-decoration-color .15s;
}
@media (hover: hover) {
  .artist-link:hover,
  .artist-link:focus-visible {
    color: var(--accent);
    text-decoration: underline;
    text-decoration-color: currentColor;
  }
}

.artist-link:focus-visible { outline: none; }
/* Inside the dark featured banner the accent is hard to read on artwork. */
@media (hover: hover) {
  .featured-artist .artist-link:hover,
  .featured-artist .artist-link:focus-visible { color: #fff; }
}

.player audio { flex: 1; height: 36px; min-width: 0; }
#player-close {
  background: var(--bg-soft); border: 1px solid var(--border);
  color: var(--muted); width: 32px; height: 32px; flex: 0 0 auto;
  border-radius: 9px; font-size: 13px; cursor: pointer;
  display: grid; place-items: center; transition: all 0.15s ease;
}
@media (hover: hover) {
  #player-close:hover { color: var(--text); border-color: var(--border-strong); }
}


/* ---------- responsive ---------- */
@media (max-width: 820px) {
  .topbar-inner {
    display: flex; flex-wrap: wrap; align-items: center;
    justify-content: space-between; gap: 12px; padding: 11px 16px;
  }
  /* Phone layout: row 1 = logo (left) + section tabs + RU|EN switch (right, on the
     same line as the tabs); row 2 = full-width search. */
  .controls { display: contents; }
  .brand { order: 1; }
  .nav-tabs { order: 2; margin-left: auto; flex: 0 0 auto; }
  .lang-switch { order: 3; flex: 0 0 auto; }
  .topbar-inner .search-wrap { order: 4; flex: 1 1 100%; }
  .search-wrap input { text-align: left; padding-left: 38px; }
}

@media (max-width: 600px) {
  main { padding: 16px 14px 150px; }
  /* Four section tabs sit beside the logo on the top row. Show only the logo
     mark (hide the wordmark) so everything fits one line on a phone. */
  .topbar-inner { gap: 9px; padding: 10px 12px; }
  .brand-name { display: none; }
  /* Tighten tabs + shrink the RU|EN switch so both fit one row with the logo. */
  .nav-tabs { gap: 11px; }
  .nav-btn { font-size: 13px; letter-spacing: 0; padding: 6px 1px 7px; }
  .lang-switch { height: 30px; padding: 2px; gap: 1px; }
  .lang-opt { height: 24px; padding: 0 8px; font-size: 11px; letter-spacing: 0.3px; }
  .featured-inner { flex-direction: column; align-items: flex-start; gap: 18px; padding: 22px; }
  .featured-art { width: 120px; height: 120px; }
  .section-head h2, .shelf-head h2 { font-size: 19px; }
  .shelf-track .card { flex-basis: 140px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 16px 14px; }
  .footer-note { display: none; }
  /* On touch screens the play control is always visible and meets 44px. */
  .card .play { opacity: 1; transform: none; width: 44px; height: 44px; }
  /* List rows (Top 100 / genre / artist): show a play badge on every cover so
     it's obvious you tap the artwork to start playback (no hover on touch). */
  .tl-art .play { opacity: 1; background: rgba(0, 0, 0, 0.22); }
  .tl-art .play .glyph {
    width: 30px; height: 30px; border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
  }
  /* Narrow cards can't fit the play control plus a fully-labelled pill side
     by side, so shorten the badge to just "320" (keep the mark, drop the
     unit) to stop the buttons overlapping. */
  .card .dl .kbps-unit { display: none; }
  /* List rows: round, icon-only download button (no "320 kbps" text). */
  .track-row .dl { width: 36px; padding: 0; gap: 0; justify-content: center; }
  .track-row .dl .kbps { display: none; }
  /* Phones: keep tempo/key/genre visible without shifting the action buttons.
     Lay the row out as a grid — buttons stay on row 1, the meta drops to row 2
     under the title (rank + artwork span both rows on the left). */
  /* (Not the mix result row — it has a different set of cells + a progress bar.) */
  .track-row:not(.mix-row) {
    display: grid; align-items: center;
    grid-template-columns: auto 52px minmax(0, 1fr) auto auto auto;
    grid-template-areas:
      "rank art main like add dl"
      "rank art meta meta meta meta";
    column-gap: 8px; row-gap: 1px;
  }
  .tl-rank { grid-area: rank; }
  .tl-art  { grid-area: art; }
  .tl-main { grid-area: main; }
  .track-row .row-act.like-btn { grid-area: like; }
  .track-row .add-btn, .track-row .rm-btn { grid-area: add; }
  .track-row .dl { grid-area: dl; }
  .tl-meta {
    grid-area: meta; display: block; max-width: none;
    white-space: normal; font-size: 11.5px; line-height: 1.3; margin: 1px 0 0;
  }
  .list-head h2 { font-size: 22px; }
  /* "Свести микс": full-width button on its own row under the title (phones). */
  .list-head { flex-wrap: wrap; row-gap: 10px; }
  .list-head .mix-head {
    order: 5; flex: 0 0 100%; width: 100%; margin: 0; align-items: stretch;
  }
  .list-head .mix-head .mix-btn {
    flex: none; width: 100%; min-height: 46px; height: 46px; margin: 0;
    justify-content: center; font-size: 15px; box-sizing: border-box;
  }
  .list-head .mix-head .mix-avail { text-align: center; }
  /* Phones: the harmonic-sort control keeps its text label (a bare key icon read
     as a music note and told nobody what the button does). It gets its own
     full-width row above "Свести микс". */
  .list-head .key-sort-btn {
    order: 4; flex: 0 0 100%; width: 100%; min-height: 46px; height: 46px;
    margin: 0; padding: 0 14px; justify-content: center; font-size: 15px;
    box-sizing: border-box; border-radius: 12px;
  }
  /* Chart hero on a phone: one row of [text button][icon][icon], caption below.
     The text button takes whatever is left rather than a hard 100% — that width
     was what pushed the icons onto a line of their own. */
  .coll-hero-mix .mix-head { align-items: center; }
  .coll-hero-mix .mix-btn:not(.mix-btn-icon) {
    flex: 1 1 auto; width: auto; min-width: 0;
    min-height: 46px; height: 46px;
    justify-content: center; font-size: 15px; box-sizing: border-box;
  }
  /* Square, and matching the 46px text button beside it. Also clears the 44px
     touch-target floor, which is what matters on a phone. */
  .coll-hero-mix .mix-btn-icon { width: 46px; height: 46px; flex: 0 0 auto; }
  .coll-hero-mix .mix-avail { text-align: left; }
  /* left/right:0 already spans the screen; the old width/centering is gone.
     bottom:0 comes from the base rule — no footer gap on mobile either. */
  .player-main { flex-wrap: wrap; gap: 10px 12px; padding: 11px 12px; }
  /* min-width:0 lets the nowrap title ellipsize instead of forcing the row
     wider than the screen (the close button was being pushed off-screen). */
  .player-info { flex: 1 1 0; min-width: 0; }
  /* The seek bar gets its own full-width row, but ABOVE the controls — not
     below. As the last row it sat on the very bottom edge of the screen, which
     is where iOS/Android put the swipe-up gesture: swiping to minimise the
     browser scrubbed the track. Buttons there are safe (they are small, spaced,
     and act only on a real tap); a 44px-tall slider was not. */
  .player-seek { order: -1; flex: 1 1 100%; min-width: 0; }
  /* Keep the whole player clear of the home-indicator strip. max() so there is
     a real gap even when Safari reports a 0 inset (URL bar visible). */
  .player-main { padding-bottom: max(14px, env(safe-area-inset-bottom, 0px)); }
  /* the seek bar needs the width more than the actions do */
  .player-act { width: 32px; height: 32px; }
  .player-act svg { width: 16px; height: 16px; }
}

/* Respect users who prefer reduced motion: keep meaning, drop the movement. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---- Pro-mix promo banner (top of home) --------------------------------- */
.promo {
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 22px;
  margin: 14px 0 18px; padding: 22px 26px;
  border: 1px solid var(--border-strong); border-radius: 18px;
  background:
    radial-gradient(120% 140% at 100% 0%, rgba(0, 217, 95, 0.16), transparent 55%),
    linear-gradient(135deg, #101512 0%, #0b0d0c 60%, #0a0a0b 100%);
  box-shadow: var(--shadow-md);
  animation: promo-in 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
.promo[hidden] { display: none; }
@keyframes promo-in { from { opacity: 0; transform: translateY(-8px); } }

/* animated equaliser bars on the left */
.promo-eq {
  flex: 0 0 auto; display: flex; align-items: flex-end; gap: 4px;
  height: 62px; width: 92px; padding: 0 4px;
}
.promo-eq span {
  flex: 1; border-radius: 3px; align-self: flex-end;
  background: linear-gradient(180deg, var(--accent-2), var(--accent));
  box-shadow: 0 0 12px rgba(0, 217, 95, 0.5);
  animation: promo-eq 1.15s ease-in-out infinite;
}
.promo-eq span:nth-child(1) { animation-delay: -.9s; }
.promo-eq span:nth-child(2) { animation-delay: -.2s; }
.promo-eq span:nth-child(3) { animation-delay: -.6s; }
.promo-eq span:nth-child(4) { animation-delay: -.1s; }
.promo-eq span:nth-child(5) { animation-delay: -.75s; }
.promo-eq span:nth-child(6) { animation-delay: -.35s; }
.promo-eq span:nth-child(7) { animation-delay: -.55s; }
.promo-eq span:nth-child(8) { animation-delay: -.15s; }
.promo-eq span:nth-child(9) { animation-delay: -.8s; }
.promo-eq span:nth-child(10){ animation-delay: -.45s; }
@keyframes promo-eq { 0%, 100% { height: 22%; } 50% { height: 100%; } }
@media (prefers-reduced-motion: reduce) {
  .promo { animation: none; }
  .promo-eq span { animation: none; height: 60%; }
}

.promo-body { flex: 1 1 auto; min-width: 0; }
.promo-badge {
  display: inline-block; margin-bottom: 8px; padding: 3px 10px;
  border-radius: 999px; font-size: 11px; font-weight: 800; letter-spacing: 0.6px;
  text-transform: uppercase; color: #04240f;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
}
.promo-title {
  margin: 0 0 6px; font-family: var(--font-display); font-weight: 700;
  font-size: clamp(18px, 2.4vw, 26px); line-height: 1.15; color: var(--text);
}
.promo-title b {
  font-weight: 800;
  background: linear-gradient(135deg, var(--accent-2), var(--accent));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.promo-sub {
  margin: 0 0 14px; color: var(--muted); font-size: 14px; line-height: 1.5;
  max-width: 62ch;
}
.promo-actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.promo-cta {
  border: 0; cursor: pointer; padding: 11px 20px; border-radius: 999px;
  font-family: inherit; font-size: 14px; font-weight: 700; color: #04240f;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  box-shadow: 0 6px 20px rgba(0, 217, 95, 0.35);
  transition: transform 0.12s ease, box-shadow 0.15s ease, filter 0.15s ease;
}
@media (hover: hover) {
  .promo-cta:hover { transform: translateY(-1px); filter: brightness(1.05);
    box-shadow: 0 10px 26px rgba(0, 217, 95, 0.45); }
}

.promo-cta:active { transform: translateY(0); }
.promo-note { color: var(--muted-2); font-size: 12.5px; }
.promo-close {
  position: absolute; top: 12px; right: 14px;
  width: 28px; height: 28px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--border); background: rgba(255, 255, 255, 0.04);
  color: var(--muted); font-size: 13px; line-height: 1;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
@media (hover: hover) {
  .promo-close:hover { color: var(--text); border-color: var(--border-strong);
    background: rgba(255, 255, 255, 0.08); }
}


@media (max-width: 640px) {
  /* Compact banner on phones: drop the equaliser graphic and tighten everything. */
  .promo { gap: 0; padding: 11px 32px 11px 13px; margin: 8px 0 12px; border-radius: 12px; }
  .promo-eq { display: none; }
  .promo-badge { margin-bottom: 5px; font-size: 9.5px; padding: 2px 7px; letter-spacing: 0.4px; }
  .promo-title { font-size: 14px; line-height: 1.22; margin-bottom: 4px; }
  .promo-sub {
    font-size: 11.5px; line-height: 1.4; margin-bottom: 9px;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
  }
  .promo-actions { gap: 9px; }
  .promo-cta { padding: 8px 14px; font-size: 12.5px; }
  .promo-note { font-size: 10.5px; }
  .promo-close { top: 6px; right: 8px; width: 22px; height: 22px; font-size: 11px; }
}

/* ===========================================================================
   Onboarding (post-signup) + the profile fields in the signup form.
   Built on the tokens above so this reads as part of the product, not a
   separate landing page. All hover rules are inside @media (hover: hover) —
   on touch a :hover rule sticks after the tap and looks like a stuck state.
   =========================================================================== */

/* Segmented control (gender) */
.seg { display: flex; gap: 8px; margin: 4px 0 2px; }
.seg-btn {
  flex: 1; min-height: 44px;                    /* 44px: touch target floor */
  padding: 10px 12px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--bg-soft);
  color: var(--text); font: inherit; cursor: pointer;
  transition: border-color .18s ease, background .18s ease, color .18s ease;
}
.seg-btn[aria-checked="true"] {
  border-color: var(--accent); color: var(--accent);
  background: rgba(0, 217, 95, .1);
}
.seg-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
@media (hover: hover) {
  .seg-btn:hover { border-color: var(--border-strong); }
}

/* --- overlay ------------------------------------------------------------- */
.onb {
  position: fixed; inset: 0; z-index: 120;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(120% 90% at 50% 0%, #10231a 0%, var(--bg) 62%);
}
.onb.hidden { display: none; }
/* Backdrop: layered CSS only. Two colour blooms drift slowly behind a faint
   grid; there is no canvas and no library, so nothing here can fail on a weak
   device or steal frames from the card drag. */
.onb::before,
.onb::after {
  content: ""; position: absolute; pointer-events: none; z-index: 0;
  border-radius: 50%; filter: blur(70px);
}
.onb::before {
  width: 68vmin; height: 68vmin; top: -18vmin; left: -14vmin;
  background: radial-gradient(circle, rgba(0, 217, 95, .38), transparent 68%);
  animation: onb-drift-a 26s ease-in-out infinite alternate;
}
.onb::after {
  width: 56vmin; height: 56vmin; right: -16vmin; bottom: -12vmin;
  background: radial-gradient(circle, rgba(0, 255, 163, .22), transparent 70%);
  animation: onb-drift-b 32s ease-in-out infinite alternate;
}
.onb-grid {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(255, 255, 255, .045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .045) 1px, transparent 1px);
  background-size: 46px 46px;
  /* Fade the grid out toward the edges so it reads as depth, not as a table. */
  mask-image: radial-gradient(120% 80% at 50% 42%, #000 30%, transparent 78%);
  -webkit-mask-image: radial-gradient(120% 80% at 50% 42%, #000 30%, transparent 78%);
}
@keyframes onb-drift-a {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(8vmin, 6vmin, 0) scale(1.12); }
}
@keyframes onb-drift-b {
  from { transform: translate3d(0, 0, 0) scale(1.08); }
  to   { transform: translate3d(-7vmin, -5vmin, 0) scale(1); }
}
.onb-inner {
  position: relative; z-index: 1;
  width: min(560px, 100%); max-height: 100%;
  overflow-y: auto; -webkit-overflow-scrolling: touch;
  padding: 20px 20px max(20px, env(safe-area-inset-bottom, 0px));
  display: flex; flex-direction: column;
}
.onb-head { display: flex; align-items: center; justify-content: space-between; }
.onb-steps { display: flex; gap: 6px; }
.onb-dot {
  width: 26px; height: 4px; border-radius: 2px;
  background: rgba(255, 255, 255, .18); transition: background .25s ease;
}
.onb-dot.is-on { background: var(--accent); }
.onb-skip { color: var(--muted); }
.onb-title {
  font-family: "Righteous", var(--font-display); font-weight: 400;
  font-size: clamp(24px, 6vw, 34px); line-height: 1.15; margin: 18px 0 6px;
  text-shadow: 0 0 18px rgba(0, 217, 95, .25);   /* the "minimal glow" cue */
}
.onb-sub { color: var(--muted); margin: 0 0 16px; font-size: 15px; line-height: 1.5; }
.onb-hint { color: var(--muted-2); font-size: 13px; margin: 8px 0 0; }

/* --- step 1: genres ------------------------------------------------------ */
.onb-genres {
  display: grid; gap: 10px; margin: 4px 0 16px;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  /* Clear the sticky footer. Without this the last row of genres sits UNDER the
     "Далее" bar and cannot be read or tapped — caught on a 430px screenshot. */
  padding-bottom: 84px;
}
.onb-genre {
  min-height: 48px; padding: 12px 14px; text-align: left;
  border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--bg-soft); color: var(--text);
  font: inherit; font-size: 14px; cursor: pointer;
  transition: border-color .18s ease, background .18s ease, transform .12s ease;
}
.onb-genre[aria-pressed="true"] {
  border-color: var(--accent); background: rgba(0, 217, 95, .12); color: var(--accent);
}
.onb-genre:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.onb-genre:active { transform: scale(.97); }
@media (hover: hover) {
  .onb-genre:hover { border-color: var(--border-strong); }
}
.onb-foot {
  position: sticky; bottom: 0; display: flex; padding: 14px 0;
  /* Opaque, not a fade: text scrolling behind a translucent bar was unreadable. */
  background: var(--bg);
  box-shadow: 0 -12px 20px 8px var(--bg);
}
/* The bar holds the button alone now that the selection counter is gone, so it
   spans the full width instead of hugging one edge. */
.onb-foot .btn-primary { width: 100%; }

/* --- step 2: card deck --------------------------------------------------- */
.onb-progress {
  height: 4px; border-radius: 2px; background: rgba(255, 255, 255, .12);
  overflow: hidden; margin-top: 4px;
}
.onb-bar {
  height: 100%; width: 0%; border-radius: 2px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: width .3s ease;
}
.onb-deck {
  position: relative; margin: 14px auto 0; width: 100%;
  aspect-ratio: 1 / 1; max-width: 340px;
}
.onb-card {
  position: absolute; inset: 0; border-radius: 18px; overflow: hidden;
  border: 1px solid var(--border-strong); background: var(--bg-elev);
  box-shadow: var(--shadow-md); cursor: grab;
  display: flex; flex-direction: column; justify-content: flex-end;
  touch-action: pan-y;              /* let vertical scrolling through, keep drags */
  will-change: transform, opacity;  /* transform/opacity only — never width/height */
}
.onb-card.is-back { transform: scale(.94) translateY(10px); opacity: .55; }
.onb-card-art {
  position: absolute; inset: 0; background-size: cover; background-position: center;
}
.onb-card-art::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(0,0,0,.92) 6%, rgba(0,0,0,.35) 48%, rgba(0,0,0,.1) 100%);
}
.onb-card-body { position: relative; padding: 16px; }
.onb-card-title {
  margin: 0; font-size: 18px; font-weight: 600; line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.onb-card-art-name { margin: 3px 0 8px; color: #d7d7db; font-size: 14px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.onb-badges { display: flex; flex-wrap: wrap; gap: 6px; }
.onb-badge {
  padding: 4px 9px; border-radius: 999px; font-size: 11px; white-space: nowrap;
  background: rgba(255, 255, 255, .14); color: #f0f0f2;
  backdrop-filter: blur(6px);
}
/* Verdict stamps that follow the drag, so the gesture explains itself. */
.onb-stamp {
  position: absolute; top: 16px; padding: 6px 12px; border-radius: 8px;
  font-family: "Righteous", var(--font-display); font-size: 15px;
  letter-spacing: 1px; opacity: 0; transition: opacity .12s linear;
  border: 2px solid currentColor;
}
.onb-stamp-yes { left: 16px; color: var(--accent); transform: rotate(-10deg); }
.onb-stamp-no  { right: 16px; color: #ff5f57;     transform: rotate(10deg); }
.onb-eq { position: absolute; top: 16px; right: 16px; display: flex; gap: 3px;
  align-items: flex-end; height: 18px; }
.onb-eq i {
  width: 3px; background: var(--accent); border-radius: 2px;
  animation: onb-eq 900ms ease-in-out infinite;
}
.onb-eq i:nth-child(2) { animation-delay: .15s; }
.onb-eq i:nth-child(3) { animation-delay: .3s; }
.onb-eq i:nth-child(4) { animation-delay: .45s; }
.onb-eq.is-paused i { animation-play-state: paused; height: 5px; }
@keyframes onb-eq { 0%, 100% { height: 5px; } 50% { height: 18px; } }

.onb-actions {
  display: flex; align-items: center; justify-content: center; gap: 18px;
  margin: 18px 0 4px;
}
.onb-act {
  width: 60px; height: 60px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--border-strong); background: var(--bg-soft);
  color: var(--text); transition: transform .12s ease, background .18s ease;
}
.onb-act:active { transform: scale(.92); }
.onb-act:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.onb-act-play { width: 48px; height: 48px; color: var(--muted); }
.onb-act-yes { color: var(--accent); border-color: rgba(0, 217, 95, .5); }
.onb-act-no  { color: #ff5f57;      border-color: rgba(255, 95, 87, .5); }
@media (hover: hover) {
  .onb-act-yes:hover { background: rgba(0, 217, 95, .14); }
  .onb-act-no:hover  { background: rgba(255, 95, 87, .14); }
  .onb-act-play:hover { color: var(--text); }
}
.onb-empty { text-align: center; color: var(--muted); padding: 40px 12px; }

@media (max-width: 420px) {
  .onb-deck { max-width: 100%; }
  .onb-act { width: 56px; height: 56px; }
}

/* Motion is decoration here: with reduced-motion the deck still works, it just
   snaps instead of sliding, and the equalizer stops pulsing. */
@media (prefers-reduced-motion: reduce) {
  .onb-card, .onb-bar, .onb-genre, .onb-act { transition: none; }
  .onb-eq i { animation: none; height: 10px; }
  .onb::before, .onb::after { animation: none; }
}

/* ===========================================================================
   Onboarding finish: the steps disappear, a green check with "Готово" rises from
   below, and confetti goes off along both edges for ~2.5s before the home page.
   Everything animates transform/opacity only — no layout properties.
   =========================================================================== */
.onb.is-done .onb-inner { display: none; }      /* clear the screen */
.onb-done {
  position: absolute; inset: 0; z-index: 2;
  display: grid; place-items: center; overflow: hidden;
}
.onb-done.hidden { display: none; }
.onb-done-inner {
  display: flex; flex-direction: column; align-items: center; gap: 16px;
  animation: onb-rise 620ms cubic-bezier(.16, .84, .28, 1) both;
}
@keyframes onb-rise {
  from { opacity: 0; transform: translateY(56px) scale(.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.onb-check svg { width: 92px; height: 92px; display: block; }
.onb-check-ring, .onb-check-tick {
  fill: none; stroke: var(--accent); stroke-width: 3;
  stroke-linecap: round; stroke-linejoin: round;
}
/* Draw the ring, then the tick — dash offset animation, so the mark appears to be
   written rather than just faded in. */
.onb-check-ring {
  stroke-dasharray: 145; stroke-dashoffset: 145;
  animation: onb-draw 560ms ease-out 120ms forwards;
}
.onb-check-tick {
  stroke-dasharray: 40; stroke-dashoffset: 40; stroke-width: 4;
  animation: onb-draw 320ms ease-out 520ms forwards;
}
@keyframes onb-draw { to { stroke-dashoffset: 0; } }
.onb-done-text {
  margin: 0; font-family: "Righteous", var(--font-display); font-weight: 400;
  font-size: clamp(28px, 8vw, 40px); letter-spacing: .5px;
  text-shadow: 0 0 22px rgba(0, 217, 95, .35);
}

/* Confetti: two columns hugging the edges, pieces injected by JS. */
.onb-conf { position: absolute; top: 0; bottom: 0; width: 34%; pointer-events: none; }
.onb-conf-l { left: 0; }
.onb-conf-r { right: 0; }
.onb-conf i {
  position: absolute; bottom: -16px; width: 8px; height: 14px; border-radius: 2px;
  opacity: 0; will-change: transform, opacity;
  animation: onb-conf-fly var(--dur, 2200ms) cubic-bezier(.2, .6, .3, 1) var(--delay, 0ms) forwards;
}
@keyframes onb-conf-fly {
  0%   { opacity: 0; transform: translate3d(0, 0, 0) rotate(0deg); }
  12%  { opacity: 1; }
  100% { opacity: 0;
         transform: translate3d(var(--dx, 0), var(--dy, -78vh), 0) rotate(var(--rot, 540deg)); }
}

/* Motion here is pure celebration, so with reduced-motion the state simply IS:
   check drawn, word visible, no confetti at all. */
@media (prefers-reduced-motion: reduce) {
  .onb-done-inner { animation: none; }
  .onb-check-ring, .onb-check-tick { animation: none; stroke-dashoffset: 0; }
  .onb-conf { display: none; }
}

/* Retry inside the empty deck: a normal-width button, not a full-bleed bar. */
.onb-retry { width: auto; min-width: 160px; margin-top: 14px; padding: 0 20px; }
