/* =========================================================
   BUTTONS
   ========================================================= */

.btn {
  width: var(--tap-md);
  height: var(--tap-md);

  display: inline-flex;
  align-items: center;
  justify-content: center;

  border: none;
  border-radius: 50%;

  background: transparent;
  color: var(--text-muted);

  cursor: pointer;

  transition:
    background 0.15s ease,
    color 0.15s ease,
    transform 0.1s ease;
}

.btn svg {
  /* Every icon-only button defaults to the utility tier — the vast
     majority of them (shuffle, repeat, mute, queue, lyrics, back/
     forward, menu toggle) are exactly that. The two contexts that
     aren't (play/pause; the compact .small variant) override this
     specifically below, rather than every icon carrying its own size
     — see css/base.css's --icon-*/--tap-* tokens for the full tier
     rationale. */
  width: var(--icon-sm);
  height: var(--icon-sm);
}

/* Compact/dense chrome — currently just the queue panel's close
   button. A full --tap-md button here would visually crowd a small
   panel header; --tap-sm still clears WCAG's 24px touch-target floor
   with real margin (32px), unlike the pre-existing 22px .clear-search
   this deliberately now matches (see below). */
.btn.small {
  width: var(--tap-sm);
  height: var(--tap-sm);
}

.btn.small svg {
  width: var(--icon-xs);
  height: var(--icon-xs);
}

.btn:hover {
  background: var(--surface-alt);
  color: var(--text);
  transform: scale(1.04);
}

.btn:active {
  transform: scale(0.94);
}

.btn:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.btn:disabled:hover {
  background: transparent;
  color: var(--text-muted);
  transform: none;
}

/* =========================================================
   SEARCH
   ========================================================= */

.search {
  position: relative; /* anchors the suggestions dropdown */

  width: min(420px, 40vw);
  height: 44px;

  display: flex;
  align-items: center;

  gap: 10px;
  padding: 0 16px;

  border-radius: var(--radius-pill);

  background: var(--surface-alt);
  border: 1px solid transparent;

  color: var(--text-muted);

  transition:
    border-color var(--dur-base) var(--ease-out),
    background var(--dur-base) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out);
}

.search:focus-within {
  border-color: var(--pink);
  background: var(--surface);
  box-shadow: 0 0 0 4px var(--pink-soft);
}

.search input {
  width: 100%;

  border: none;
  outline: none;

  background: transparent;
  color: var(--text);

  font-size: var(--fs-body);
}

/* The app draws its own clear button (#clearSearchBtn); the
   browser's built-in one on type="search" made two × side by side. */
.search input::-webkit-search-cancel-button,
.search input::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
}

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

.clear-search {
  /* Was 22px — below WCAG 2.5.8's 24px touch-target floor. --tap-sm
     (32px) clears it with real margin, same compact tier as the
     queue panel's close button. */
  flex-shrink: 0;

  width: var(--tap-sm);
  height: var(--tap-sm);

  display: flex;
  align-items: center;
  justify-content: center;

  border: none;
  border-radius: 50%;

  background: var(--surface);
  color: var(--text-muted);

  cursor: pointer;

  /* Fades in and out (js/search.js toggles .is-visible) instead of
     popping, and takes no clicks while hidden. */
  opacity: 0;
  transform: scale(0.8);
  visibility: hidden;

  transition:
    opacity var(--dur-fast) ease,
    transform var(--dur-fast) ease,
    visibility 0s linear var(--dur-fast),
    background 0.15s ease,
    color 0.15s ease;
}

.clear-search.is-visible {
  opacity: 1;
  transform: none;
  visibility: visible;

  transition:
    opacity var(--dur-fast) ease,
    transform var(--dur-fast) ease,
    background 0.15s ease,
    color 0.15s ease;
}

.clear-search svg {
  width: var(--icon-xs);
  height: var(--icon-xs);
}

.clear-search:hover {
  background: var(--pink-light);
  color: var(--pink);
}

/* =========================================================
   AVATAR
   ========================================================= */

.avatar {
  width: 36px;
  height: 36px;

  flex-shrink: 0;

  display: flex;
  align-items: center;
  justify-content: center;

  border: none;
  border-radius: 50%;

  background: linear-gradient(135deg, var(--pink-fill), var(--pink-dark));

  color: #fff;

  font: inherit;
  font-size: 14px;
  font-weight: 700;

  cursor: pointer;

  transition: transform 0.15s ease;
}

.avatar:hover {
  transform: scale(1.06);
}

.avatar svg {
  width: 18px;
  height: 18px;
}

/* Preferences panel from the avatar, and the first-visit welcome
   (js/profile-menu.js) */
.prefs-panel {
  position: fixed;

  z-index: 1400;

  width: 340px;
  max-height: calc(100vh - 80px);

  overflow-y: auto;

  padding: var(--space-5);

  border-radius: var(--radius-lg);
  border: 1px solid var(--border-strong);

  background: var(--surface-alt);

  box-shadow: var(--shadow-md);

  animation: save-to-in var(--dur-base) var(--ease-out);
}

/* First visit: a centered card over a dimmed page. */
.prefs-panel.is-welcome {
  top: 50%;
  left: 50%;

  width: min(440px, calc(100vw - 32px));
  max-height: calc(100dvh - 32px);

  transform: translate(-50%, -50%);

  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.6), var(--shadow-md);

  /* The first impression: the brand's pink-to-violet glow. */
  background:
    radial-gradient(90% 60% at 0% 0%, rgba(214, 20, 95, 0.22), transparent 70%),
    radial-gradient(90% 60% at 100% 100%, rgba(142, 45, 226, 0.2), transparent 70%),
    var(--surface-alt);

  animation: none;
}

.prefs-title {
  margin: 0 0 var(--space-2);

  color: var(--text);

  font-size: var(--fs-title);
  font-weight: 800;
}

.prefs-panel.is-welcome .prefs-title {
  font-size: 22px;
}

.prefs-intro {
  margin: 0 0 var(--space-4);

  color: var(--text-muted);

  font-size: var(--fs-body);
}

.prefs-label {
  display: block;

  margin: var(--space-4) 0 var(--space-2);
  padding: 0;

  color: var(--text);

  font-size: var(--fs-body-sm);
  font-weight: 700;
}

.prefs-optional {
  color: var(--text-faint);
  font-weight: 500;
}

/* A one-line heads-up under a choice (the English catalog note). */
.prefs-note {
  margin: var(--space-2) 0 0;

  color: var(--text-muted);

  font-size: var(--fs-body-sm);
  line-height: 1.4;
}

.prefs-note[hidden] {
  display: none;
}

/* The account row at the top of preferences: who's signed in, or Sign in. */
.prefs-account {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);

  margin-bottom: var(--space-2);
  padding: var(--space-3);

  border-radius: var(--radius-md);

  background: var(--surface);

  font-size: var(--fs-body-sm);
}

.prefs-account-text {
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

.prefs-account-text strong {
  color: var(--text);
}

.prefs-account-button {
  flex: none;

  min-height: 36px;
  padding: 0 var(--space-4);

  border: none;
  border-radius: var(--radius-pill);

  background: var(--pink-fill);
  color: #fff;

  font: inherit;
  font-weight: 700;

  cursor: pointer;
}

.prefs-link {
  flex: none;

  padding: 0;

  border: none;

  background: none;
  color: var(--pink);

  font: inherit;
  font-weight: 700;

  cursor: pointer;
}

/* "Artists you like" in the welcome: round photos with names, picked
   like the language chips. */
.prefs-artists {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);

  margin-top: var(--space-2);
}

.prefs-artist {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);

  padding: 4px 12px 4px 4px;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);

  font-size: var(--fs-body-sm);
  font-weight: 600;

  cursor: pointer;
}

.prefs-artist input {
  position: absolute;

  opacity: 0;
  pointer-events: none;
}

.prefs-artist img {
  width: 28px;
  height: 28px;

  border-radius: 50%;

  object-fit: cover;
}

.prefs-artist:has(input:checked) {
  border-color: var(--pink-fill);

  background: var(--pink-fill);
  color: #fff;
}

.prefs-artist:has(input:focus-visible) {
  outline: 2px solid var(--pink);
  outline-offset: 2px;
}

/* "Hidden from Home": artists set aside with "Don't recommend". */
.prefs-hidden {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);

  margin: 0;
  padding: 0;

  list-style: none;
}

.prefs-hidden li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);

  font-size: var(--fs-body);
}

.prefs-show-again {
  min-height: 32px;
  padding: 0 var(--space-3);

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);

  background: none;
  color: var(--text);

  font: inherit;
  font-size: var(--fs-body-sm);
  font-weight: 600;

  cursor: pointer;
}

.prefs-show-again:hover {
  border-color: var(--text-muted);
}

.prefs-input {
  width: 100%;
  padding: 10px 12px;

  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  outline: none;

  background: var(--surface);
  color: var(--text);

  font: inherit;
  font-size: var(--fs-body);
}

.prefs-input:focus {
  border-color: var(--pink);
}

/* Spacing sits on the group, not the legend: browsers ignore a
   <legend>'s top margin. */
.prefs-group {
  margin: var(--space-5) 0 0;
  padding: 0;

  border: none;
}

.prefs-group > .prefs-label {
  margin-top: 0;
}

.prefs-chips {
  display: flex;
  flex-wrap: wrap;

  gap: var(--space-2);
}

.prefs-chip input,
.prefs-option input {
  position: absolute;

  opacity: 0;
  pointer-events: none;
}

.prefs-chip span {
  display: inline-block;

  padding: 7px 14px;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);

  color: var(--text-muted);

  font-size: var(--fs-body-sm);
  font-weight: 600;

  cursor: pointer;

  transition:
    background var(--dur-fast) ease,
    color var(--dur-fast) ease,
    border-color var(--dur-fast) ease;
}

.prefs-chip input:checked + span {
  border-color: var(--pink-fill);

  background: var(--pink-fill);
  color: #fff;
}

.prefs-chip input:focus-visible + span,
.prefs-option input:focus-visible ~ .prefs-option-label {
  outline: 2px solid var(--pink);
  outline-offset: 2px;
}

.prefs-options {
  display: grid;

  gap: var(--space-1);
}

.prefs-option {
  display: flex;
  align-items: baseline;

  gap: var(--space-2);
  padding: 8px 12px;

  border-radius: var(--radius-md);

  cursor: pointer;
}

.prefs-option:has(input:checked) {
  background: var(--pink-soft);
}

.prefs-option-label {
  color: var(--text);

  font-size: var(--fs-body);
  font-weight: 600;
}

.prefs-option:has(input:checked) .prefs-option-label {
  color: var(--pink);
}

.prefs-option-hint {
  color: var(--text-faint);

  font-size: var(--fs-body-sm);
}

.prefs-error {
  margin: var(--space-3) 0 0;

  color: var(--error);

  font-size: var(--fs-body-sm);
}

.prefs-actions {
  display: flex;
  justify-content: flex-end;

  gap: var(--space-2);
  margin-top: var(--space-5);
}

.prefs-cancel,
.prefs-save {
  padding: 10px 20px;

  border: none;
  border-radius: var(--radius-pill);

  font: inherit;
  font-size: var(--fs-body-sm);
  font-weight: 700;

  cursor: pointer;
}

/* Secondary actions everywhere: an outlined pill (.hero-secondary-btn,
   .playlist-edit-cancel). Primary: a pink fill. */
.prefs-cancel {
  border: 1px solid var(--border-strong);

  background: transparent;
  color: var(--text-muted);
}

.prefs-cancel:hover {
  background: var(--surface-alt);
  color: var(--text);
}

.prefs-save {
  background: var(--pink-fill);
  color: #fff;
}

.prefs-save:hover {
  background: var(--pink-fill-hover);
}

.prefs-panel.is-welcome .prefs-save {
  width: 100%;
  padding: 12px;

  font-size: var(--fs-body);
}

body.prefs-welcome-open {
  overflow: hidden;
}

/* =========================================================
   HERO
   ========================================================= */

.hero {
  min-height: 176px;

  position: relative;

  display: flex;
  align-items: center;

  gap: 26px;
  padding: 26px 32px;
  margin-bottom: 6px;

  border-radius: 18px;

  overflow: hidden;

  /* Glow from the cover's colour (js/artwork-tint.js sets --tint),
     with a faint violet at the far corner: the brand's pink-to-violet
     pairing, kept behind neutral text. */
  background:
    radial-gradient(90% 140% at 0% 0%, var(--tint) 0%, transparent 65%),
    radial-gradient(80% 120% at 100% 100%, var(--violet-soft) 0%, transparent 60%),
    var(--surface);

  transition: --tint 500ms var(--ease-out);
}

.hero-info {
  min-width: 0;

  display: flex;
  flex-direction: column;

  gap: 10px;
}

/* A quiet eyebrow label, not a pill: pink is kept for actions. */
.hero-badge {
  align-self: flex-start;

  color: var(--text-muted);

  font-size: var(--fs-label);
  font-weight: var(--fw-label);
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
}

.hero-play {
  align-self: flex-start;

  display: inline-flex;
  align-items: center;

  gap: 8px;
  margin-top: 4px;
  padding: 11px 24px 11px 18px;

  border: none;
  border-radius: var(--radius-pill);

  background: var(--pink-fill);
  color: #fff;

  font-size: var(--fs-body-lg);
  font-weight: 700; /* bolder than body-lg's own 600 — a CTA earns the extra weight */

  cursor: pointer;

  transition:
    background 0.15s ease,
    transform 0.1s ease,
    opacity 0.15s ease;
}

.hero-play svg {
  width: var(--icon-xs);
  height: var(--icon-xs);

  flex-shrink: 0;
}

.hero-play:hover {
  background: var(--pink-fill-hover);
  transform: scale(1.03);
}

.hero-play:disabled {
  background: var(--surface-alt);
  color: var(--text-faint);
  cursor: not-allowed;
  opacity: 1;
  transform: none;
}

/* Custom-playlist-only hero extras — visibility label + the Add /
   Name & details buttons alongside Play. Hidden everywhere else via
   the `hidden` attribute (js/render.js's
   setHeroPlaylistControlsVisible()). */
.hero-visibility {
  color: var(--text-faint);

  font-size: var(--fs-body-sm);
  font-weight: var(--fw-body-sm);
}

.hero-actions {
  display: flex;
  align-items: center;

  gap: 10px;
  margin-top: 4px;
}

.hero-actions .hero-play {
  margin-top: 0;
}

.hero-secondary-btn {
  display: inline-flex;
  align-items: center;

  gap: 6px;
  padding: 10px 18px;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);

  background: transparent;
  color: var(--text-muted);

  font-size: var(--fs-body-sm);
  font-weight: var(--fw-body-sm);

  cursor: pointer;

  transition:
    background 0.15s ease,
    color 0.15s ease;
}

.hero-secondary-btn svg {
  width: var(--icon-xs);
  height: var(--icon-xs);
}

/* Same `display` vs. `[hidden]` precedence issue as .home-shelves and
   .playlist-edit-overlay above — see either for the full explanation. */
.hero-secondary-btn[hidden] {
  display: none;
}

.hero-secondary-btn:hover {
  background: var(--surface-alt);
  color: var(--text);
}

/* Hero Cover */

.cover {
  width: 122px;
  height: 122px;

  flex-shrink: 0;

  display: flex;
  align-items: center;
  justify-content: center;

  border-radius: 14px;

  background: linear-gradient(135deg, var(--pink-fill), var(--pink-dark));

  color: #fff;

  font-size: 30px;
  font-weight: 800;

  /* The same colour as the header glow (--tint), not always pink. */
  box-shadow: 0 20px 40px -12px var(--tint);
}

.hero h1 {
  margin-bottom: 6px;

  color: var(--text);

  font-size: var(--fs-display);
  font-weight: var(--fw-display);
  letter-spacing: var(--ls-display);
  line-height: var(--lh-display);
}

.hero p {
  color: var(--text-muted);

  font-size: var(--fs-body);
  line-height: 1.5;
}

/* =========================================================
   HOME SHELVES
   =========================================================
   Home's own content — Continue Listening, Because You Listened To,
   Pick a Vibe, Recently Played, Popular Right Now, Something
   Different, More Vibes — all built by js/home-view.js. Hidden
   everywhere else via the `hidden` attribute (setHomeShelvesVisible());
   .hero and .tracks-scroll are hidden in the same way while this is
   visible (js/render.js's setHeroVisible()/setTracksScrollVisible()) —
   Home replaced the shared hero+flat-list pattern entirely rather
   than adding shelves above it. */
/* flex:1/min-height:0/overflow-y:auto matches .tracks-scroll exactly
   (css/components.css's TRACK LIST section) — without its own scroll
   handling here, .left-col's own `overflow: hidden` (css/layout.css)
   silently clipped every shelf past the first viewport's height. A
   real bug caught only by a full-page screenshot tool that respects
   true scrollability rather than just a fixed capture height — see
   this file's own recurring `[hidden]`-vs-`display` bug class for the
   same "looks fine on paper" failure mode. */
.home-shelves {
  flex: 1;

  min-height: 0;

  display: flex;
  flex-direction: column;

  gap: 28px;
  padding: 4px 2px 24px;

  overflow-y: auto;
}

/* Same `display` vs. `[hidden]` precedence issue called out
   elsewhere in this file (.hero-secondary-btn, .playlist-edit-overlay)
   — an unconditional `display` declaration above always wins over the
   `hidden` attribute's UA default regardless of specificity. */
.home-shelves[hidden] {
  display: none;
}

.hero[hidden] {
  display: none;
}

.home-greeting,
.library-page-title {
  margin: 4px 0 -4px;

  color: var(--text);

  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

.home-shelf {
  display: flex;
  flex-direction: column;

  gap: 14px;
}

.home-shelf-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;

  gap: 12px;
}

.home-shelf-title,
.home-shelf-heading h2 {
  color: var(--text);

  font-size: var(--fs-title);
  font-weight: var(--fw-title);
  letter-spacing: var(--ls-title);
}

.home-shelf-heading p {
  margin-top: 2px;

  color: var(--text-muted);

  font-size: var(--fs-body-sm);
  font-weight: var(--fw-body-sm);
}

.home-shelf-see-all {
  flex-shrink: 0;

  border: none;
  background: transparent;

  color: var(--text-muted);

  font-size: var(--fs-body-sm);
  font-weight: var(--fw-body-sm);

  cursor: pointer;

  transition: color 0.15s ease;
}

.home-shelf-see-all:hover {
  color: var(--pink);
}

/* Horizontally-scrolling row of cards — every shelf except Continue
   Listening (a single wide card, never a row — see home-view.js's
   own comment on why that one is a separate builder). Scroll-snap is
   a light touch, not decoration: it keeps a mid-drag/mid-scroll stop
   from landing a card half-cut-off at the row's edge. */
.home-shelf-row {
  display: flex;

  gap: 14px;
  padding: 2px 2px 10px;

  overflow-x: auto;
  scroll-snap-type: x proximity;
}

.home-card {
  flex-shrink: 0;
  scroll-snap-align: start;

  width: 148px;

  display: flex;
  flex-direction: column;

  gap: 8px;
  padding: 10px;

  border: none;
  border-radius: 12px;

  background: var(--surface);
  color: var(--text);

  text-align: left;
  cursor: pointer;

  transition:
    background var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.home-card:hover {
  background: var(--surface-alt);
  transform: translateY(-2px);
}

.home-card-cover {
  width: 100%;
  aspect-ratio: 1;

  border-radius: 8px;
  overflow: hidden;
}

.home-card-cover img {
  width: 100%;
  height: 100%;

  object-fit: cover;
}

.home-card-cover-fallback,
.home-card-mood-icon {
  width: 100%;
  height: 100%;

  display: flex;
  align-items: center;
  justify-content: center;

  background: linear-gradient(135deg, var(--pink-fill), var(--pink-dark));
  color: #fff;

  font-size: 20px;
  font-weight: 800;
}

.home-card-mood-icon svg {
  width: 32px;
  height: 32px;
}

.home-card-title {
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-body-lg);

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.home-card-artist {
  margin-top: -4px;

  color: var(--text-muted);

  font-size: var(--fs-body-sm);
  font-weight: var(--fw-body-sm);

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Continue Listening — one wide card, not a shelf row. Reuses .hero's
   own corner-glow gradient recipe at a much smaller scale, so it
   reads as "the same brand of important" without being hero-sized —
   see the Home architecture brief's rejection of a giant banner as
   Home's default first element. */
.continue-card {
  width: 100%;

  display: flex;
  align-items: center;

  gap: 16px;
  padding: 14px 18px;

  border: none;
  border-radius: 14px;

  background: radial-gradient(120% 150% at 100% 0%, var(--pink-soft) 0%, transparent 55%), var(--surface);
  color: var(--text);

  text-align: left;
  cursor: pointer;

  transition: background 0.15s ease;
}

.continue-card:hover {
  background: radial-gradient(120% 150% at 100% 0%, var(--pink-light) 0%, transparent 55%), var(--surface);
}

.continue-card-cover {
  flex-shrink: 0;

  width: 56px;
  height: 56px;

  border-radius: 8px;
  overflow: hidden;
}

.continue-card-cover img {
  width: 100%;
  height: 100%;

  object-fit: cover;
}

.continue-card-cover-fallback {
  width: 100%;
  height: 100%;

  display: flex;
  align-items: center;
  justify-content: center;

  background: linear-gradient(135deg, var(--pink-fill), var(--pink-dark));
  color: #fff;

  font-size: 16px;
  font-weight: 800;
}

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

.continue-card-title {
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-body-lg);

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.continue-card-sub {
  margin-top: 2px;

  color: var(--text-muted);

  font-size: var(--fs-body-sm);

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.continue-card-play {
  flex-shrink: 0;

  width: var(--tap-lg);
  height: var(--tap-lg);

  display: flex;
  align-items: center;
  justify-content: center;

  border-radius: 50%;

  background: var(--pink-fill);
  color: #fff;
}

.continue-card-play svg {
  width: var(--icon-md);
  height: var(--icon-md);
}

/* =========================================================
   LIBRARY VIEW
   =========================================================
   "Your Library" — built by js/library-view.js. Same flex:1/
   overflow-y:auto/[hidden] treatment as .home-shelves above, and for
   the same reason: .left-col's own overflow:hidden otherwise clips
   everything past the first screenful. */
.library-view {
  flex: 1;

  min-height: 0;

  display: flex;
  flex-direction: column;

  gap: 20px;
  padding: 4px 2px 24px;

  overflow-y: auto;
}

.library-view[hidden] {
  display: none;
}

.library-tabs {
  display: flex;
  gap: 8px;
}

.library-tab {
  flex-shrink: 0;

  padding: 9px 20px;

  border: none;
  border-radius: var(--radius-pill);

  background: var(--surface-alt);
  color: var(--text-muted);

  font-size: var(--fs-body);
  font-weight: var(--fw-body-lg);

  cursor: pointer;

  transition:
    background 0.15s ease,
    color 0.15s ease;
}

.library-tab:hover {
  color: var(--text);
}

.library-tab.active {
  background: var(--pink-fill);
  color: #fff;
}

.library-tab-panel {
  display: flex;
  flex-direction: column;

  gap: 16px;
}

/* Recently Played's simpler header — just a label and an optional
   clear action, not the full search/sort/view toolbar Playlists
   needs (reusing .library-toolbar's own position:relative here would
   be inert — there's no menu to anchor — so this is a plain flex row
   instead of that class). */
.library-toolbar-static {
  display: flex;
  align-items: center;
  justify-content: space-between;

  gap: 12px;
  padding: 0 2px 8px;
}

.library-toolbar-static .library-toolbar-label {
  padding-left: 0;

  color: var(--text);

  font-size: var(--fs-title);
  font-weight: var(--fw-title);
  text-transform: none;
  letter-spacing: var(--ls-title);
}

.library-clear-btn {
  flex-shrink: 0;

  padding: 7px 16px;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);

  background: transparent;
  color: var(--text-muted);

  font-size: var(--fs-body-sm);
  font-weight: var(--fw-body-sm);

  cursor: pointer;

  transition:
    background 0.15s ease,
    color 0.15s ease;
}

.library-clear-btn:hover {
  background: var(--surface-alt);
  color: var(--text);
}

.library-playlist-list {
  padding: 4px 2px 10px;
}

/* =========================================================
   TRACK LIST
   ========================================================= */

/* The scrolling container — used to be .tracks itself, split out so
   the sticky mini-header (below) can be a normal-flow sibling of
   #tracksList inside the same scrollport instead of living inside an
   element that renderTracks()/showLoadingState()/showErrorState()
   fully overwrite via innerHTML on every render. */
.tracks-scroll {
  position: relative; /* anchors .sticky-mini-header */

  flex: 1;

  min-height: 0;

  overflow-y: auto;
}

.tracks {
  padding: 6px 2px;
}

/* Fades in once the track list has scrolled down a bit (see
   render.js's scroll listener) — a compact "you're still in this
   playlist" bar with its own play button, since the real .hero
   above doesn't scroll out of view on its own. */
.sticky-mini-header {
  position: sticky;
  top: 0;

  z-index: 5;

  display: flex;
  align-items: center;

  gap: 12px;
  height: 60px;
  padding: 10px 14px;

  /* Floats over the list instead of reserving its own 60px row: the
     negative margin cancels its height, so at the top of the page the
     songs sit right under the hero, and once scrolled the bar covers
     the rows passing beneath it. */
  margin: 0 2px -60px;

  border-radius: var(--radius-md);

  background: var(--surface-alt);
  box-shadow: var(--shadow-sm);

  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;

  transition:
    opacity 0.2s ease,
    transform 0.2s ease;
}

.sticky-mini-header.visible {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.sticky-mini-cover {
  width: 32px;
  height: 32px;

  flex-shrink: 0;

  display: flex;
  align-items: center;
  justify-content: center;

  border-radius: var(--radius-sm);

  background-size: cover;
  background-position: center;

  color: #fff;

  font-size: 11px;
  font-weight: 700;
}

#stickyMiniTitle {
  flex: 1;
  min-width: 0;

  color: var(--text);

  font-size: var(--fs-body-lg);
  font-weight: var(--fw-body-lg);

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.sticky-mini-play {
  flex-shrink: 0;

  width: var(--tap-md);
  height: var(--tap-md);

  display: inline-flex;
  align-items: center;
  justify-content: center;

  border: none;
  border-radius: 50%;

  background: var(--pink-fill);
  color: #fff;

  cursor: pointer;
}

.sticky-mini-play svg {
  width: var(--icon-sm);
  height: var(--icon-sm);
}

/* =========================================================
   LIST STATUS (loading / error / empty)
   ========================================================= */

.list-status {
  padding: 16px;

  color: var(--text-muted);

  font-size: var(--fs-body);
}

.list-status.error {
  color: var(--error);
}

/* =========================================================
   TRACK
   ========================================================= */

.track {
  min-height: 64px;

  display: flex;
  align-items: center;

  gap: 12px;
  padding: 8px 10px;

  border-radius: 8px;

  cursor: pointer;

  color: var(--text);

  transition: background 0.15s ease;
}

.track:hover {
  background: var(--surface-alt);
}

/* Track number */

.track .idx {
  width: 26px;

  flex-shrink: 0;

  display: flex;
  align-items: center;
  justify-content: center;

  text-align: center;

  color: var(--text-faint);

  font-size: var(--fs-body-sm);
  font-weight: 600;
}

/* Now-playing state */

.track.playing {
  background: var(--pink-soft);
}

.track.playing .idx {
  color: var(--pink);
}

.track.playing .title {
  color: var(--pink);
}

/* Mini equalizer shown on the currently playing track */

.eq-bars {
  display: flex;
  align-items: flex-end;
  justify-content: center;

  gap: 2.5px;

  width: 16px;
  height: 14px;
}

.eq-bars span {
  width: 3px;

  border-radius: 2px;

  background: var(--pink-fill);

  animation: eq-bounce 0.9s ease-in-out infinite;
}

.eq-bars span:nth-child(1) {
  animation-delay: -0.6s;
}

.eq-bars span:nth-child(2) {
  animation-delay: -0.3s;
}

.eq-bars span:nth-child(3) {
  animation-delay: 0s;
}

@keyframes eq-bounce {
  0%,
  100% {
    height: 4px;
  }

  50% {
    height: 14px;
  }
}

/* Track image */

.track img {
  width: 46px;
  height: 46px;

  flex-shrink: 0;

  object-fit: cover;

  border-radius: var(--radius-sm);

  background: var(--surface-alt);
}

/* Fallback cover for tracks with no artwork */

.track-cover-fallback {
  width: 46px;
  height: 46px;

  flex-shrink: 0;

  display: flex;
  align-items: center;
  justify-content: center;

  border-radius: var(--radius-sm);

  background: linear-gradient(135deg, var(--pink-fill), var(--pink-dark));

  color: #fff;

  font-size: 12px;
  font-weight: 700;
}

/* Track metadata */

.track .meta {
  flex: 1;

  min-width: 0;

  display: flex;
  flex-direction: column;

  gap: 3px;
}

.track .title {
  color: var(--text);

  font-size: var(--fs-body-lg);
  font-weight: var(--fw-body-lg);
  line-height: 1.25;

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.track .sub {
  color: var(--text-muted);

  font-size: var(--fs-body-sm);
  line-height: 1.25;

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Duration */

.track .time {
  width: 48px;

  flex-shrink: 0;

  text-align: right;

  color: var(--text-faint);

  font-size: var(--fs-body-sm);
  /* Tabular figures for clean columnar alignment down the duration
     column — same underlying rule as the player bar's timestamps,
     here for column-alignment rather than in-place-change jitter. */
  font-variant-numeric: tabular-nums;
}

/* =========================================================
   TRACK ACTIONS
   ========================================================= */

.track .actions {
  width: 80px; /* save (⊕/✓) and play */

  flex-shrink: 0;

  display: flex;
  align-items: center;
  justify-content: flex-end;

  gap: 2px;
}

.track .actions button {
  width: 36px;
  height: 36px;

  display: inline-flex;
  align-items: center;
  justify-content: center;

  border: none;
  border-radius: 50%;

  background: transparent;

  color: var(--text-faint);

  cursor: pointer;

  opacity: 0.9;

  transition:
    transform 0.1s ease,
    background 0.15s ease,
    color 0.15s ease,
    opacity 0.15s ease;
}

.track .actions button:hover {
  opacity: 1;

  background: var(--surface);

  color: var(--pink);

  transform: scale(1.08);
}

.track .actions .save-btn.is-liked {
  color: var(--pink);
  opacity: 1;
}

/* =========================================================
   QUEUE ITEM
   (shared by the toggleable queue panel — see player.css —
   and by nothing else now that the always-visible "Up Next"
   sidebar card has been removed)
   ========================================================= */

.queue-item {
  display: flex;
  align-items: center;

  gap: 11px;

  padding: 7px;
  margin-bottom: 2px;

  border-radius: 8px;

  color: var(--text);

  cursor: pointer;

  transition: background 0.15s ease;
}

.queue-item:hover {
  background: var(--surface-alt);
}

.queue-item img {
  width: 42px;
  height: 42px;

  flex-shrink: 0;

  object-fit: cover;

  border-radius: var(--radius-sm);
}

/* Cover art wrapper for the "Next up" rows — lets a play-icon
   overlay sit on top of the artwork on hover, Spotify's own
   queue-row pattern. Not used for the Now Playing row, which isn't
   clickable — a hover-play affordance there would promise an action
   that doesn't happen. */
.queue-cover {
  position: relative;

  flex-shrink: 0;

  width: 42px;
  height: 42px;

  border-radius: var(--radius-sm);

  overflow: hidden;
}

.queue-cover img,
.queue-cover .track-cover-fallback {
  width: 100%;
  height: 100%;
}

.queue-play-overlay {
  position: absolute;
  inset: 0;

  display: flex;
  align-items: center;
  justify-content: center;

  background: rgba(0, 0, 0, 0.55);
  color: #fff;

  opacity: 0;

  transition: opacity 0.15s ease;
}

.queue-item-reorderable:hover .queue-play-overlay,
.queue-item-reorderable:focus-within .queue-play-overlay {
  opacity: 1;
}

.queue-item .meta {
  min-width: 0;

  display: flex;
  flex-direction: column;

  gap: 3px;
}

.queue-item .title {
  color: var(--text);

  font-size: var(--fs-body);
  font-weight: 600;

  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.queue-item .sub {
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-body-sm);

  /* A track can have four+ credited artists ("Anand Bhaskar, Romy,
     Shreya Ghoshal, Ginny Diwan...") — without this it wraps to a
     second line and that one row grows taller than every other row
     in the list. One line + ellipsis keeps every row's height
     identical, which matters more here than showing every name. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.queue-item .meta {
  flex: 1;
}

/* =========================================================
   PRESS-AND-HOLD TO REORDER
   ========================================================= */

/* No visible handle/icon — press-and-hold-to-drag is treated as a
   default-expected interaction on any row, not something that needs
   its own affordance graphic. Cursor stays the normal pointer (the
   row's primary, immediate action is a click-to-play); it only
   switches to "grabbing" once a hold has actually armed a drag, as
   feedback for the gesture already in progress, not a hint to start
   one.

   touch-action: pan-y — not none. A real, severe bug: with `none`
   here, every row in a scrollable list blocked the browser's native
   touch-scroll entirely (touch-action governs the browser's own
   gesture handling regardless of what any JS pointer listener does),
   so "Next up" was effectively unscrollable by touch the moment it
   held more than one row — which the endless queue makes true almost
   always. pan-y explicitly allows vertical panning/scrolling by
   default; js/queue-panel.js's onRowPointerDown gives touch its own
   brief hold-before-arming rule specifically so a normal scroll swipe
   doesn't get misread as the start of a drag before the browser's own
   scroll has a chance to take over — see its TOUCH_HOLD_DURATION
   comment for the full reasoning. Mouse/pen are unaffected either
   way, since touch-action only governs touch gesture handling. */
.queue-item-reorderable {
  cursor: pointer;
  touch-action: pan-y;
}

/* The row actively being dragged: lifts off the list visually and
   tracks the pointer with zero transition lag (any easing here would
   make it visibly trail behind the cursor). */
.queue-item-reorderable.dragging {
  position: relative;
  z-index: 50;

  background: var(--surface-alt);

  box-shadow: var(--shadow-md);

  cursor: grabbing;

  transition: none;
}

/* Every other row, mid-drag: this is what makes room for the dragged
   item — a real transition, since these moves should read as a
   smooth reflow, not a snap. */
.queue-item-reorderable.drag-shifting {
  transition: transform 0.18s cubic-bezier(0.2, 0, 0.2, 1);
}

/* Fires once, the instant a hold arms into a drag — the "triggers"
   feedback confirming the gesture registered. A glow pulse rather
   than a transform: scale, deliberately — the row's own transform is
   already live-driven by pointermove's translateY tracking the very
   moment this fires (the user's finger/cursor may already be moving),
   and a CSS animation on the same property would fight that JS-driven
   value for its 0.28s duration. box-shadow has no such conflict. */
@media (prefers-reduced-motion: no-preference) {
  .queue-item-reorderable.drag-armed-pulse {
    animation: queue-drag-armed-pulse 0.28s ease-out;
  }
}

@keyframes queue-drag-armed-pulse {
  0% {
    box-shadow: var(--shadow-md), 0 0 0 0 var(--pink-soft);
  }

  50% {
    box-shadow: var(--shadow-md), 0 0 0 6px var(--pink-soft);
  }

  100% {
    box-shadow: var(--shadow-md), 0 0 0 0 transparent;
  }
}

/* =========================================================
   TOAST
   ========================================================= */

/* Non-blocking status message — see js/toast.js for why this exists
   instead of alert(). Centered above the player bar so it's never
   confused for part of the transport controls, and never blocks
   clicks on anything (pointer-events:none) even while visible. */
.toast {
  position: fixed;
  left: 50%;
  bottom: 116px;

  max-width: min(420px, calc(100vw - 48px));

  padding: 12px 20px;

  border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong);

  background: var(--surface-alt);
  color: var(--text);

  font-size: var(--fs-body-sm);
  font-weight: var(--fw-body-sm);
  text-align: center;

  box-shadow: var(--shadow-md);

  opacity: 0;
  pointer-events: none;

  transform: translateX(-50%) translateY(8px);

  transition:
    opacity 0.2s ease,
    transform 0.2s ease;

  z-index: 1400;
}

.toast.visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* =========================================================
   SAVE TO MENU (js/add-to-playlist.js)
   ========================================================= */

/* One shared, body-appended checklist. Positioned inline from the
   triggering button (opens upward from the player bar); a bottom sheet
   on phones. */
.save-to-menu {
  position: fixed;

  z-index: 1400;

  width: 280px;
  max-height: min(420px, calc(100vh - 32px));

  display: flex;
  flex-direction: column;

  padding: 8px;

  border-radius: 12px;
  border: 1px solid var(--border-strong);

  background: var(--surface-alt);

  box-shadow: var(--shadow-md);

  animation: save-to-in 0.16s ease-out;
}

@keyframes save-to-in {
  from {
    opacity: 0;
    transform: translateY(4px) scale(0.98);
  }
}

.save-to-header {
  padding: 8px 8px 10px;
}

.save-to-title {
  color: var(--text);

  font-size: var(--fs-body);
  font-weight: 700;
}

.save-to-song {
  margin-top: 2px;

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;

  color: var(--text-muted);

  font-size: var(--fs-body-sm);
}

.save-to-filter {
  margin: 0 4px 8px;
  padding: 8px 12px;

  border: 1px solid var(--border);
  border-radius: 8px;
  outline: none;

  background: var(--surface);
  color: var(--text);

  font: inherit;
  font-size: var(--fs-body-sm);
}

.save-to-filter:focus {
  border-color: var(--pink);
}

.save-to-list {
  min-height: 0;

  overflow-y: auto;

  border-top: 1px solid var(--border);
  padding-top: 4px;
}

.save-to-row {
  width: 100%;

  display: flex;
  align-items: center;

  gap: 12px;
  padding: 6px 8px;

  border: none;
  border-radius: 8px;
  outline: none;

  background: transparent;
  color: var(--text);

  font: inherit;
  text-align: left;

  cursor: pointer;

  transition: background 0.12s ease;
}

.save-to-row:hover,
.save-to-row:focus-visible {
  background: var(--surface);
}

.save-to-cover {
  width: 36px;
  height: 36px;

  flex-shrink: 0;

  display: grid;
  place-items: center;

  border-radius: var(--radius-sm);

  overflow: hidden;

  background: var(--surface);
  color: var(--text-muted);
}

.save-to-cover img,
.save-to-cover-initials {
  width: 100%;
  height: 100%;

  display: grid;
  place-items: center;

  object-fit: cover;

  color: #fff;

  font-size: 12px;
  font-weight: 700;
}

.save-to-cover svg {
  width: 16px;
  height: 16px;
}

.save-to-cover-liked {
  background: linear-gradient(135deg, var(--pink), var(--pink-fill));
  color: #fff;
}

.save-to-name {
  min-width: 0;
  flex: 1;

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;

  font-size: var(--fs-body);
  font-weight: 600;
}

.save-to-checkbox {
  width: 20px;
  height: 20px;

  flex-shrink: 0;

  display: grid;
  place-items: center;

  border: 2px solid var(--text-faint);
  border-radius: 50%;

  color: var(--bg);

  transition:
    background 0.12s ease,
    border-color 0.12s ease,
    transform 0.12s ease;
}

.save-to-checkbox.is-checked {
  border-color: var(--pink);

  background: var(--pink-fill);

  animation: save-to-check 0.2s ease-out;
}

@keyframes save-to-check {
  50% {
    transform: scale(1.18);
  }
}

.save-to-checkbox svg {
  width: 12px;
  height: 12px;
}

.save-to-create {
  margin-bottom: 4px;
}

.save-to-cover-create {
  background: var(--surface);
  color: var(--text);
}

.save-to-empty {
  padding: 12px 8px;

  color: var(--text-faint);

  font-size: var(--fs-body-sm);
}

/* Phones: a bottom sheet with a dimmed page behind it. */
.save-to-menu.is-sheet {
  top: auto;
  right: 0;
  bottom: 0;
  left: 0;

  width: auto;
  max-height: 70vh;

  padding: 12px 12px calc(12px + env(safe-area-inset-bottom));

  border-radius: 16px 16px 0 0;

  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.5);

  animation: save-to-sheet-in 0.22s ease-out;
}

@keyframes save-to-sheet-in {
  from {
    transform: translateY(100%);
  }
}

.save-to-menu.is-sheet .save-to-row {
  padding: 10px 8px;
}

@media (prefers-reduced-motion: reduce) {
  .save-to-menu,
  .save-to-menu.is-sheet,
  .save-to-checkbox.is-checked {
    animation: none;
  }
}

/* =========================================================
   PLAYLIST EDIT DETAILS MODAL (js/playlist-edit.js)
   ========================================================= */

.playlist-edit-overlay {
  position: fixed;
  inset: 0;

  z-index: 1500;

  display: flex;
  align-items: center;
  justify-content: center;

  padding: 20px;

  background: rgba(0, 0, 0, 0.6);
}

/* An author-origin `display` declaration (above) always beats the
   `hidden` attribute's UA-stylesheet default regardless of
   specificity — this explicit override is what actually hides it
   (see css/sidebar.css's identical note on .sort-menu-item-arrow). */
.playlist-edit-overlay[hidden] {
  display: none;
}

.playlist-edit-modal {
  width: min(420px, 100%);
  max-height: 90vh;

  overflow-y: auto;

  border-radius: 14px;
  border: 1px solid var(--border-strong);

  background: var(--surface);
  box-shadow: var(--shadow-md);
}

.playlist-edit-header {
  display: flex;
  align-items: center;
  justify-content: space-between;

  padding: 18px 20px 8px;
}

.playlist-edit-header h2 {
  color: var(--text);
  font-size: var(--fs-title);
  font-weight: var(--fw-title);
}

.playlist-edit-close {
  width: var(--tap-sm);
  height: var(--tap-sm);

  display: inline-flex;
  align-items: center;
  justify-content: center;

  border: none;
  border-radius: 50%;

  background: transparent;
  color: var(--text-muted);

  cursor: pointer;
}

.playlist-edit-close svg {
  width: var(--icon-xs);
  height: var(--icon-xs);
}

.playlist-edit-close:hover {
  background: var(--surface-alt);
  color: var(--text);
}

.playlist-edit-body {
  display: flex;
  flex-direction: column;

  gap: 18px;
  padding: 8px 20px 20px;
}

.playlist-edit-artwork {
  position: relative;

  align-self: center;

  width: 140px;
  height: 140px;

  border-radius: var(--radius-md);
  overflow: hidden;

  cursor: pointer;
}

.playlist-edit-artwork-preview,
.playlist-edit-artwork-preview img,
.playlist-edit-artwork-preview .playlist-cover-initials {
  width: 100%;
  height: 100%;
}

.playlist-edit-artwork-preview img {
  object-fit: cover;
}

.playlist-edit-artwork-preview .playlist-cover-initials {
  display: flex;
  align-items: center;
  justify-content: center;

  color: #fff;
  font-size: 36px;
  font-weight: 700;
}

.playlist-edit-artwork-overlay {
  position: absolute;
  inset: 0;

  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;

  gap: 6px;

  background: rgba(0, 0, 0, 0.55);
  color: #fff;

  font-size: var(--fs-body-sm);
  font-weight: 600;

  opacity: 0;

  transition: opacity 0.15s ease;
}

.playlist-edit-artwork-overlay svg {
  width: 22px;
  height: 22px;
}

.playlist-edit-artwork:hover .playlist-edit-artwork-overlay {
  opacity: 1;
}

.playlist-edit-artwork-input {
  position: absolute;
  inset: 0;

  width: 100%;
  height: 100%;

  opacity: 0;
  cursor: pointer;
}

.playlist-edit-fields {
  display: flex;
  flex-direction: column;

  gap: 14px;
}

.playlist-edit-field {
  display: flex;
  flex-direction: column;

  gap: 6px;
}

.playlist-edit-field span {
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-body-sm);
}

.playlist-edit-field input,
.playlist-edit-field textarea {
  padding: 10px 12px;

  border: 1px solid var(--border-strong);
  border-radius: 8px;

  background: var(--surface-alt);
  color: var(--text);

  font-size: var(--fs-body);
  font-family: inherit;

  resize: none;
}

.playlist-edit-field input:focus,
.playlist-edit-field textarea:focus {
  outline: none;
  border-color: var(--pink);
}

/* Takes no space until there's an error (it left a gap under Title). */
.playlist-edit-error:empty {
  display: none;
}

.playlist-edit-error {
  margin-top: -8px;

  color: var(--error);
  font-size: var(--fs-body-sm);
}

.playlist-edit-visibility {
  display: flex;
  align-items: center;
  justify-content: space-between;

  padding: 10px 12px;

  border-radius: 8px;

  background: var(--surface-alt);
}

.playlist-edit-visibility-label {
  color: var(--text);
  font-size: var(--fs-body-sm);
  font-weight: 600;
}

/* An on/off switch (role="switch"), not a "Make public" button. */
.playlist-edit-visibility-toggle {
  position: relative;

  width: 40px;
  height: 24px;

  flex-shrink: 0;

  border: none;
  border-radius: var(--radius-pill);

  background: var(--border-strong);

  cursor: pointer;

  transition: background 0.15s ease;
}

.playlist-edit-visibility-toggle::after {
  content: "";

  position: absolute;
  top: 3px;
  left: 3px;

  width: 18px;
  height: 18px;

  border-radius: 50%;

  background: var(--text);

  transition: transform 0.15s ease;
}

.playlist-edit-visibility-toggle[aria-checked="true"] {
  background: var(--pink-fill);
}

.playlist-edit-visibility-toggle[aria-checked="true"]::after {
  transform: translateX(16px);
}

.hero-cover-credit {
  display: block;

  margin-top: 4px;

  color: var(--text-faint);

  font-size: var(--fs-caption, 12px);
}

.hero-cover-credit[hidden] {
  display: none;
}

.hero-cover-credit a {
  color: inherit;

  text-decoration: underline;
  text-underline-offset: 2px;
}

.hero-cover-credit a:hover {
  color: var(--text);
}

/* Suggested covers (js/playlist-edit.js, js/cover-suggest.js): a
   row of six photos under the details, the reason they were picked,
   and who took the one on show. Selected: a pink ring. */
.playlist-edit-covers {
  display: flex;
  flex-direction: column;

  gap: 10px;
  padding: 0 20px 18px;
}

.playlist-edit-covers[hidden] {
  display: none;
}

.playlist-edit-covers-head,
.playlist-edit-covers-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;

  gap: 12px;
}

.playlist-edit-covers-reason,
.playlist-edit-covers-credit {
  min-width: 0;

  margin: 0;

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;

  color: var(--text-muted);

  font-size: var(--fs-body-sm);
}

.playlist-edit-covers-credit a {
  color: var(--text);

  text-decoration: underline;
  text-underline-offset: 2px;
}

.playlist-edit-covers-actions {
  flex-shrink: 0;

  display: flex;

  gap: 6px;
}

.playlist-edit-covers-upload,
.playlist-edit-covers-note-upload,
.playlist-edit-covers-more,
.playlist-edit-covers-colour {
  flex-shrink: 0;

  padding: 6px 12px;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);

  background: transparent;
  color: var(--text);

  font: inherit;
  font-size: var(--fs-body-sm);
  font-weight: 600;

  cursor: pointer;

  transition: background 150ms ease, transform 150ms cubic-bezier(0.2, 0, 0, 1);
}

.playlist-edit-covers-upload:hover,
.playlist-edit-covers-note-upload:hover,
.playlist-edit-covers-more:hover,
.playlist-edit-covers-colour:hover {
  background: var(--fill-hover);
}

.playlist-edit-covers-upload:active,
.playlist-edit-covers-note-upload:active,
.playlist-edit-covers-more:active,
.playlist-edit-covers-colour:active {
  transform: scale(0.96);
}

.playlist-edit-covers-strip {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));

  gap: 8px;
}

.cover-thumb {
  position: relative;

  aspect-ratio: 1;

  padding: 0;

  overflow: hidden;

  border: none;
  border-radius: 8px;

  cursor: pointer;

  transition: transform 160ms cubic-bezier(0.2, 0, 0, 1), box-shadow 160ms ease;
}

.cover-thumb img {
  width: 100%;
  height: 100%;

  display: block;

  object-fit: cover;
}

.cover-thumb:hover {
  transform: scale(1.05);
}

.cover-thumb.is-selected {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--pink);
}

.cover-thumb:focus-visible {
  outline: 2px solid var(--pink);
  outline-offset: 2px;
}

/* Waiting for photos: six soft placeholders in the photos' own spots,
   so nothing jumps when they arrive. */
.cover-thumb.is-skeleton {
  display: block;

  background: linear-gradient(100deg, var(--surface-alt) 30%, var(--fill-hover) 50%, var(--surface-alt) 70%);
  background-size: 300% 100%;

  cursor: default;

  animation: cover-shimmer 1.2s ease-in-out infinite;
}

.cover-thumb.is-skeleton:hover {
  transform: none;
}

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

  to {
    background-position: 0 0;
  }
}

/* Photos arriving fade in rather than pop. */
.playlist-edit-covers[data-state="ready"] .cover-thumb {
  animation: cover-in 220ms ease both;
}

@keyframes cover-in {
  from {
    opacity: 0;
  }
}

/* More only makes sense with photos on show. */
.playlist-edit-covers:not([data-state="ready"]) .playlist-edit-covers-more,
.playlist-edit-covers[data-state="error"] .playlist-edit-covers-strip:empty {
  display: none;
}

.playlist-edit-covers-note {
  display: flex;
  align-items: center;
  justify-content: space-between;

  gap: 12px;
  margin: 0;
  padding: 10px 12px;

  border-radius: 10px;

  background: var(--surface-alt);
  color: var(--text-muted);

  font-size: var(--fs-body-sm);
  line-height: 1.45;
}

/* The note's button: Try again for errors, Upload for "nothing
   matched the name". */
.playlist-edit-covers-note[data-kind="error"] .playlist-edit-covers-note-upload,
.playlist-edit-covers-note[data-kind="info"] .playlist-edit-covers-retry {
  display: none;
}

.playlist-edit-covers-colour[hidden],
.playlist-edit-covers-note[hidden] {
  display: none;
}

.playlist-edit-covers-retry {
  flex-shrink: 0;

  padding: 5px 12px;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);

  background: var(--surface);
  color: var(--text);

  font: inherit;
  font-weight: 600;

  cursor: pointer;
}

.playlist-edit-covers-retry:hover {
  background: var(--fill-hover);
}

@media (prefers-reduced-motion: reduce) {
  .cover-thumb,
  .cover-thumb.is-skeleton,
  .playlist-edit-covers[data-state="ready"] .cover-thumb {
    transition: none;
    animation: none;
  }
}

.playlist-edit-footer {
  display: flex;
  justify-content: flex-end;

  gap: 10px;
  padding: 0 20px 20px;
}

.playlist-edit-cancel,
.playlist-edit-save {
  padding: 10px 20px;

  border: none;
  border-radius: var(--radius-pill);

  font-size: var(--fs-body-sm);
  font-weight: 700;

  cursor: pointer;
}

.playlist-edit-cancel {
  border: 1px solid var(--border-strong);

  background: transparent;
  color: var(--text-muted);
}

.playlist-edit-cancel:hover {
  background: var(--surface-alt);
  color: var(--text);
}

.playlist-edit-save {
  background: var(--pink-fill);
  color: #fff;
}

.playlist-edit-save:hover {
  background: var(--pink-fill-hover);
}

/* =========================================================
   SONG PICKER DRAWER (js/song-picker-drawer.js) — the parts that
   differ from .queue-panel's own shared docking/header styles
   ========================================================= */

.song-picker-title {
  padding-left: 6px;

  color: var(--text);
  font-size: var(--fs-title);
  font-weight: var(--fw-title);
}

.song-picker-search {
  flex-shrink: 0;

  display: flex;
  align-items: center;

  gap: 8px;
  margin: 0 12px 8px;
  padding: 8px 12px;

  border-radius: var(--radius-pill);

  background: var(--surface-alt);
}

.song-picker-search svg {
  width: var(--icon-xs);
  height: var(--icon-xs);

  flex-shrink: 0;

  color: var(--text-faint);
}

.song-picker-search input {
  width: 100%;

  border: none;
  outline: none;

  background: transparent;
  color: var(--text);

  font-size: var(--fs-body-sm);
}

.song-picker-row {
  display: flex;
  align-items: center;

  gap: 10px;
  padding: 7px;

  border-radius: 8px;
}

.song-picker-row:hover {
  background: var(--surface-alt);
}

.song-picker-cover {
  width: 40px;
  height: 40px;

  flex-shrink: 0;
}

.song-picker-cover img,
.song-picker-cover .track-cover-fallback {
  width: 100%;
  height: 100%;

  border-radius: var(--radius-sm);
}

.song-picker-meta {
  flex: 1;
  min-width: 0;
}

.song-picker-row-title {
  color: var(--text);
  font-size: var(--fs-body);
  font-weight: 600;

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.song-picker-artist {
  color: var(--text-muted);
  font-size: var(--fs-body-sm);

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.song-picker-add {
  flex-shrink: 0;

  width: 32px;
  height: 32px;

  display: inline-flex;
  align-items: center;
  justify-content: center;

  border: none;
  border-radius: 50%;

  background: transparent;
  color: var(--text-muted);

  cursor: pointer;
}

.song-picker-add svg {
  width: var(--icon-xs);
  height: var(--icon-xs);
}

.song-picker-add:hover {
  background: var(--surface);
  color: var(--pink);
}

.song-picker-add.is-added {
  color: var(--now-playing);
  cursor: default;
}

/* =========================================================
   EMPTY LIST (js/render.js's renderEmptyState)
   ========================================================= */

.list-empty {
  display: flex;
  flex-direction: column;
  align-items: center;

  padding: 48px 24px;

  text-align: center;
}

.list-empty-icon {
  width: 56px;
  height: 56px;

  display: grid;
  place-items: center;

  margin-bottom: 16px;

  border-radius: 50%;

  background: var(--surface-alt);
  color: var(--text-faint);
}

.list-empty-icon svg {
  width: 24px;
  height: 24px;
}

.list-empty-title {
  margin: 0;

  color: var(--text);

  font-size: var(--fs-title);
  font-weight: var(--fw-title);
  line-height: var(--lh-title);
}

.list-empty-body {
  margin: 8px 0 0;

  color: var(--text-muted);

  font-size: var(--fs-body);
}

.list-empty-cta {
  margin-top: 24px;
  padding: 10px 24px;

  border: none;
  border-radius: var(--radius-pill);

  /* The page's one next step: the same pink fill as every primary
     button (it was white, a third button style). */
  background: var(--pink-fill);
  color: #fff;

  font: inherit;
  font-size: var(--fs-body);
  font-weight: 700;

  cursor: pointer;

  transition:
    transform 0.15s ease,
    background 0.15s ease;
}

.list-empty-cta:hover {
  background: var(--pink-fill-hover);
  transform: scale(1.04);
}

.hero-cover-icon svg {
  width: 40%;
  height: 40%;
}

.hero-cover-icon {
  width: 100%;
  height: 100%;

  display: grid;
  place-items: center;
}

/* =========================================================
   LOADING SKELETON (js/render.js's showLoadingState)
   ========================================================= */

.track-skeleton {
  cursor: default;
}

.track-skeleton:hover {
  background: transparent;
}

.skeleton {
  border-radius: var(--radius-sm);

  background: linear-gradient(
    90deg,
    var(--surface-alt) 0%,
    var(--skeleton-shine) 50%,
    var(--surface-alt) 100%
  );
  background-size: 200% 100%;

  animation: skeleton-shimmer 1.2s ease-in-out infinite;
}

.skeleton-cover {
  width: 46px;
  height: 46px;

  flex-shrink: 0;
}

.skeleton-line {
  width: 220px;
  max-width: 60%;
  height: 12px;
}

.skeleton-line-short {
  width: 140px;
  height: 10px;
  margin-top: 8px;
}

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

  to {
    background-position: -100% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .skeleton {
    animation: none;
  }
}

.visually-hidden {
  position: absolute;

  width: 1px;
  height: 1px;

  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* The full-width Library gets bigger tiles than the sidebar does. */
.library-playlist-list.view-grid {
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));

  gap: 20px 16px;
}

.library-playlist-list.view-compactGrid {
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));

  gap: 12px;
}

/* =========================================================
   QUIETER TRACK ROWS (devices with a real hover only)
   =========================================================
   Heart, + and ▶ on every row at once is a lot of repeated noise.
   With a mouse they show on the hovered (or keyboard-focused) row
   only, and the track number becomes the play control. A liked
   heart always stays visible, since it carries information. Touch
   screens keep every control visible: there's no hover to reveal
   them. */

.track .idx-play {
  display: none;
}

@media (hover: hover) {
  .track .idx-play {
    width: 28px;
    height: 28px;

    padding: 0;

    border: none;
    border-radius: 50%;

    background: transparent;
    color: var(--text);

    cursor: pointer;
  }

  .track .idx-play svg {
    width: 14px;
    height: 14px;
  }

  .track:hover .idx-num {
    display: none;
  }

  .track:hover .idx-play {
    display: grid;
    place-items: center;
  }

  .track.playing .idx-play {
    color: var(--pink);
  }

  .track .actions .play-btn {
    display: none;
  }

  .track .actions {
    width: 44px;
  }

  .track .actions .save-btn:not(.is-liked) {
    opacity: 0;

    transition: opacity 0.12s ease;
  }

  .track:hover .actions .save-btn,
  .track:focus-within .actions .save-btn,
  .track .actions .save-btn[aria-expanded="true"] {
    opacity: 1;
  }
}

/* Continue Listening: a compact card the size of its content, not a
   full-width bar with an oversized button at the far end. */
.continue-card {
  width: auto;
  max-width: 460px;

  padding: 10px 12px 10px 10px;
}

.continue-card-play {
  width: 40px;
  height: 40px;
}

.continue-card-play svg {
  width: 16px;
  height: 16px;
}

/* Slim header for search results (js/render.js's setHeroCompact). */
.hero.hero-compact {
  min-height: 0;

  gap: 18px;
  padding: 16px 24px;
}

.hero.hero-compact .cover {
  width: 72px;
  height: 72px;

  border-radius: var(--radius-md);
}

.hero.hero-compact h1 {
  font-size: 22px;
}

.hero.hero-compact .hero-actions {
  margin-top: 8px;
}

.hero.hero-compact .hero-play {
  padding: 8px 18px;
}

/* Library's playlist filter is a real text field here (the sidebar's
   version is a compact expand-on-click input; same class, see
   css/sidebar.css). It used to look like a plain label. */
.library-view .library-search-input.expanded {
  flex: 0 1 280px;

  padding: 8px 14px 8px 36px;

  border: 1px solid var(--border);
  border-radius: var(--radius-pill);

  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m21 21-4.34-4.34'/%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3C/svg%3E") 12px center / 14px no-repeat,
    var(--surface-alt);

  font-size: var(--fs-body-sm);

  transition: border-color 0.15s ease;
}

.library-view .library-search-input.expanded:focus {
  border-color: var(--pink);
}

/* The title already says "Results for ...", so the badge is redundant. */
.hero.hero-compact .hero-badge {
  display: none;
}

.hero.hero-compact #heroDesc {
  margin-top: 2px;
}

/* Library's "New playlist" (js/library-view.js) */
.library-create-btn {
  display: inline-flex;
  align-items: center;

  gap: 6px;
  padding: 8px 14px;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);

  background: transparent;
  color: var(--text);

  font: inherit;
  font-size: var(--fs-body-sm);
  font-weight: 700;

  cursor: pointer;

  transition: background var(--dur-fast) ease;
}

.library-create-btn:hover {
  background: var(--surface-alt);
}

.library-create-btn svg {
  width: var(--icon-xs);
  height: var(--icon-xs);
}

/* One height for the whole Library toolbar row (search, New
   playlist, sort), and no wrapping "New / playlist" on phones. */
.library-view .library-search-input.expanded,
.library-view .library-create-btn,
.library-view .library-sort-btn {
  height: 36px;

  white-space: nowrap;
}

.library-view .library-create-btn,
.library-view .library-sort-btn {
  flex-shrink: 0;

  padding-top: 0;
  padding-bottom: 0;
}

@media (max-width: 480px) {
  .library-view .library-search-input.expanded {
    flex-basis: 0;
    flex-grow: 1;

    min-width: 0;
  }
}

.library-empty {
  padding-top: 32px;
}

/* =========================================================
   AI PLAYLIST (js/ai-playlist.js)
   ========================================================= */

.ai-badge {
  width: 36px;
  height: 36px;

  flex-shrink: 0;

  display: grid;
  place-items: center;

  border-radius: var(--radius-md);

  background: var(--pink-fill);
  color: #fff;
}

.ai-badge svg {
  width: 18px;
  height: 18px;
}

/* Dialog */
.ai-overlay {
  position: fixed;
  inset: 0;

  z-index: 1450;

  display: grid;
  place-items: center;

  padding: var(--space-4);

  background: rgba(0, 0, 0, 0.6);
}

body.ai-open {
  overflow: hidden;
}

.ai-dialog {
  width: min(600px, 100%);
  max-height: min(760px, calc(100dvh - 32px));

  display: flex;
  flex-direction: column;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);

  background: var(--surface-alt);

  box-shadow: var(--shadow-md);

  overflow: hidden;

  animation: save-to-in var(--dur-base) var(--ease-out);
}

.ai-dialog-head {
  display: flex;
  align-items: center;

  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);

  border-bottom: 1px solid var(--border);
}

.ai-dialog-head h2 {
  flex: 1;

  margin: 0;

  font-size: var(--fs-title);
  font-weight: 800;
}

.ai-close {
  width: var(--tap-sm);
  height: var(--tap-sm);

  display: grid;
  place-items: center;

  border: none;
  border-radius: 50%;

  background: transparent;
  color: var(--text-muted);

  cursor: pointer;
}

.ai-close:hover {
  background: var(--surface);
  color: var(--text);
}

.ai-close svg {
  width: 18px;
  height: 18px;
}

.ai-body {
  min-height: 0;

  overflow-y: auto;

  padding: var(--space-5);
}

.ai-input-row {
  display: flex;
  align-items: flex-end;

  gap: var(--space-2);
  padding: 6px 6px 6px var(--space-4);

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);

  background: var(--surface);

  transition: border-color var(--dur-fast) ease;
}

.ai-input-row:focus-within {
  border-color: var(--pink);
}

.ai-input {
  flex: 1;

  min-width: 0;
  padding: 8px 0;

  border: none;
  outline: none;

  background: transparent;
  color: var(--text);

  font: inherit;
  font-size: var(--fs-body-lg);

  resize: none;
}

.ai-input::placeholder {
  color: var(--text-faint);
}

.ai-send {
  width: 40px;
  height: 40px;

  flex-shrink: 0;

  display: grid;
  place-items: center;

  border: none;
  border-radius: 50%;

  background: var(--pink-fill);
  color: #fff;

  cursor: pointer;
}

.ai-send:hover {
  background: var(--pink-fill-hover);
}

.ai-send svg {
  width: 18px;
  height: 18px;
}

.ai-hint {
  margin: var(--space-2) 0 0;

  color: var(--text-faint);

  font-size: var(--fs-body-sm);
}

.ai-section-label {
  margin: var(--space-5) 0 var(--space-2);

  color: var(--text-muted);

  font-size: var(--fs-label);
  font-weight: var(--fw-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.ai-chips {
  display: flex;
  flex-wrap: wrap;

  gap: var(--space-2);
}

.ai-refine .ai-chips {
  margin-top: var(--space-2);
}

.ai-chip {
  padding: 8px 14px;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);

  background: transparent;
  color: var(--text);

  font: inherit;
  font-size: var(--fs-body-sm);

  cursor: pointer;

  transition:
    background var(--dur-fast) ease,
    border-color var(--dur-fast) ease;
}

.ai-chip:hover {
  border-color: var(--pink);

  background: var(--pink-soft);
}

.ai-chip-small {
  padding: 6px 12px;
}

.ai-recent-list {
  margin: 0;
  padding: 0;

  list-style: none;
}

.ai-recent-item {
  display: flex;
  align-items: center;

  border-radius: var(--radius-md);
}

.ai-recent-item:hover {
  background: var(--surface);
}

.ai-recent-open {
  flex: 1;

  min-width: 0;

  display: flex;
  flex-direction: column;

  gap: 2px;
  padding: 8px var(--space-3);

  border: none;

  background: transparent;
  color: var(--text);

  font: inherit;
  text-align: left;

  cursor: pointer;
}

.ai-recent-title {
  font-size: var(--fs-body);
  font-weight: 600;
}

.ai-recent-prompt {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;

  color: var(--text-muted);

  font-size: var(--fs-body-sm);
}

.ai-recent-forget {
  width: var(--tap-sm);
  height: var(--tap-sm);

  flex-shrink: 0;

  display: grid;
  place-items: center;

  border: none;
  border-radius: 50%;

  background: transparent;
  color: var(--text-faint);

  cursor: pointer;
}

.ai-recent-forget:hover {
  color: var(--text);
}

.ai-recent-forget svg {
  width: 14px;
  height: 14px;
}

/* Loading */
.ai-loading {
  display: flex;
  flex-direction: column;
  align-items: center;

  padding: var(--space-7) var(--space-4);

  text-align: center;
}

.ai-loading-orb {
  width: 64px;
  height: 64px;

  display: grid;
  place-items: center;

  margin-bottom: var(--space-4);

  border-radius: 50%;

  background: radial-gradient(circle, var(--pink-fill), var(--pink-dark));
  color: #fff;

  animation: ai-pulse 1.4s ease-in-out infinite;
}

.ai-loading-orb svg {
  width: 28px;
  height: 28px;
}

@keyframes ai-pulse {
  50% {
    transform: scale(1.08);
    box-shadow: 0 0 0 12px rgba(214, 20, 95, 0.15);
  }
}

.ai-loading-title {
  margin: 0;

  font-size: var(--fs-body-lg);
  font-weight: 700;
}

.ai-loading-sub,
.ai-error-sub {
  margin: var(--space-1) 0 0;

  color: var(--text-muted);

  font-size: var(--fs-body-sm);
}

/* Result */
.ai-result-title {
  margin: 0;

  font-size: 22px;
  font-weight: 800;
}

.ai-result-desc {
  margin: var(--space-1) 0 0;

  color: var(--text-muted);
}

.ai-result-meta {
  margin: var(--space-2) 0 0;

  color: var(--text-faint);

  font-size: var(--fs-body-sm);
}

.ai-songs {
  margin: var(--space-4) 0;
  padding: 0;

  list-style: none;
}

.ai-song {
  width: 100%;

  display: flex;
  align-items: center;

  gap: var(--space-3);
  padding: 6px var(--space-2);

  border: none;
  border-radius: var(--radius-md);

  background: transparent;
  color: var(--text);

  font: inherit;
  text-align: left;

  cursor: pointer;
}

.ai-song:hover {
  background: var(--surface);
}

.ai-song img,
.ai-song-cover {
  width: 40px;
  height: 40px;

  flex-shrink: 0;

  border-radius: var(--radius-sm);

  background: var(--surface);

  object-fit: cover;
}

.ai-song-text {
  min-width: 0;

  display: flex;
  flex-direction: column;
}

.ai-song-title,
.ai-song-artist {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.ai-song-title {
  font-size: var(--fs-body);
  font-weight: 600;
}

.ai-song-artist {
  color: var(--text-muted);

  font-size: var(--fs-body-sm);
}

.ai-refine {
  padding-top: var(--space-4);

  border-top: 1px solid var(--border);
}

.ai-actions {
  display: flex;
  justify-content: flex-end;

  gap: var(--space-2);
  margin-top: var(--space-5);
}

.ai-primary,
.ai-secondary {
  padding: 10px 20px;

  border: none;
  border-radius: var(--radius-pill);

  font: inherit;
  font-size: var(--fs-body);
  font-weight: 700;

  cursor: pointer;
}

.ai-primary {
  background: var(--pink-fill);
  color: #fff;
}

.ai-primary:hover {
  background: var(--pink-fill-hover);
}

.ai-primary:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.ai-secondary {
  background: transparent;
  color: var(--text-muted);
}

.ai-secondary:hover {
  color: var(--text);
}

.ai-error {
  padding: var(--space-6) var(--space-2);

  text-align: center;
}

.ai-error-title {
  margin: 0;

  font-size: var(--fs-body-lg);
  font-weight: 700;
}

.ai-error .ai-secondary {
  margin-top: var(--space-4);
}

/* Phones: a full-height sheet */
@media (max-width: 600px) {
  .ai-overlay {
    place-items: end stretch;

    padding: 0;
  }

  .ai-dialog {
    width: 100%;
    max-height: 92dvh;

    border-radius: 16px 16px 0 0;
  }

  .ai-body {
    padding: var(--space-4) var(--space-4) calc(var(--space-4) + env(safe-area-inset-bottom));
  }
}

@media (prefers-reduced-motion: reduce) {
  .ai-loading-orb {
    animation: none;
  }
}

/* "Save to Library" stays in view while the song list scrolls. */
.ai-result .ai-actions {
  position: sticky;
  bottom: calc(-1 * var(--space-5));

  margin: var(--space-4) calc(-1 * var(--space-5)) calc(-1 * var(--space-5));
  padding: var(--space-3) var(--space-5);

  border-top: 1px solid var(--border);

  background: var(--surface-alt);
}

@media (max-width: 600px) {
  .ai-result .ai-actions {
    bottom: calc(-1 * var(--space-4) - env(safe-area-inset-bottom));

    margin: var(--space-4) calc(-1 * var(--space-4)) calc(-1 * var(--space-4) - env(safe-area-inset-bottom));
    padding: var(--space-3) var(--space-4) calc(var(--space-3) + env(safe-area-inset-bottom));
  }
}

/* =========================================================
   MOOD GRID (Home's "Pick a Vibe", Search's "Browse")
   =========================================================
   Compact tiles in a grid that fills the width, instead of a row of
   fixed 148px cards that left half of a wide screen empty. */
.mood-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));

  gap: 10px;
}

.mood-grid .home-card {
  width: auto;
  height: 64px;

  flex-direction: row;
  align-items: center;

  gap: 12px;
  padding: 0 12px 0 0;

  overflow: hidden;
}

.mood-grid .home-card-cover {
  width: 64px;
  height: 64px;

  flex-shrink: 0;

  border-radius: 0;
}

.mood-grid .home-card-mood-icon svg {
  width: var(--icon-md);
  height: var(--icon-md);
}

@media (max-width: 480px) {
  .mood-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));

    gap: 8px;
  }

  .mood-grid .home-card {
    height: 56px;

    gap: 10px;
  }

  .mood-grid .home-card-cover {
    width: 48px;
    height: 56px;
  }

  .mood-grid .home-card-title {
    font-size: var(--fs-body);
  }
}

/* Title on the left, "Show all" on the right, centred together. */
.home-shelf-header {
  align-items: center;
}

/* =========================================================
   SEARCH PAGE (js/search-home.js)
   ========================================================= */
.search-home {
  flex: 1;

  min-height: 0;

  display: flex;
  flex-direction: column;

  gap: 28px;
  padding: 4px 2px 24px;

  overflow-y: auto;
}

.search-home[hidden] {
  display: none;
}

.search-home-title {
  margin: 4px 0 -4px;

  color: var(--text);

  font-size: var(--fs-display);
  font-weight: var(--fw-display);
  letter-spacing: var(--ls-display);
  line-height: var(--lh-display);
}

.search-home-chips {
  display: flex;
  flex-wrap: wrap;

  gap: 8px;
}

.search-chip {
  max-width: 100%;

  padding: 8px 14px;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);

  background: transparent;
  color: var(--text);

  font-size: var(--fs-body-sm);
  font-weight: var(--fw-body-sm);

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;

  cursor: pointer;

  transition: background 0.15s ease;
}

.search-chip:hover {
  background: var(--surface-alt);
}

/* =========================================================
   SEARCH: voice, suggestions, results (js/search*.js)
   ========================================================= */

.voice-search {
  flex-shrink: 0;

  width: var(--tap-sm);
  height: var(--tap-sm);

  display: grid;
  place-items: center;

  border: none;
  border-radius: 50%;

  background: transparent;
  color: var(--text-muted);

  cursor: pointer;

  transition: color var(--dur-fast) ease, background var(--dur-fast) ease;
}

.voice-search svg {
  width: 16px;
  height: 16px;
}

.voice-search:hover {
  color: var(--text);
}

.voice-search.is-listening {
  background: var(--pink-fill);
  color: #fff;

  animation: voice-pulse 1.2s ease-in-out infinite;
}

@keyframes voice-pulse {
  50% {
    box-shadow: 0 0 0 8px rgba(214, 20, 95, 0.18);
  }
}

/* Suggestions dropdown */
.search-suggest {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;

  z-index: 1300;

  max-height: min(440px, 70vh);

  overflow-y: auto;

  padding: 6px;

  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);

  background: var(--surface-alt);

  box-shadow: var(--shadow-md);

  animation: save-to-in var(--dur-fast) var(--ease-out);
}

.suggest-row {
  display: flex;
  align-items: center;

  gap: 12px;
  padding: 6px 10px;

  border-radius: var(--radius-md);

  cursor: pointer;
}

.suggest-row.is-active {
  background: var(--surface);
}

.suggest-art {
  width: 40px;
  height: 40px;

  flex-shrink: 0;

  border-radius: var(--radius-sm);

  object-fit: cover;
}

.suggest-art.is-round {
  border-radius: 50%;
}

.suggest-art-icon {
  display: grid;
  place-items: center;

  background: var(--surface);
  color: var(--text-muted);

  font-weight: 700;
}

.suggest-art-icon svg {
  width: 16px;
  height: 16px;
}

.suggest-text {
  min-width: 0;

  display: flex;
  flex-direction: column;
}

.suggest-title,
.suggest-sub {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.suggest-title {
  color: var(--text);

  font-size: var(--fs-body);
  font-weight: 600;
}

.suggest-sub {
  color: var(--text-muted);

  font-size: var(--fs-body-sm);
}

/* Results page */
.search-home.sr-enter > * {
  animation: view-enter var(--dur-slow) var(--ease-out);
}

/* A new search over old results: dim them while loading, instead of
   blanking the page. */
.search-home.is-refreshing .sr-body {
  opacity: 0.45;
  pointer-events: none;

  transition: opacity var(--dur-fast) ease;
}

.sr-body {
  display: flex;
  flex-direction: column;

  gap: var(--space-6);

  transition: opacity var(--dur-base) ease;
}

.sr-chips {
  position: sticky;
  top: 0;

  z-index: 2;

  display: flex;
  flex-wrap: wrap;

  gap: var(--space-2);
  padding: var(--space-1) 0 var(--space-4);

  background: var(--bg);
}

.sr-chip {
  padding: 7px 16px;

  border: none;
  border-radius: var(--radius-pill);

  background: var(--surface-alt);
  color: var(--text);

  font: inherit;
  font-size: var(--fs-body-sm);
  font-weight: 600;

  cursor: pointer;

  transition: background var(--dur-fast) ease, color var(--dur-fast) ease;
}

.sr-chip:hover {
  background: var(--surface);
}

.sr-chip.is-active {
  background: var(--text);
  color: var(--bg);
}

.sr-heading {
  margin: 0 0 var(--space-3);

  color: var(--text);

  font-size: var(--fs-title);
  font-weight: 800;
}

.sr-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}

.sr-see-all {
  border: none;

  background: none;
  color: var(--text-muted);

  font: inherit;
  font-size: var(--fs-body-sm);
  font-weight: 700;

  cursor: pointer;
}

.sr-see-all:hover {
  color: var(--text);
  text-decoration: underline;
}

.sr-corrected {
  margin: 0;

  color: var(--text-muted);

  font-size: var(--fs-body);
}

.sr-corrected strong {
  color: var(--text);
}

/* Top result + songs side by side */
.sr-top-grid {
  display: grid;
  grid-template-columns: minmax(260px, 2fr) 3fr;

  gap: var(--space-5);
}

.sr-top-card {
  position: relative;

  height: calc(100% - 36px);
  min-height: 200px;

  display: flex;
  flex-direction: column;
  justify-content: flex-end;

  gap: var(--space-2);
  padding: var(--space-5);

  border-radius: var(--radius-lg);

  background: var(--surface-alt);

  cursor: pointer;

  transition: background var(--dur-fast) ease;
}

.sr-top-card:hover,
.sr-top-card:has(.sr-card-open:focus-visible) {
  background: var(--surface);
}

.sr-top-art img,
.sr-top-art .sr-art-fallback {
  width: 96px;
  height: 96px;

  border-radius: var(--radius-sm);

  box-shadow: var(--shadow-md);

  object-fit: cover;
}

.sr-card-artist .sr-top-art img,
.sr-card-artist .sr-top-art .sr-art-fallback {
  border-radius: 50%;
}

.sr-top-title {
  margin-top: var(--space-3);

  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;

  color: var(--text);

  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
}

.sr-top-sub {
  color: var(--text-muted);

  font-size: var(--fs-body-sm);
}

.sr-kind {
  display: inline-block;

  margin-right: var(--space-2);
  padding: 3px 10px;

  border-radius: var(--radius-pill);

  background: var(--bg);
  color: var(--text);

  font-weight: 700;
}

.sr-top-play,
.sr-card-play {
  position: absolute;

  display: grid;
  place-items: center;

  border: none;
  border-radius: 50%;

  background: var(--pink-fill);
  color: #fff;

  box-shadow: var(--shadow-md);

  cursor: pointer;

  opacity: 0;
  transform: translateY(6px);

  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out), background var(--dur-fast) ease;
}

.sr-top-play {
  right: var(--space-5);
  bottom: var(--space-5);

  width: 52px;
  height: 52px;
}

.sr-top-play svg,
.sr-card-play svg {
  width: 20px;
  height: 20px;
}

.sr-top-card:hover .sr-top-play,
.sr-top-card:focus-within .sr-top-play,
.sr-card:hover .sr-card-play,
.sr-card:focus-within .sr-card-play {
  opacity: 1;
  transform: none;
}

.sr-top-play:hover,
.sr-card-play:hover {
  background: var(--pink-fill-hover);
}

/* Song rows */
.sr-song {
  display: flex;
  align-items: center;

  gap: var(--space-3);
  padding: 6px var(--space-2);

  border-radius: var(--radius-md);

  cursor: pointer;

  transition: background var(--dur-fast) ease;
}

.sr-song:hover,
.sr-song:has(.sr-song-main:focus-visible) {
  background: var(--surface-alt);
}

/* The row's play target: a real button beside the save button, not a
   role="button" row wrapping it (WCAG 4.1.2, no nested controls). */
.sr-song-main {
  flex: 1;

  min-width: 0;

  display: flex;
  align-items: center;

  gap: var(--space-3);
  padding: 0;

  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;

  cursor: pointer;
}

.sr-song.is-playing .sr-song-title {
  color: var(--pink);
}

.sr-song-art {
  position: relative;

  width: 44px;
  height: 44px;

  flex-shrink: 0;

  overflow: hidden;

  border-radius: var(--radius-sm);
}

.sr-song-art img,
.sr-song-art .sr-art-fallback {
  width: 100%;
  height: 100%;

  object-fit: cover;
}

.sr-song-play {
  position: absolute;
  inset: 0;

  display: grid;
  place-items: center;

  background: rgba(0, 0, 0, 0.5);
  color: #fff;

  opacity: 0;

  transition: opacity var(--dur-fast) ease;
}

.sr-song-play svg {
  width: 16px;
  height: 16px;
}

.sr-song:hover .sr-song-play,
.sr-song-main:focus-visible .sr-song-play {
  opacity: 1;
}

.sr-song-text {
  flex: 1;

  min-width: 0;

  display: flex;
  flex-direction: column;

  gap: 2px;
}

.sr-song-title,
.sr-song-artist {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.sr-song-title {
  color: var(--text);

  font-size: var(--fs-body-lg);
  font-weight: 600;
}

.sr-song-artist {
  color: var(--text-muted);

  font-size: var(--fs-body-sm);
}

.sr-song-time {
  color: var(--text-faint);

  font-size: var(--fs-body-sm);
  font-variant-numeric: tabular-nums;
}

.sr-save {
  width: var(--tap-sm);
  height: var(--tap-sm);

  border: none;
  border-radius: 50%;

  background: transparent;
  color: var(--text-muted);

  cursor: pointer;
}

.sr-save.is-liked {
  color: var(--pink);
}

.sr-save svg {
  width: 18px;
  height: 18px;
}

.sr-skeleton {
  cursor: default;
}

.sr-skeleton .skeleton-line {
  display: block;
}

.sr-top-skeleton {
  height: 220px;

  border-radius: var(--radius-lg);
}

/* Artist / album / playlist cards */
.sr-row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(150px, 180px);

  gap: var(--space-3);

  overflow-x: auto;

  padding-bottom: var(--space-1);
}

/* Desktop: one row that fits the width, extra cards hidden
   (js/search-results.js, fitRow); See all opens the rest. */
@media (min-width: 768px) {
  .sr-row {
    grid-auto-flow: row;
    grid-template-columns: repeat(var(--sr-columns, 4), minmax(0, 1fr));

    overflow-x: visible;
  }

  .sr-row > [hidden] {
    display: none;
  }
}

.sr-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));

  gap: var(--space-4) var(--space-3);
}

.sr-card {
  position: relative;

  min-width: 0;

  display: flex;
  flex-direction: column;

  gap: 4px;
  padding: var(--space-3);

  border-radius: var(--radius-md);

  cursor: pointer;

  transition: background var(--dur-fast) ease;
}

.sr-card:hover,
.sr-card:has(.sr-card-open:focus-visible) {
  background: var(--surface-alt);
}

/* What opens a card: a real button laid over the whole card, beside
   its play button rather than wrapping it (WCAG 4.1.2, no nested
   controls; same pattern as the Home tiles). */
.sr-card-open {
  position: absolute;
  inset: 0;

  z-index: 1;

  padding: 0;

  border: 0;
  border-radius: inherit;
  background: none;

  cursor: pointer;
}

.sr-top-play,
.sr-card-play {
  z-index: 2;
}

.sr-card-art {
  position: relative;

  margin-bottom: var(--space-2);
}

.sr-card-art img,
.sr-card-art .sr-art-fallback {
  width: 100%;
  aspect-ratio: 1;

  border-radius: var(--radius-md);

  box-shadow: var(--shadow-sm);

  object-fit: cover;
}

.sr-card-artist .sr-card-art img,
.sr-card-artist .sr-card-art .sr-art-fallback {
  border-radius: 50%;
}

.sr-card-play {
  right: 8px;
  bottom: 8px;

  width: 44px;
  height: 44px;
}

.sr-card-title,
.sr-card-sub {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.sr-card-title {
  color: var(--text);

  font-size: var(--fs-body);
  font-weight: 700;
}

.sr-card-sub {
  color: var(--text-muted);

  font-size: var(--fs-body-sm);
}

.sr-art-fallback {
  display: grid;
  place-items: center;

  background: linear-gradient(135deg, var(--pink-fill), var(--pink-dark));
  color: #fff;

  font-weight: 800;
}

/* In your library */
.sr-library {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));

  gap: var(--space-2);
}

.sr-library-item {
  display: flex;
  align-items: center;

  gap: var(--space-3);
  padding: var(--space-2);

  border: none;
  border-radius: var(--radius-md);

  background: var(--surface-alt);
  color: var(--text);

  font: inherit;
  text-align: left;

  cursor: pointer;
}

.sr-library-item:hover {
  background: var(--surface);
}

.sr-library-item > span:last-child {
  min-width: 0;

  display: flex;
  flex-direction: column;
}

.sr-library-art {
  width: 48px;
  height: 48px;

  flex-shrink: 0;

  display: grid;
  place-items: center;

  border-radius: var(--radius-sm);

  background: var(--surface);

  font-weight: 800;
}

.sr-library-liked {
  background: linear-gradient(135deg, var(--pink), var(--pink-fill));
  color: #fff;
}

.sr-library-liked svg {
  width: 20px;
  height: 20px;
}

.sr-library-title {
  font-weight: 700;
}

.sr-library-sub {
  color: var(--text-muted);

  font-size: var(--fs-body-sm);
}

/* No results / errors */
.sr-empty {
  display: flex;
  flex-direction: column;
  align-items: center;

  gap: var(--space-2);
  padding: var(--space-6) var(--space-4) var(--space-2);

  text-align: center;
}

.sr-empty-title {
  margin: 0;

  color: var(--text);

  font-size: 22px;
  font-weight: 800;
}

.sr-empty-body {
  margin: 0;

  color: var(--text-muted);
}

.sr-empty-ai,
.sr-retry {
  margin-top: var(--space-3);
  padding: 10px 20px;

  border: none;
  border-radius: var(--radius-pill);

  background: var(--pink-fill);
  color: #fff;

  font: inherit;
  font-weight: 700;

  cursor: pointer;
}

.sr-retry {
  background: var(--text);
  color: var(--bg);
}

/* Recent searches */
.recent-list {
  margin: 0;
  padding: 0;

  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));

  gap: var(--space-1) var(--space-3);

  list-style: none;
}

.recent-item {
  display: flex;
  align-items: center;

  border-radius: var(--radius-md);

  transition: background var(--dur-fast) ease;
}

.recent-item:hover {
  background: var(--surface-alt);
}

.recent-open {
  flex: 1;

  min-width: 0;

  display: flex;
  align-items: center;

  gap: var(--space-3);
  padding: 6px var(--space-2);

  border: none;

  background: none;
  color: var(--text);

  font: inherit;
  text-align: left;

  cursor: pointer;
}

.recent-art {
  width: 44px;
  height: 44px;

  flex-shrink: 0;

  display: grid;
  place-items: center;

  overflow: hidden;

  border-radius: var(--radius-sm);

  background: var(--surface-alt);
  color: var(--text-muted);

  font-weight: 800;
}

.recent-item.is-artist .recent-art {
  border-radius: 50%;
}

.recent-art img {
  width: 100%;
  height: 100%;

  object-fit: cover;
}

.recent-art svg {
  width: 18px;
  height: 18px;
}

.recent-text {
  min-width: 0;

  display: flex;
  flex-direction: column;
}

.recent-title,
.recent-sub {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.recent-title {
  font-weight: 600;
}

.recent-sub {
  color: var(--text-muted);

  font-size: var(--fs-body-sm);
}

.recent-remove {
  width: var(--tap-sm);
  height: var(--tap-sm);

  flex-shrink: 0;
  margin-right: var(--space-1);

  display: grid;
  place-items: center;

  border: none;
  border-radius: 50%;

  background: transparent;
  color: var(--text-faint);

  cursor: pointer;

  opacity: 0;

  transition: opacity var(--dur-fast) ease;
}

.recent-item:hover .recent-remove,
.recent-remove:focus-visible {
  opacity: 1;
}

@media (hover: none) {
  .recent-remove {
    opacity: 1;
  }
}

.recent-remove svg {
  width: 14px;
  height: 14px;
}

/* Find in this list */
.list-filter {
  position: relative;
  z-index: 6; /* above the sticky mini header */

  width: min(260px, 100%);

  display: flex;
  align-items: center;

  gap: var(--space-2);
  margin: 0 var(--space-2) var(--space-2) auto;
  padding: 6px var(--space-3);

  border: 1px solid var(--border);
  border-radius: var(--radius-pill);

  background: var(--surface-alt);
  color: var(--text-muted);

  transition: border-color var(--dur-fast) ease;
}

.list-filter:focus-within {
  border-color: var(--pink);
}

.list-filter svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.list-filter input {
  min-width: 0;
  flex: 1;

  border: none;
  outline: none;

  background: transparent;
  color: var(--text);

  font: inherit;
  font-size: var(--fs-body-sm);
}

.list-filter input::-webkit-search-cancel-button {
  -webkit-appearance: none;
}

.list-filter-empty {
  padding: var(--space-5);

  color: var(--text-muted);

  text-align: center;
}

/* Artist pages get a round cover */
.cover.is-round {
  border-radius: 50%;
}

/* Covers fade in as they load instead of popping in one by one
   (js/main.js marks each image .is-loaded on load or error). */
.track img,
.sr-body img,
.recent-art img,
.home-card-cover img,
.continue-card-cover img {
  opacity: 0;

  transition: opacity var(--dur-slow) ease;
}

.track img.is-loaded,
.sr-body img.is-loaded,
.recent-art img.is-loaded,
.home-card-cover img.is-loaded,
.continue-card-cover img.is-loaded {
  opacity: 1;
}

@media (max-width: 850px) {
  .sr-top-grid {
    grid-template-columns: 1fr;
  }

  .sr-top-card {
    height: auto;
    min-height: 0;
  }

  .sr-top-play {
    opacity: 1;
    transform: none;
  }

  .sr-song-time {
    display: none;
  }

  .search-suggest {
    position: fixed;
    top: 72px;
    left: 8px;
    right: 8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .voice-search.is-listening,
  .search-home.sr-enter > * {
    animation: none;
  }
}

/* Grid and flex children default to min-width:auto, so a long artist
   list pushed the songs column (and on phones the top card) past the
   page edge. Let them shrink and truncate instead. */
.sr-top-grid > *,
.sr-songs,
.sr-top,
.sr-section {
  min-width: 0;
}

/* The tabs sit right above the results, not a full gap away. */
.search-home > .sr-chips + .sr-body {
  margin-top: calc(-1 * var(--space-4));
}

@media (max-width: 850px) {
  .sr-top-card {
    padding: var(--space-4);
  }

  .sr-top-art img,
  .sr-top-art .sr-art-fallback {
    width: 72px;
    height: 72px;
  }

  .sr-top-title {
    font-size: 22px;
  }

  .sr-top-play {
    right: var(--space-4);
    bottom: var(--space-4);
  }
}

/* =========================================================
   TOOLTIPS (js/rail-tooltips.js)
   =========================================================
   A small, solid label, never translucent (it has to read over
   artwork). Night: a raised warm grey, one step above every surface,
   with a hairline so it doesn't sink into dark pages. Day: inverted,
   cocoa with cream text, the usual light-theme tooltip (Apple,
   Material). Both are 12 to 14:1 contrast.
   Motion: fades in over 150ms while sliding 4px from the target;
   fades out in 100ms (exits faster than entries). Instant (no fade)
   when hopping between neighbouring controls. */
.app-tooltip {
  position: fixed;
  top: 0;
  left: 0;

  z-index: 2500;

  max-width: 240px;

  padding: 6px 10px;

  border: 1px solid rgba(255, 240, 225, 0.08);
  border-radius: var(--radius-sm);

  background: #352d28;
  color: var(--text);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);

  font-size: var(--fs-body-sm);
  font-weight: 600;
  line-height: 1.35;

  opacity: 0;
  pointer-events: none;

  --tip-from: translateY(4px);
  transform: var(--tip-from);

  transition:
    opacity 100ms ease,
    transform 100ms ease;
}

.app-tooltip[data-side="bottom"] {
  --tip-from: translateY(-4px);
}

.app-tooltip[data-side="right"] {
  --tip-from: translateX(-4px);
}

.app-tooltip.visible {
  opacity: 1;
  pointer-events: auto;
  transform: none;

  transition:
    opacity 150ms var(--ease-out),
    transform 150ms var(--ease-out);
}

.app-tooltip.instant,
.app-tooltip.instant.visible {
  transition: none;
}

:root[data-theme="day"] .app-tooltip {
  border-color: transparent;

  background: #2b231e;
  color: #f7efe7;
  box-shadow: 0 6px 18px rgba(60, 40, 25, 0.25);
}

@media (prefers-reduced-motion: reduce) {
  .app-tooltip,
  .app-tooltip.visible {
    transform: none;
    transition: opacity 100ms ease;
  }
}

/* Reordering your own playlist (js/render.js): a pink line where the
   dragged song will land, and the dragged row fades. */
.track.is-dragging {
  opacity: 0.4;
}

.track.drop-before {
  box-shadow: inset 0 2px 0 var(--pink);
}

.track.drop-after {
  box-shadow: inset 0 -2px 0 var(--pink);
}

/* The note offers Upload itself; don't show it twice. */
.playlist-edit-covers:has(.playlist-edit-covers-note[data-kind="info"]:not([hidden])) .playlist-edit-covers-upload {
  display: none;
}
