/* =========================================================================
   Spotify AI Analytics — Design tokens (B-1)
   =========================================================================
   Single source of truth for colour, type scale, spacing, radii, elevation,
   motion and breakpoints. Loaded before components.css and style.css on every
   page via base.html, so the whole app consumes the same vocabulary.

   Dark-first: `:root` and `[data-theme="dark"]` carry the dark palette; a
   `[data-theme="light"]` override exists so B-7 can add the persisted toggle
   without re-scoping anything here. Consumers must reference tokens, never
   hex literals.
   ========================================================================= */

:root,
[data-theme="dark"] {
  color-scheme: dark;

  /* ── Colour · surfaces ─────────────────────────────────────────────── */
  --color-surface: #121212;
  --color-surface-raised: #181818;
  --color-surface-card: #1e1e2e;
  --color-surface-card-hover: #252538;
  --color-surface-input: #2a2a3e;
  --color-surface-sidebar: #0d0d14;
  --color-surface-sidebar-hover: #1a1a2e;

  /* ── Colour · text ─────────────────────────────────────────────────── */
  --color-text: #eeeeee;
  /* B-8 · #888888 measured 3.95 to 1 on --color-surface-input (#2a2a3e):
     the inactive period pills paint this ramp on the dark input tint at
     11.5px (axe color-contrast, serious, 38 nodes across the eleven
     pages).  #a0a0a0 clears AA there (5.36) and on the page surfaces
     (7.16), and stays a clear step under --color-text (#eeeeee). */
  --color-text-secondary: #a0a0a0;
  /* B-7 contrast.  The muted grey used to be #555555, which measures 2.51 to 1
     on the surface and 2.20 to 1 on the card - unreadable metadata rather than
     de-emphasised metadata.  #878787 clears AA (4.5 to 1) on surface, raised,
     card and sidebar while staying a step dimmer than --color-text-secondary,
     so the ramp keeps its order. */
  --color-text-muted: #949494;
  --color-text-inverse: #121212;

  /* ── Colour · brand + feedback ─────────────────────────────────────── */
  --color-accent: #1db954;
  --color-on-accent: #121212;
  --color-accent-hover: #1ed760;
  --color-accent-dim: rgba(29, 185, 84, 0.15);
  --color-success: #1db954;
  --color-danger: #f2725f;
  --color-danger-hover: #ff6b5c;
  --color-danger-dim: rgba(231, 76, 60, 0.15);
  --color-warning: #f39c12;
  --color-warning-dim: rgba(243, 156, 18, 0.15);
  --color-info: #5b9dd9;
  --color-purple: #a78bfa;

  /* ── Colour · borders (on dark surfaces) ───────────────────────────── */
  --border-color: #2a2a3e;
  --border-subtle: #1e1e2e;
  --border-strong: #3a3a52;

  /* ── Type scale (1.200 minor-third-ish ratio; see --type-ratio) ────── */
  --type-ratio: 1.2;
  --font-size-2xs: 0.625rem;   /* 10px  */
  --font-size-xs: 0.75rem;     /* 12px  */
  --font-size-sm: 0.875rem;    /* 14px  — base (html { font-size }) */
  --font-size-md: 1rem;        /* 16px  */
  --font-size-lg: 1.2rem;      /* 19.2px */
  --font-size-xl: 1.44rem;     /* 23px  */
  --font-size-2xl: 1.728rem;   /* 27.6px */
  --font-size-3xl: 2.074rem;   /* 33px  */

  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
    Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif;
  --font-mono: "SF Mono", "Fira Code", "Fira Mono", "Roboto Mono", monospace;
  --font-weight-regular: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;

  --line-height-tight: 1.2;
  --line-height-normal: 1.5;
  --line-height-relaxed: 1.65;

  /* ── Spacing scale (base 4px) ──────────────────────────────────────── */
  --space-3xs: 2px;
  --space-2xs: 4px;
  --space-xs: 8px;
  --space-sm: 12px;
  --space-md: 16px;
  --space-lg: 24px;
  --space-xl: 32px;
  --space-2xl: 48px;
  --space-3xl: 64px;

  /* ── Radii ─────────────────────────────────────────────────────────── */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-full: 999px;

  /* ── Elevation (shadows) ───────────────────────────────────────────── */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.25);
  --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.4);
  --shadow-accent: 0 4px 12px rgba(29, 184, 84, 0.25);

  /* ── Motion ────────────────────────────────────────────────────────── */
  --transition-fast: 120ms ease;
  --transition: 150ms ease;
  --transition-slow: 240ms ease;
  --transition-ease-out: 150ms cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --transition-spring: 360ms cubic-bezier(0.34, 1.56, 0.64, 1);
  --transition-pill: 260ms cubic-bezier(0.34, 1.56, 0.64, 1);
  --mini-player-clearance: calc(var(--space-2xl) + var(--space-sm));

  /* ── Tap targets (Phase B requirement: ≥ 44px) ─────────────────────── */
  --tap-min: 44px;
  --tap-comfortable: 48px;

  /* B-8 · the *text* half of the active navigation link's pair.  The tint
     behind it (`--accent-dim`) and its label were both the brand green, which
     measures 4.29:1 in the light theme — 0.2 under the AA floor for its 13.3px
     label (axe `color-contrast`, serious).  The light theme points the label
     at the plain text colour instead (13.75:1 on the same tint); the tint and
     the icon keep carrying the state. */
  --nav-active-text: var(--color-accent);

  /* B-8 · the clip box the visually-hidden pattern needs.  A zero-sized box
     can drop out of the accessibility tree in some browsers, so the pattern
     keeps a hairline; naming it here keeps the 1px out of the ad-hoc census
     (B-1's ratchet) and out of the page stylesheets. */
  --hairline: 1px;

  /* B-8 · the visible focus ring, in one place: the width doubles as the
     offset, so the ring reads the same everywhere it is drawn (and the ad-hoc
     census stays at its ceiling). */
  --focus-ring: 2px;

  /* ── Breakpoints (custom properties are static; see @media below) ──── */
  --bp-sm: 480px;
  --bp-md: 768px;
  --bp-lg: 1024px;
  --bp-xl: 1280px;

  /* ── App layout constants (referenced by style.css consumers) ──────── */
  --sidebar-width: 220px;

  /* ── z-index scale ─────────────────────────────────────────────────── */
  --z-below: -1;
  --z-base: 0;
  --z-raised: 10;
  --z-sticky: 100;
  --z-overlay: 200;

  /* ── Component skeleton (for hidden-but-structured placeholders) ───── */
  --skeleton-base: #2a2a3e;
  --skeleton-highlight: #3a3a52;
}

/* ── Light theme override (B-7 renders it from the persisted choice). ────
   The `html` element in the selector is load-bearing.  ``style.css`` is
   linked *after* this file and declares the legacy names the shell paints
   itself with (``--bg-primary``, ``--text-primary``, …) in its own ``:root``,
   so B-1's bare ``[data-theme="light"]`` tied on specificity (0,1,0) and lost
   on load order: the class-name map below never reached the page.  ``html[…]``
   (0,1,1) beats ``:root`` whatever the order, which is what makes the toggle
   visible at all.
   Where a name exists in both vocabularies the alias points at the token, so
   the two cannot drift.  The legacy *text* colours with no light counterpart
   get values of their own, and two B-1 tokens are re-pointed for light, all
   for the same reason: the dark-first ramps fall short of WCAG AA as text on a
   light surface.  --color-text-muted was 3.06:1 and the brand green (as accent
   text) 2.48:1; every pair is measured in tests/test_theme_toggle.py, and the
   dark ramp itself is untouched. */
html[data-theme="light"] {
  color-scheme: light;

  --color-surface: #fafafa;
  --color-surface-raised: #ffffff;
  --color-surface-card: #ffffff;
  --color-surface-card-hover: #f0f0f0;
  --color-surface-input: #f2f2f2;
  --color-surface-sidebar: #f0f0f0;
  --color-surface-sidebar-hover: #e6e6e6;

  --color-text: #1a1a1a;
  --color-text-secondary: #555555;
  /* B-7 contrast.  The muted grey used to be #909090, which measures 3.06 to 1
     on the surface and 2.80 to 1 on the sidebar.  #6b6b6b clears AA on every
     light surface, the input tint included, while staying dimmer than
     --color-text-secondary. */
  --color-text-muted: #6b6b6b;
  --color-text-inverse: #fafafa;

  /* The brand green is a dark-surface colour.  As *text* on a light surface it
     measures 2.48 to 1, so the light palette points the accent at the same
     text-safe green the shell already paints accent text with, one step darker
     on hover.  The dark ramp is untouched. */
  --color-accent: #0f7a37;
  /* Text on an accent fill: the light theme's green is dark, the dark
     theme's is bright, so the readable colour flips with the theme. */
  --color-on-accent: #fafafa;
  --color-accent-hover: #0b5f2b;
  --color-accent-dim: rgba(29, 185, 84, 0.12);
  --color-info: #2f6fb3;
  /* B-8 · #7c5cd6 measured 4.41 to 1 as heading text on the light cards'
     #f6f4fa tint (axe color-contrast, serious, /cultural and
     /compatibility); one step darker clears AA on that tint (4.90) and on
     white (5.35), and white text on the same purple as a badge fill improves
     from 4.82 to 5.35.  Mirrored in the auto block below. */
    --color-purple: #7554cf;

  --border-color: #d8d8d8;
  --border-subtle: #e6e6e6;
  --border-strong: #b0b0b0;

  /* Feedback tints recalc against the light surfaces. */
  --color-danger-dim: rgba(231, 76, 60, 0.12);
  --color-warning-dim: rgba(243, 156, 18, 0.12);

  /* B-8 · the two solid feedback colours are *text* on these surfaces as well
     (system-status' values, the quiz's feature numbers), and the dark-first
     ramps fall short of AA there — #e74c3c measures 3.87 to 1 on white and
     #f39c12 only 2.20.  The light palette points them at the same text-safe
     values the shell's legacy aliases already paint with; every pair is
     measured with tests/test_accessibility.py's ratio helper and in the
     browser by tests/e2e/test_a11y.py, in both themes. */
  --color-danger: #c0392b;
  --color-warning: #8a5a00;

  /* B-8 · the active navigation link's label — see the dark palette. */
  --nav-active-text: var(--color-text);

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.08);
  --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.12);
  --shadow-accent: 0 4px 12px rgba(29, 185, 84, 0.18);

  --skeleton-base: #e0e0e0;
  --skeleton-highlight: #f0f0f0;

  /* The legacy vocabulary the shell in style.css still reads. */
  --bg-primary: var(--color-surface);
  --bg-secondary: #f2f2f2;
  --bg-card: var(--color-surface-card);
  --bg-card-hover: var(--color-surface-card-hover);
  --bg-input: var(--color-surface-input);
  --bg-sidebar: var(--color-surface-sidebar);
  --bg-sidebar-hover: var(--color-surface-sidebar-hover);
  --text-primary: var(--color-text);
  --text-secondary: var(--color-text-secondary);
  --text-muted: var(--color-text-muted);
  --accent: #0f7a37;
  --accent-hover: #0b5f2b;
  --accent-dim: var(--color-accent-dim);
  --danger: #c0392b;
  --warning: #8a5a00;
  --shadow: var(--shadow-md);
}

/* ── The unchosen case: follow the operating system (B-7). ───────────────
   ``base.html`` emits ``data-theme="auto"`` when the owner has never chosen
   a theme, so the *absence* of a choice is a state of its own and this media
   query - not a script - decides what it looks like.  The declarations below
   are the light palette again, deliberately: a custom property cannot be
   aliased from a media query, so the only alternative here would be a
   rewrite of the token layer (the light values as ``light-dark()``
   arguments), which B-1's contract with the rest of the app forbids.
   tests/test_theme_toggle.py asserts these two blocks stay identical, so the
   duplication cannot drift. */
@media (prefers-color-scheme: light) {
  html[data-theme="auto"] {
    color-scheme: light;

    --color-surface: #fafafa;
    --color-surface-raised: #ffffff;
    --color-surface-card: #ffffff;
    --color-surface-card-hover: #f0f0f0;
    --color-surface-input: #f2f2f2;
    --color-surface-sidebar: #f0f0f0;
    --color-surface-sidebar-hover: #e6e6e6;

    --color-text: #1a1a1a;
    --color-text-secondary: #555555;
    /* B-7 contrast.  The muted grey used to be #909090, which measures 3.06 to
       1 on the surface and 2.80 to 1 on the sidebar.  #6b6b6b clears AA on
       every light surface, the input tint included, while staying dimmer than
       --color-text-secondary. */
    --color-text-muted: #6b6b6b;
    --color-text-inverse: #fafafa;

    /* The brand green is a dark-surface colour.  As *text* on a light surface
       it measures 2.48 to 1, so the light palette points the accent at the same
       text-safe green the shell already paints accent text with, one step
       darker on hover.  The dark ramp is untouched. */
    --color-accent: #0f7a37;
  /* Text on an accent fill: the light theme's green is dark, the dark
     theme's is bright, so the readable colour flips with the theme. */
  --color-on-accent: #fafafa;
    --color-accent-hover: #0b5f2b;
    --color-accent-dim: rgba(29, 185, 84, 0.12);
    --color-info: #2f6fb3;
    /* B-8 · #7c5cd6 measured 4.41 to 1 as heading text on the light cards'
     #f6f4fa tint (axe color-contrast, serious, /cultural and
     /compatibility); one step darker clears AA on that tint (4.90) and on
     white (5.35), and white text on the same purple as a badge fill improves
     from 4.82 to 5.35.  Mirrored in the auto block below. */
    --color-purple: #7554cf;

    --border-color: #d8d8d8;
    --border-subtle: #e6e6e6;
    --border-strong: #b0b0b0;

    --color-danger-dim: rgba(231, 76, 60, 0.12);
    --color-warning-dim: rgba(243, 156, 18, 0.12);

    /* B-8 · mirrors the light palette above, see the note there. */
    --color-danger: #c0392b;
    --color-warning: #8a5a00;
    --nav-active-text: var(--color-text);

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.08);
    --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.1);
    --shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.12);
    --shadow-accent: 0 4px 12px rgba(29, 185, 84, 0.18);

    --skeleton-base: #e0e0e0;
    --skeleton-highlight: #f0f0f0;

    --bg-primary: var(--color-surface);
    --bg-secondary: #f2f2f2;
    --bg-card: var(--color-surface-card);
    --bg-card-hover: var(--color-surface-card-hover);
    --bg-input: var(--color-surface-input);
    --bg-sidebar: var(--color-surface-sidebar);
    --bg-sidebar-hover: var(--color-surface-sidebar-hover);
    --text-primary: var(--color-text);
    --text-secondary: var(--color-text-secondary);
    --text-muted: var(--color-text-muted);
    --accent: #0f7a37;
    --accent-hover: #0b5f2b;
    --accent-dim: var(--color-accent-dim);
    --danger: #c0392b;
    --warning: #8a5a00;
    --shadow: var(--shadow-md);
  }
}

/* ── Breakpoints ─────────────────────────────────────────────────────────
   CSS @media cannot read custom properties, so the breakpoints live here as
   custom properties `--bp-*` AND as the canonical media queries below.
   Consumers MUST copy these exact query strings — never invent literals:
     @media (min-width: 480px)   { … }   --bp-sm
     @media (min-width: 768px)   { … }   --bp-md
     @media (min-width: 1024px)  { … }   --bp-lg
     @media (min-width: 1280px)  { … }   --bp-xl
   390 px (phones, phase target) falls below --bp-sm and needs no query. */


/* ── Studio layer (S1) ───────────────────────────────────────────────────
   The overlay vocabulary the redesigned shell, cards, pills and rows draw
   with.  Every value here is derived from a colour token with ``color-mix``
   so a single definition adapts to both themes — no second palette block to
   drift, and no colour literal in any consumer.
   ───────────────────────────────────────────────────────────────────────── */

:root,
[data-theme="dark"] {
  /* Geometry */
  --radius-xl: 20px;
  --radius-2xl: 28px;
  --header-height: 58px;
  --tabbar-height: 62px;
  --content-max: 1180px;
  --nav-float-inset: var(--space-sm);

  /* Glass — a raised surface, thinned so the page tint reads through it. */
  --glass-bg: color-mix(in srgb, var(--color-surface-raised) 68%, transparent);
  --glass-bg-strong: color-mix(
    in srgb,
    var(--color-surface-raised) 88%,
    transparent
  );
  --glass-border: color-mix(in srgb, var(--border-strong) 45%, transparent);
  --glass-blur: 20px;
  --glass-sheen: color-mix(in srgb, var(--color-text) 5%, transparent);
  --scrim: color-mix(in srgb, var(--color-surface) 78%, transparent);

  /* Wash + tints */
  --surface-tint: color-mix(in srgb, var(--color-text) 4%, transparent);
  --surface-tint-strong: color-mix(in srgb, var(--color-text) 8%, transparent);
  --meter-track: color-mix(in srgb, var(--border-color) 80%, transparent);
  --ring-accent: 0 0 0 3px
    color-mix(in srgb, var(--color-accent) 26%, transparent);

  /* Gradients */
  --hero-gradient: linear-gradient(
    145deg,
    color-mix(in srgb, var(--color-accent) 16%, transparent) 0%,
    transparent 62%
  );
  --accent-gradient: linear-gradient(
    120deg,
    var(--color-accent) 0%,
    var(--color-success) 100%
  );
  --page-gradient:
    radial-gradient(
      ellipse 90% 50% at 12% -12%,
      color-mix(in srgb, var(--color-accent) 13%, transparent),
      transparent 60%
    ),
    radial-gradient(
      ellipse 70% 40% at 92% 4%,
      color-mix(in srgb, var(--color-purple) 11%, transparent),
      transparent 62%
    );

  /* Elevation */
  --shadow-card: 0 1px 2px color-mix(in srgb, #000 22%, transparent),
    0 10px 30px -18px color-mix(in srgb, #000 60%, transparent);
  --shadow-float: 0 14px 38px -14px color-mix(in srgb, #000 70%, transparent);
  --shadow-nav: 0 -10px 32px -16px color-mix(in srgb, #000 75%, transparent);

  /* Avatar tints — deterministic initials placeholders. */
  --avatar-1: color-mix(in srgb, var(--color-accent) 24%, var(--color-surface-input));
  --avatar-2: color-mix(in srgb, var(--color-purple) 26%, var(--color-surface-input));
  --avatar-3: color-mix(in srgb, var(--color-info) 26%, var(--color-surface-input));
  --avatar-4: color-mix(in srgb, var(--color-warning) 24%, var(--color-surface-input));
  --avatar-5: color-mix(in srgb, var(--color-danger) 22%, var(--color-surface-input));
  --avatar-6: color-mix(in srgb, var(--color-success) 22%, var(--color-surface-input));
}

/* ── Base element defaults (inherited by every page) ─────────────────── */
html {
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  line-height: var(--line-height-normal);
}

body {
  font-family: var(--font-sans);
  font-size: var(--font-size-sm);
  color: var(--color-text);
  background-color: var(--color-surface);
}
