/* =========================================================
   EARLOOP — DESIGN TOKENS
   Two warm themes, rani pink as the one accent in both:
   - Night (:root, below): cocoa black with cream text.
   - Day ([data-theme="day"], after it): cream with cocoa text.
   js/theme.js picks one by the clock (Day 6:00 to 18:59) unless the
   listener chose one in Preferences. Not OS-preference-driven: the
   two themes are part of the brand, and both are reviewed by hand.
   Every text colour passes 4.5:1 on every surface in both themes.
   ========================================================= */

/* Registered so the artwork glow can fade between colours instead
   of snapping (gradients themselves can't transition). */
@property --tint {
  syntax: "<color>";
  inherits: true;
  initial-value: rgba(214, 20, 95, 0.28);
}

:root {
  /* ---- accent: one pink, two shades ----
     Rani pink, the deep Indian pink, is the brand color. Like every
     saturated brand color on a dark theme (Material's dark theme
     guidance), it needs two shades to stay legible:
     - --pink-fill: filled surfaces with white text on them (play
       button, Save, badges). White on it is 5.1:1 (WCAG AA needs 4.5).
     - --pink: a brighter tone for pink text, icons and active states
       on the dark background, 5.3 to 6.2:1 on every surface. The old
       single #ff2d78 failed both jobs: white text on it was 3.6:1.
     Hover on a fill goes darker, not lighter, so contrast only rises. */
  --pink: #ff4d8d;
  --pink-fill: #d6145f;
  --pink-fill-hover: #be0f53;
  --pink-dark: #9e0d45; /* deep end of pink gradients */
  --pink-light: rgba(255, 77, 141, 0.16);
  --pink-soft: rgba(255, 77, 141, 0.08);

  /* ---- partner: jamuni violet ----
     Only for hero moments (welcome, page headers, Now Playing glow),
     paired with pink in a gradient. Never for buttons, text or states:
     pink stays the one interactive accent. Violet keeps the gradient
     vivid for red-green colour-blind listeners, for whom pink alone
     turns grey-beige. White on --violet-fill is 5.8:1; across the
     pink-to-violet gradient it never drops below 5.1:1. */
  --violet: #b36bff; /* violet text, if ever needed: 6.0:1 on --bg */
  --violet-fill: #8e2de2;
  --violet-soft: rgba(142, 45, 226, 0.1);
  --brand-gradient: linear-gradient(135deg, var(--pink-fill), var(--violet-fill));

  /* Page-header and Now Playing glow. js/artwork-tint.js replaces it
     with a colour from the current artwork; this is the fallback. */
  --tint: rgba(214, 20, 95, 0.28);

  /* ---- text ----
     Cream-tinted, warm greys, so the neutrals belong with the warm
     surfaces. Faint is 4.9:1 on the lightest surface, the rest higher. */
  --text: #f7efe7;
  --text-muted: #bcaea3;
  --text-faint: #9a8c81;

  /* ---- surfaces ----
     Cocoa black (warm, not the old plum). Raised layers get lighter,
     not shadowed (Material's dark-theme elevation rule). */
  --bg: #14110f;
  --bg-rgb: 20, 17, 15; /* same as --bg, as r,g,b, for rgba() fades */
  --surface: #1c1815;
  --surface-alt: #27211d;
  --surface-rgb: 28, 24, 21; /* same as --surface, as r,g,b, for rgba() translucency */
  --border: rgba(255, 240, 225, 0.08);
  --border-strong: rgba(255, 240, 225, 0.14);
  --skeleton-shine: rgba(255, 240, 225, 0.08);
  /* Hover fill for quiet controls (arrows, chips, sort): one step
     up from the surface, never an outline colour reused as a fill. */
  --fill-hover: rgba(255, 240, 225, 0.12);
  /* List rows (sidebar library): three steps you can tell apart.
     Hover is a hint, the open item is clearly marked, pressing is
     firmer still. */
  --row-hover: rgba(255, 240, 225, 0.06);
  --row-active: rgba(255, 240, 225, 0.12);
  --row-press: rgba(255, 240, 225, 0.17);

  --shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 16px 40px rgba(0, 0, 0, 0.5);

  /* Orange, not red: a red error would look like the pink brand color
     and stop reading as a warning. */
  --error: #ff8a4c;

  /* "Currently playing" indicator for a sidebar playlist row — the
     one deliberate exception to this app's single-pink-accent rule
     (see css/sidebar.css's own header comment): playback state reads
     as a distinct signal from selection/hover everywhere else in
     this app already (the track-list's own .playing state also uses
     an accent, just pink there since there's no competing "selected"
     state to disambiguate from in that list). Reuses the same green
     already in playlist-colors.js's cover palette rather than
     inventing a second one. */
  /* Was a separate green, while the playing row and queue used pink:
     two "now playing" colours. One accent now. */
  --now-playing: var(--pink);

  color-scheme: dark;

  /* ---- typography ----
     Grounded in three researched sources rather than eyeballed —
     see docs/PRODUCT.md's "Typography" section for the full citation-by-
     citation rationale:
       - Material Design 3's type scale (m3.material.io/styles/typography) —
         the most concretely evidenced numbers here: Body Large 16 /
         Medium 14 / Small 12, Label Small 11.
       - Apple HIG Dynamic Type (Body = 17pt at the default size) —
         apple.com/design/human-interface-guidelines/typography.
       - The general accessibility best practice of not running real,
         repeatedly-read content below ~14px, distinct from WCAG 1.4.4
         itself (which sets no hard px minimum, only a 200%-resize
         requirement) — the two are often conflated, so kept separate
         on purpose.
     Still a restrained, hand-tuned scale rather than a strict
     mathematical ratio — this is a dense, information-heavy UI (track
     lists, metadata), not editorial copy, so steps compress at the
     small end where a "true" ratio would produce sizes that don't
     actually read well (13px vs 13.97px isn't a meaningful
     difference; 17px vs 28px is). */
  /* Figtree first, so Latin always uses it; the Anek families only
     ever supply Indian-script characters (index.html explains the
     loading). Then system fonts, in case Google Fonts is blocked. */
  --font-sans:
    "Figtree", "Anek Devanagari", "Anek Bangla", "Anek Gurmukhi",
    "Anek Gujarati", "Anek Tamil", "Anek Telugu", "Anek Kannada",
    "Anek Malayalam", -apple-system, BlinkMacSystemFont, "Segoe UI",
    Roboto, Helvetica, Arial, sans-serif;

  --fs-display: 28px; /* hero title — the one true page heading; restrained vs Apple's 34pt Large Title on purpose */
  --fw-display: 800;
  --lh-display: 1.15;
  --ls-display: -0.02em;

  --fs-title: 17px; /* brand wordmark, panel/section headers — matches Apple's Dynamic Type Body (17pt) */
  --fw-title: 700;
  --lh-title: 1.3;
  --ls-title: -0.01em;

  --fs-body-lg: 15px; /* primary scannable content — track titles, nav links, buttons.
                          Clears the ~14px "don't run real content smaller" floor with
                          headroom, while staying under Material's Body Large (16px)
                          and Apple's Body (17pt) — this is denser than either by design. */
  --fw-body-lg: 600;
  --lh-body-lg: 1.35;

  --fs-body: 14px; /* default UI text — inputs, descriptions, messages.
                       Exact match to Material 3's Body Medium. */
  --fw-body: 500;
  --lh-body: 1.45;

  --fs-body-sm: 12px; /* secondary/metadata — artist names, durations, sub-text.
                          Exact match to Material 3's Body Small / Label Medium. */
  --fw-body-sm: 500;
  --lh-body-sm: 1.4;

  --fs-label: 11px; /* eyebrow labels and micro numerals share a size, distinguished
                        by weight/case, not another step. Exact match to Material 3's
                        Label Small — the established floor for utilitarian, non-body
                        text (never used for anything a user reads at length). */
  --fw-label: 700;
  --lh-label: 1.2;
  --ls-label: 0.06em;

  /* ---- icon sizes ----
     Same "researched tokens, not eyeballed per component" approach as
     typography above — see docs/PRODUCT.md's "Icon sizes" section for full
     citations. Two dimensions, kept deliberately separate: the icon
     *glyph* itself (--icon-*, what the SVG renders at) and its
     *touch/click target* (--tap-*, the button's own box) — conflating
     these is the single most common icon-sizing mistake per both
     Apple's HIG and Material Design's own guidance: a target can (and
     for accessibility, often should) be meaningfully bigger than the
     glyph inside it, with padding absorbing the difference rather than
     an oversized icon.

     Four icon tiers map to function, not to whatever pixel value a
     given icon already happened to be — a music player's transport
     cluster has a real, well-established hierarchy (every mainstream
     player — Spotify, Apple Music, YouTube Music — renders it this
     way): Play/Pause is the single most-used control and reads
     visibly larger than its neighbors; Prev/Next are frequent but
     secondary; everything else (shuffle, repeat, volume, queue,
     lyrics, nav, track-row actions) is utility-tier, same small size
     throughout so it doesn't compete with the controls that matter. */
  --icon-xs: 14px; /* compact/dense chrome — clear-search ×, queue-panel close × — and icon+label CTAs, where the text carries the primary legibility load */
  --icon-sm: 16px; /* utility/modifier controls — shuffle, repeat, volume, queue, lyrics, back/forward, sidebar nav, track-row actions */
  --icon-md: 20px; /* core transport — prev/next */
  --icon-lg: 26px; /* primary transport — play/pause, the one icon in the whole UI that should read as visually dominant */

  /* Touch targets — WCAG 2.5.8 (Target Size Minimum, AA) sets 24×24
     CSS px as the accessibility floor; Apple HIG and Material Design
     both go further for anything meant to be comfortably tappable —
     44×44pt and 48×48dp respectively. --tap-sm is the only tier that
     comes close to the WCAG floor, and still clears it with real
     margin (32px vs. a 24px minimum) — nothing in this system ever
     sits at the floor itself. */
  --tap-sm: 32px; /* compact/dense chrome only — same contexts as --icon-xs */
  --tap-md: 40px; /* the default for icon-only buttons — utility controls and prev/next alike */
  --tap-lg: 48px; /* play/pause — Material's full 48dp touch-target spec, matching its role as the most-used control */

  /* ---- sidebar ----
     A single variable driving the grid column (css/layout.css), not
     a hardcoded width — js/sidebar.js reads/writes this directly so
     dragging the resize handle and toggling rail mode are just
     "change one number," with every layout rule that depends on the
     sidebar's width already wired to follow it. Bounds match Spotify
     desktop's own resizable sidebar range closely (theirs is roughly
     ~220–420px) — restrictive enough that the main content never gets
     starved, generous enough for genuinely long playlist names to
     read without truncating immediately. */
  --sidebar-width: 272px;
  --sidebar-min-width: 220px;
  --sidebar-max-width: 400px;
  --sidebar-collapsed-width: 76px; /* rail mode — enough for a centered 20px icon plus real touch-target padding, not a cramped sliver */

  /* Spacing, corners and motion, same idea as the type and icon
     tokens above: named steps instead of a value picked per rule.
     Spacing is a 4px grid. New and touched styles use these; older
     rules still carry literal values (7px, 9px, ...) and move over as
     they're edited. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;

  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-pill: 999px;

  --dur-fast: 120ms;
  --dur-base: 200ms;
  --dur-slow: 320ms;
  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-in: cubic-bezier(0.4, 0, 1, 1); /* exits: speed up and get out of the way */
}

/* ---- Day theme ----
   Only colours change; sizes, type and motion are shared. Measured
   contrast: text 13.7 to 16.4:1, muted 5.8:1+, faint 4.7:1+, pink
   text 4.8:1+ on every surface; white on --pink-fill stays 5.1:1.
   The brighter night pink (#ff4d8d) would be 3:1 on cream, so pink
   text here is a deeper shade. */
:root[data-theme="day"] {
  --pink: #c4105a;
  --pink-light: rgba(214, 20, 95, 0.12);
  --pink-soft: rgba(214, 20, 95, 0.06);

  --violet: #7b2fd0;
  --violet-soft: rgba(142, 45, 226, 0.08);

  --tint: rgba(255, 138, 101, 0.3);

  --text: #231c17;
  --text-muted: #62564d;
  --text-faint: #716459;

  /* Cream page, near-white cards: elevation reads by a soft shadow
     here, the light-theme convention, instead of a lighter fill. */
  --bg: #f6f1ea;
  --bg-rgb: 246, 241, 234;
  --surface: #fffcf8;
  --surface-alt: #eee7de;
  --surface-rgb: 255, 252, 248;
  --border: rgba(60, 40, 25, 0.1);
  --border-strong: rgba(60, 40, 25, 0.18);
  --skeleton-shine: rgba(255, 255, 255, 0.7);
  --fill-hover: rgba(60, 40, 25, 0.08);
  --row-hover: rgba(60, 40, 25, 0.05);
  --row-active: rgba(60, 40, 25, 0.1);
  --row-press: rgba(60, 40, 25, 0.15);

  --shadow-sm: 0 2px 10px rgba(60, 40, 25, 0.08);
  --shadow-md: 0 16px 40px rgba(60, 40, 25, 0.14);

  --error: #b93a0a;

  color-scheme: light;
}

/* The moment the clock switches themes (js/theme.js adds this class
   for a second), colours fade instead of flipping mid-song. */
.theme-fading,
.theme-fading * {
  transition:
    background-color 600ms ease,
    border-color 600ms ease,
    color 600ms ease !important;
}

/* =========================================================
   RESET
   ========================================================= */

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* The browser's own [hidden] rule is weaker than any class that sets
   display (.btn's inline-flex, for one), so `hidden` on a button
   silently did nothing. This makes the attribute always win. */
[hidden] {
  display: none !important;
}

html {
  height: 100%;
}

body {
  min-height: 100%;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);

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

  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;

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

button,
input {
  font: inherit;
}

svg {
  display: block;
}

/* Digits that appear in columns (time, counts) shouldn't jitter
   as they change — tabular figures keep every glyph the same width. */
.time,
.time-row,
.player-title,
.player-artist,
#curTime,
#durTime {
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* =========================================================
   SCROLLBARS
   ========================================================= */

* {
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}

*::-webkit-scrollbar {
  width: 7px;
  height: 7px;
}

*::-webkit-scrollbar-track {
  background: transparent;
}

*::-webkit-scrollbar-thumb {
  background: var(--border-strong);

  border-radius: 999px;
}

*::-webkit-scrollbar-thumb:hover {
  background: var(--pink-fill);
}

/* =========================================================
   FOCUS STATES (keyboard accessibility)
   ========================================================= */

a:focus-visible,
button:focus-visible,
input:focus-visible,
.track:focus-visible,
.playlist-item:focus-visible,
.queue-item:focus-visible {
  outline: 2px solid var(--pink);
  outline-offset: 2px;
}

/* Off screen until focused, then a pill at the top left. */
.skip-link {
  position: fixed;
  top: 12px;
  left: 12px;

  z-index: 1000;

  padding: 10px 16px;

  border: 0;
  border-radius: 999px;
  background: var(--pink-fill);
  color: #fff;

  font: inherit;
  font-weight: 700;

  transform: translateY(-200%);
}

.skip-link:focus-visible {
  transform: none;
}

/* The page area takes focus from the skip link; no ring around all of it. */
#mainContent:focus {
  outline: none;
}

/* These fields show focus with their own border; the ring on top
   doubled it. */
.search input:focus-visible,
.prefs-input:focus-visible,
.save-to-filter:focus-visible,
.playlist-edit-field input:focus-visible,
.library-view .library-search-input:focus-visible,
.ai-input-row input:focus-visible {
  outline: none;
}

/* =========================================================
   SELECTION
   ========================================================= */

::selection {
  background: var(--pink-light);

  color: var(--text);
}

/* =========================================================
   MOTION
   ========================================================= */

/* Page change: the new content fades up into place instead of
   swapping in abruptly (js/navigation.js adds .view-enter). */
.view-enter {
  animation: view-enter var(--dur-slow) var(--ease-out);
}

@keyframes view-enter {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

/* Press feedback on buttons, so a click feels registered. */
.btn:active:not(:disabled),
.hero-play:active:not(:disabled),
.hero-secondary-btn:active,
.list-empty-cta:active,
.avatar:active {
  transform: scale(0.95);
}

/* New song: the player-bar cover fades in (js/player.js). */
.cover-swap {
  animation: cover-swap var(--dur-base) var(--ease-out);
}

@keyframes cover-swap {
  from {
    opacity: 0.2;
    transform: scale(0.94);
  }
}

@media (prefers-reduced-motion: reduce) {
  .view-enter,
  .cover-swap {
    animation: none;
  }
}
