/* AudioPress stylesheet.
 *
 * Authored against guidelines/css_and_some_js.md + website.md:
 * mobile-first, custom-property design tokens, fluid `clamp()` type scale,
 * logical properties throughout, `:focus-visible` rings, light/dark via
 * `prefers-color-scheme`, and all motion gated behind
 * `prefers-reduced-motion: no-preference`. Served immutably + fingerprinted. */

/* ---- Design tokens ------------------------------------------------------ */

:root {
  color-scheme: light dark;

  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* Comfortable reading measure for prose-heavy podcast pages, plus a wider
     measure for grid-y, scannable pages (the episode list) that should use the
     extra room on desktop instead of stranding it in the margins. */
  --measure: 70ch;
  --measure-wide: 78rem;
  --radius: 10px;

  /* Motion tokens (one easing, two durations) — see guidelines/animations.md.
     All motion is gated behind `prefers-reduced-motion: no-preference`. */
  --ease-out: cubic-bezier(0.33, 1, 0.68, 1);
  --dur-quick: 120ms;
  --dur-default: 280ms;
  --shadow-soft: 0 4px 12px -6px rgb(0 0 0 / 45%);
  --shadow-card: 0 16px 34px -20px rgb(0 0 0 / 60%);

  /* Spacing scale (one knob per step). */
  --space-3xs: 0.25rem;
  --space-2xs: 0.5rem;
  --space-xs: 0.75rem;
  --space-s: 1rem;
  --space-m: 1.5rem;
  --space-l: 2.5rem;
  --space-xl: 4rem;
  --space-2xl: 6rem;

  /* Fluid type scale: each step interpolates with the viewport, floored at an
     accessible rem base so user font-size preferences are respected. */
  --step--1: clamp(0.83rem, 0.78rem + 0.24vw, 0.95rem);
  --step-0: clamp(1rem, 0.93rem + 0.34vw, 1.19rem);
  --step-1: clamp(1.2rem, 1.06rem + 0.68vw, 1.55rem);
  --step-2: clamp(1.44rem, 1.21rem + 1.14vw, 2.03rem);
  --step-3: clamp(1.73rem, 1.36rem + 1.85vw, 2.66rem);

  /* Palette: light defaults at `:root`. OS preference + the nav theme toggle
     each layer on top — see the `@media` + `[data-theme]` blocks below.
     (We *used* `light-dark()` here, but axe-core 4.10.2 in CI couldn't resolve
     its computed value, so color-contrast spuriously read `#aeafb2` for every
     text node. Explicit declarations + a `[data-theme]` toggle override work
     everywhere and keep the instant-flip toggle behaviour.) */
  --bg: hsl(40 36% 97%);
  --surface: hsl(40 40% 100%);
  --text: hsl(222 24% 16%);
  --muted: hsl(222 12% 40%);
  --border: hsl(222 16% 87%);
  --accent: hsl(255 64% 50%);
  --on-accent: hsl(0 0% 100%);
  --focus: hsl(255 86% 58%);

  /* Colour-blind-aware per-speaker transcript palette (AA contrast on this
     scheme; à la Okabe–Ito). Independent of `--accent` so speakers stay
     mutually distinct under any show theme. Dark variants below. */
  --spk-0: #1565c0;
  --spk-1: #c62828;
  --spk-2: #2e7d32;
  --spk-3: #6a1b9a;
  --spk-4: #b35900;
  --spk-5: #ad1457;

  /* Form/validation error text (AA on this scheme). */
  --danger: #c62828;

  --min-tap: 32px;

  /* Stacking layers. The painting order, bottom → top:
     * page content (default `auto`, effectively 0)
     * `--z-dock`     — sticky episode-dock (the player bar)
     * `--z-popover`  — popovers anchored to page content (the download
       menu); MUST sit above `--z-dock` because the chip lives in the
       hero `.episode-header` (static, z:auto) while the player dock is
       a sticky sibling — the popover panel extends downward INTO the
       dock's territory and would be painted over by the dock otherwise
     * `--z-header`   — the site banner (always-visible top chrome)
     * `--z-side-nav` — the floating "On this page" jump-nav (pill + open
       panel). Always on top: the pill must stay tappable over the dock, and
       the panel opens UPWARD into the dock's territory, so anything lower lets
       the player bar paint over it. Above the banner too — a bottom-corner
       control never overlaps the top chrome in practice, and an actively-open
       menu should win if it ever does. Dismisses on outside-click / Escape
       (episode-dock.js), so it never lingers over the page. */
  --z-dock: 25;
  --z-popover: 26;
  --z-header: 30;
  --z-side-nav: 40;
}

/* OS prefers dark — unless the user explicitly forced "light" via the toggle. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: hsl(230 18% 11%);
    --surface: hsl(230 16% 16%);
    --text: hsl(220 24% 92%);
    --muted: hsl(220 14% 66%);
    --border: hsl(230 12% 27%);
    --accent: hsl(255 90% 80%);
    --on-accent: hsl(230 34% 12%);
    --focus: hsl(255 92% 80%);
    --spk-0: #64b5f6;
    --spk-1: #ef9a9a;
    --spk-2: #81c784;
    --spk-3: #ce93d8;
    --spk-4: #ffb74d;
    --spk-5: #f48fb1;
    --danger: #ef9a9a;
  }
}

/* Toggle override (theme-init.js sets data-theme + color-scheme on <html>):
   user's explicit choice always wins over the OS preference. */
:root[data-theme="dark"] {
  --bg: hsl(230 18% 11%);
  --surface: hsl(230 16% 16%);
  --text: hsl(220 24% 92%);
  --muted: hsl(220 14% 66%);
  --border: hsl(230 12% 27%);
  --accent: hsl(255 90% 80%);
  --on-accent: hsl(230 34% 12%);
  --focus: hsl(255 92% 80%);
  --spk-0: #64b5f6;
  --spk-1: #ef9a9a;
  --spk-2: #81c784;
  --spk-3: #ce93d8;
  --spk-4: #ffb74d;
  --spk-5: #f48fb1;
}

/* Coarse pointers (touch) get larger hit targets — WCAG 2.2 target size. */
@media (pointer: coarse) {
  :root {
    --min-tap: 44px;
  }
}

/* ---- Reset (low-specificity) ------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

:where(body, h1, h2, h3, p, ul, ol, figure) {
  margin: 0;
}

:where(ul[class]) {
  padding: 0;
  list-style: none;
}

img,
audio {
  display: block;
  max-inline-size: 100%;
}

/* ---- Base --------------------------------------------------------------- */

/* Reserve the scrollbar gutter so content doesn't shift sideways when a page
   grows past one viewport and the scrollbar appears (no effect under overlay
   scrollbars; matters on classic Windows/Linux scrollbars). */
html {
  scrollbar-gutter: stable;
}

body {
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  /* Sticky footer without layout-thrash: column flex, main grows. */
  display: flex;
  flex-direction: column;
  min-block-size: 100vh;
  min-block-size: 100dvh;
}

:where(h1, h2, h3) {
  line-height: 1.15;
  text-wrap: balance;
}

h1 {
  font-size: var(--step-3);
}

h2 {
  font-size: var(--step-1);
}

p {
  text-wrap: pretty;
}

:where(main p, .show-notes) {
  margin-block-end: var(--space-s);
}

a {
  color: var(--accent);
}

a:hover {
  text-decoration: underline;
}

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--radius);
}

/* ---- A11y utilities ----------------------------------------------------- */

/* Skip link: visually hidden until focused (no motion). */
.skip-link:not(:focus) {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link:focus {
  position: absolute;
  inset-block-start: var(--space-2xs);
  inset-inline-start: var(--space-2xs);
  z-index: 10;
  padding: var(--space-2xs) var(--space-s);
  color: var(--on-accent);
  background: var(--accent);
  border-radius: var(--radius);
}

/* Visually hidden, but available to assistive tech (labels, headings). */
.sr-only {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
