/* ── Search ── */
.search-container {
  display: flex; flex-direction: column; gap: 14px; margin-bottom: 28px;
  position: sticky; top: calc(var(--nav-height) + env(safe-area-inset-top, 0px)); z-index: 90;
  background: var(--bg); padding-top: 8px; padding-bottom: 8px;
}
.search-row {
  display: flex; gap: 12px; align-items: center;
}
.search-input-wrap {
  flex: 1; position: relative;
}
.search-logo {
  position: absolute; left: 16px; top: 50%; transform: translateY(-50%);
  width: 22px; height: 22px; pointer-events: none; opacity: 0.7;
}
.search-input {
  width: 100%; padding: 16px 48px 16px 50px; font-size: 16px;
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius); color: var(--text); outline: none;
  font-family: inherit; transition: all var(--transition);
  box-shadow: inset 0 1px 3px rgba(0,0,0,.2);
}
.search-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim), inset 0 1px 3px rgba(0,0,0,.2); }
.search-input::placeholder { color: var(--text-dim); }

#searchClear {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  background: none; border: none; color: var(--red, #ef4444); font-size: 20px;
  cursor: pointer; padding: 4px 8px; display: none; transition: opacity var(--transition);
  opacity: 0.7;
}
#searchClear:hover { opacity: 1; }

.btn-mic {
  width: 52px; height: 52px; border-radius: 50%;
  background: var(--bg-card); border: 2px solid var(--border);
  color: var(--text-muted); cursor: pointer; display: flex;
  align-items: center; justify-content: center; transition: all .3s;
  flex-shrink: 0;
}
.btn-mic:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-dim); }
.btn-mic.recording {
  border-color: var(--red); color: var(--red);
  animation: pulse 1.5s ease infinite;
  box-shadow: 0 0 24px rgba(239, 68, 68, 0.3);
}
.btn-mic.identifying { border-color: var(--accent); color: var(--accent); animation: pulse 1s ease infinite; }

.mic-status {
  font-size: 12px; color: var(--text-muted);
  text-align: center; width: 100%;
}
.mic-status:empty { display: none; }

/* Live input-level meter shown only while recording (Fix 4). Hidden by
   default; JS toggles .active so it doesn't reserve layout space when idle. */
.mic-level {
  display: none; width: 100%; height: 4px; margin-top: 6px;
  border-radius: 2px; background: var(--bg-card); border: 1px solid var(--border);
  overflow: hidden;
}
.mic-level.active { display: block; }
.mic-level-fill {
  height: 100%; width: 0%; background: var(--accent);
  transition: width .1s linear;
}
.mic-level-fill.quiet { background: var(--red); }

.type-toggle {
  display: flex; gap: 6px; flex-wrap: wrap;
}
.type-btn {
  background: var(--bg-card); border: 1px solid var(--border); color: var(--text-muted);
  padding: 8px 18px; cursor: pointer; font-size: 13px; transition: all var(--transition);
  font-family: inherit; font-weight: 500; border-radius: 20px;
}
.type-btn:hover { border-color: var(--border-hover); color: var(--text); }
.type-btn.active { background: var(--accent); color: #000; font-weight: 600; border-color: var(--accent); }

/* ── Recognize Result ── */
.recognize-result {
  background: var(--bg-card); border: 1px solid var(--accent); border-radius: var(--radius);
  padding: 20px; margin-bottom: 24px; display: none;
  animation: slideUp .3s ease;
  box-shadow: 0 0 20px rgba(162,230,64,.1);
}
.recognize-result .rr-header { display: flex; gap: 16px; align-items: center; }
.recognize-result .rr-img { width: 64px; height: 64px; border-radius: var(--radius-sm); object-fit: cover; }
.recognize-result .rr-info { flex: 1; min-width: 0; }
.recognize-result .rr-title { font-size: 16px; font-weight: 700; }
.recognize-result .rr-artist { font-size: 14px; color: var(--text-muted); margin-top: 2px; }
.recognize-result .rr-label { font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 6px; font-weight: 600; }
.recognize-result .rr-actions { display: flex; gap: 8px; margin-left: auto; }
.recognize-result .rr-btn {
  padding: 8px 16px; border-radius: 20px; border: none;
  font-size: 13px; font-weight: 600; cursor: pointer; font-family: inherit;
  transition: all var(--transition);
}
.rr-btn-download { background: var(--accent); color: #000; }
.rr-btn-download:hover { box-shadow: var(--shadow-glow); }
.rr-btn-search { background: var(--bg-elevated); color: var(--text); border: 1px solid var(--border) !important; }
.rr-btn-search:hover { border-color: var(--accent) !important; }
.rr-btn-close { background: none; color: var(--text-muted); font-size: 18px; cursor: pointer; border: none; padding: 4px 8px; }

/* ── All-mode aggregated search (Spotify-style sections) ── */
.search-section { margin-top: 28px; }

.search-section-header {
  display: flex; align-items: baseline; justify-content: space-between;
  margin: 0 0 12px;
}
.search-section-header h3 {
  font-size: 20px; font-weight: 700; color: var(--text); margin: 0;
}
.section-showall {
  background: none; border: none; cursor: pointer; font-family: inherit;
  font-size: 12px; font-weight: 600; letter-spacing: .4px; text-transform: uppercase;
  color: var(--text-dim); padding: 4px 2px; transition: color .15s;
}
.section-showall:hover { color: var(--text); }

/* ── Top-result hero row (top card + songs panel) ── */
.top-result-row {
  display: grid; grid-template-columns: minmax(0, 340px) 1fr; gap: 20px;
  margin-top: 8px;
}

.top-result-card {
  background: var(--bg-card); border-radius: 16px; padding: 20px;
  position: relative; display: flex; flex-direction: column; gap: 4px;
  overflow: visible;
}
/* .card-play-btn's shared cards.css rule anchors to `100cqw` (the artwork's
   height, since .card-img is width:100%;aspect-ratio:1) — that doesn't hold
   here: .top-result-img is a FIXED 180px square (140px below the 640px
   breakpoint), unrelated to the hero card's own (much wider, up to 340px)
   inline size. Fall back to a fixed px offset instead: 20px card padding-top
   + 180px artwork - 8px inset - 36px button height = 156px (116px at the
   140px mobile artwork size, kept in sync with the breakpoint below). This
   selector's specificity (2 classes) already wins over the shared rule, so
   no !important is needed. */
.top-result-card .card-play-btn,
.top-result-card .card-radio-btn,
.top-result-card .card-addpl-btn { top: 156px; bottom: auto; }
/* Horizontal placement of the radio/add buttons is set in JS (buildTopResultCard),
   because it depends on whether a play button exists for this item type; only the
   artwork-relative `top` is static, so it lives here with the play button. */
.top-result-img {
  width: 180px; height: 180px; max-width: 100%; border-radius: 8px;
  object-fit: cover; background: var(--bg-elevated); margin-bottom: 12px;
}
.top-result-card.artist-card .top-result-img { border-radius: 50%; }
.top-result-name {
  font-size: 26px; font-weight: 800; line-height: 1.15; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.top-result-type {
  font-size: 13px; color: var(--text-dim); text-transform: capitalize;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.top-songs-panel { min-width: 0; }

/* ── Song rows (compact list; each row carries .card for play delegation) ── */
/* The album/playlist track list lives inside #albumTracks, which is a CSS grid
   (styled for card layouts). Span all columns + full width so the flat list
   doesn't collapse into a single ~150px grid cell (which zeroed out titles). */
.song-list { display: flex; flex-direction: column; gap: 2px; width: 100%; grid-column: 1 / -1; }
.song-list .song-row {
  display: flex; align-items: center; gap: 12px; padding: 8px;
  border-radius: 8px; cursor: pointer; background: transparent;
  overflow: visible; border: 1px solid transparent;
}
.song-list .song-row:hover { background: var(--bg-elevated); transform: none; box-shadow: none; }
.song-list .song-row:active { transform: none; }
.song-row .song-thumb {
  width: 44px; height: 44px; border-radius: 4px; object-fit: cover;
  background: var(--bg-elevated); flex-shrink: 0;
}
/* Numbered album list: track position replaces the repeated cover thumbnail. */
.song-num {
  width: 28px; flex-shrink: 0; text-align: center;
  font-size: 14px; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.song-info { min-width: 0; flex: 1; }
.song-title {
  font-size: 14px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.3;
}
.song-artist {
  font-size: 12px; color: var(--text-muted); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.song-duration { color: var(--text-dim); font-size: 12px; flex-shrink: 0; }
/* Reset the card-absolute buttons back to inline flow inside a row. */
.song-list .song-row .card-play-btn {
  position: static; width: 32px; height: 32px; box-shadow: none;
  opacity: 0; transform: none; flex-shrink: 0;
}
.song-list .song-row:hover .card-play-btn { opacity: 1; transform: none; }
.song-list .song-row .kebab-btn {
  position: static; width: 32px; height: 32px; background: none; flex-shrink: 0;
}
.song-list .song-row .kebab-btn:hover { background: var(--bg-elevated); }
.song-list .song-row .like-btn { position: static; width: 32px; height: 32px; flex-shrink: 0; }
/* Quick add-to-playlist: same inline-flow reset as the play button above. */
.song-list .song-row .card-addpl-btn {
  position: static; width: 32px; height: 32px; background: none; border: none;
  box-shadow: none; opacity: 0; transform: none; flex-shrink: 0;
}
.song-list .song-row:hover .card-addpl-btn { opacity: 1; transform: none; }
.song-list .song-row .card-addpl-btn:hover { background: var(--bg-elevated); }
/* The card overlay "In Library" badge is position:absolute (built for cover art)
   and would float over the track title on a flat row. Drop it and instead tint
   the track number of in-library rows — clean and non-overlapping. */
.song-list .song-row .in-library-badge { display: none; }
.song-list .song-row.in-library .song-num { color: var(--accent); }

/* Circular artist thumbnails on result cards. */
.card.artist-card .card-img { border-radius: 50%; }

/* Aligned to the app's single mobile breakpoint (640px — see responsive.css,
   which switches the card grids, nav, modal, etc. at max-width:640px). This
   used to be 760px, so the 641–760px range rendered the hero row collapsed
   to mobile layout while the card grids below it were still on desktop
   sizing ("mobile on top, desktop below"). Picked 640 over bumping the rest
   of the app to 760 since 640 is already the established convention
   everywhere else and responsive.css is out of this fix's scope. */
@media (max-width: 640px) {
  .top-result-row { grid-template-columns: 1fr; gap: 16px; }
  .top-result-img { width: 140px; height: 140px; }
  .top-result-name { font-size: 22px; }
  /* Keep in sync with .top-result-img's shrink above: 20px padding-top +
     140px artwork - 8px inset - 36px button height = 116px. */
  .top-result-card .card-play-btn,
  .top-result-card .card-radio-btn,
  .top-result-card .card-addpl-btn { top: 116px; }
  .song-list .song-row .card-play-btn,
  .song-list .song-row .card-addpl-btn { opacity: 1; }
  /* Universal-search rows now carry play + add + kebab + heart; at this width the
     title already truncates, so drop the heart here the same way the numbered
     album/playlist list below does (still reachable from the ⋮ menu). */
  .song-list:not(.song-list-numbered) .song-row .like-btn { display: none; }
  /* Album/playlist track list: maximise room for the title on narrow screens by
     dropping the per-row heart + BPM badge (both still reachable — the ⋮ menu and
     the tempo-filter bar respectively) and tightening the gaps. */
  .song-list-numbered .song-row { gap: 8px; }
  .song-list-numbered .song-row .like-btn,
  .song-list-numbered .song-row .bpm-badge { display: none; }
}

/* ── Playlist import banner (search page) ──
   Shown when a Spotify/Deezer playlist/album link is pasted into the search
   box. Deliberately reads as a result, not an error: cover thumb + name +
   actions. The imported list is playable without downloading anything, so
   "Play all" is the primary action and "Download all" is just one more button. */
.import-banner {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px; margin-bottom: 20px;
}
.import-banner-thumb {
  width: 72px; height: 72px; flex-shrink: 0;
  border-radius: var(--radius-sm); object-fit: cover;
  background: var(--bg-elevated);
}
.import-banner-thumb--empty { border: 1px solid var(--border); }
.import-banner-info { flex: 1 1 200px; min-width: 0; }
.import-banner-title {
  font-size: 15px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.import-banner-meta { font-size: 12px; color: var(--text-muted); margin-top: 3px; }
.import-banner-note {
  font-size: 12px; color: var(--text-muted); line-height: 1.5; margin-top: 8px;
  padding: 8px 10px; border-radius: var(--radius-sm);
  background: var(--accent-dim); border: 1px solid var(--border);
}
.import-banner-hint { font-size: 13px; color: var(--text-muted); }

/* Note action ("Paste track links…") — the documented way past Spotify's
   100-track ceiling, so it must look tappable, not like body copy. Shared with
   the same note rendered into the playlist detail hero (.import-note). */
.import-banner-notebtn,
.import-note .pl-note-btn {
  background: none; border: none; padding: 0; margin-left: 6px;
  color: var(--accent); font-family: inherit; font-size: 12px; font-weight: 600;
  cursor: pointer; text-decoration: underline;
}
.import-banner-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.import-btn {
  background: var(--bg-elevated); border: 1px solid var(--border); color: var(--text);
  padding: 9px 16px; border-radius: 20px; cursor: pointer;
  font-family: inherit; font-size: 13px; font-weight: 500;
  transition: all var(--transition); white-space: nowrap;
}
.import-btn:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-dim); }
.import-btn-primary {
  background: var(--accent); border-color: var(--accent); color: #000; font-weight: 600;
}
.import-btn-primary:hover { background: var(--accent); color: #000; opacity: .88; }

/* ── Truncation escape hatches (banner note + playlist detail note) ──
   "Get all tracks automatically" drives the server-side headless harvest; it is
   the primary action, so the manual console helper next to it is a text link.
   The job takes minutes, hence the live status line underneath. */
.import-harvest {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; margin-top: 8px;
}
.import-harvest-btn {
  font-size: 12px; padding: 7px 14px; max-width: 100%; white-space: normal;
}
.import-harvest-btn:disabled { opacity: .6; cursor: default; }
.import-harvest-btn:disabled:hover { background: var(--accent); color: #000; }
.import-harvest-manual { margin-left: 0; }
/* Full-width own row so a long "Collecting… 120 tracks" never widens the note. */
.import-harvest-status {
  flex: 1 1 100%; display: flex; align-items: center; gap: 8px; min-width: 0;
  font-size: 12px; color: var(--text-muted);
}
/* `display: flex` above beats the [hidden] attribute, so hiding this row in JS
   left an empty status line whose spinner pulsed forever. */
.import-harvest-status[hidden] { display: none; }
.import-harvest-status--error { color: var(--text); }
.import-harvest-text { min-width: 0; overflow-wrap: anywhere; }
.import-harvest-spin {
  width: 9px; height: 9px; flex-shrink: 0; border-radius: 50%;
  background: var(--accent); animation: import-harvest-pulse 1s ease-in-out infinite;
}
@keyframes import-harvest-pulse {
  0%, 100% { opacity: .25; transform: scale(.8); }
  50%      { opacity: 1;   transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .import-harvest-spin { animation: none; opacity: .8; }
}

/* ── "Grab the whole playlist" helper (import modal) ──
   Collapsed by default: it is the answer to the 100-track ceiling, but it costs
   a console paste, so it must not compete with just pasting a link. */
.import-helper {
  margin-top: 12px; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-elevated);
}
.import-helper-summary {
  cursor: pointer; font-size: 12px; font-weight: 600; color: var(--accent);
  list-style: none;
}
.import-helper-summary::-webkit-details-marker { display: none; }
.import-helper-summary::before { content: '▸ '; }
.import-helper[open] .import-helper-summary::before { content: '▾ '; }
.import-helper-why {
  font-size: 12px; color: var(--text-muted); line-height: 1.5; margin: 10px 0 0;
}
.import-helper-steps {
  font-size: 12px; color: var(--text-muted); line-height: 1.5;
  margin: 8px 0 0; padding-left: 20px;
}
.import-helper-steps li { margin-bottom: 3px; }
.import-helper-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.import-helper-actions .import-btn { font-size: 12px; padding: 7px 13px; }
/* Only shown when the clipboard API is unavailable or refuses. */
.import-helper-field {
  width: 100%; margin-top: 10px; padding: 8px 10px; resize: vertical;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-card); color: var(--text);
  font-family: monospace; font-size: 11px; line-height: 1.4;
}

/* Truncation note inside the playlist detail hero. */
.import-note {
  font-size: 12px; color: var(--text-muted); line-height: 1.5; margin-top: 8px;
  max-width: 520px;
}

@media (max-width: 640px) {
  /* Stack: thumb + title on one row, actions full-width underneath. Nothing may
     overflow horizontally at 390px, so the buttons share the row and wrap. */
  .import-banner { gap: 12px; padding: 12px; }
  .import-banner-thumb { width: 56px; height: 56px; }
  .import-banner-info { flex-basis: calc(100% - 68px); }
  .import-banner-actions { flex-basis: 100%; }
  .import-banner-actions .import-btn { flex: 1 1 auto; padding: 9px 12px; text-align: center; }
}
