/**
 * Design tokens — the single source of truth for the article experience.
 *
 * MOBILE-FIRST: every scale below is authored at its phone value and grows with
 * the viewport through `clamp()`, so there is one definition per token instead of
 * a base value plus a pile of media-query overrides. Only genuinely structural
 * changes (a column count, a stacked vs. side-by-side layout) use media queries.
 *
 * The scales are deliberately small. A short scale is what keeps a page looking
 * proportional: if a size or a gap is not on the scale, it does not get used.
 */

:root {
  color-scheme: dark;

  /* ---- palette: neutral near-black surfaces, one blue accent ---- */
  --blue: #2f6fd0;
  --blue-hover: #3d7dd9;
  --blue-bright: #6aa3e0;
  --blue-dim: rgba(47, 111, 208, 0.12);
  --blue-dim-2: rgba(47, 111, 208, 0.18);
  --blue-line: rgba(47, 111, 208, 0.28);
  --grad-blue: linear-gradient(135deg, #7fb0e8 0%, #2f6fd0 100%);

  --bg: #07080a;
  --bg-raised: #0b0c0f;
  --surface: #0f1013;
  --surface-2: #15171b;
  --line: #22242a;
  --line-soft: #16171c;

  /* Four-step neutral ramp: bright for headings, then body, secondary, faint. */
  --text-bright: #f5f6f8;
  --text: #dee1e6;
  --text-2: #9aa0aa;
  --text-3: #6b7078;
  --pos: #46b98a;
  --warn: #d3a35a;
  --danger: #e0736b;

  /* ---- typography ----------------------------------------------------
     One system-sans family. The heading/body hierarchy comes from size,
     weight, and measure — never from a second typeface. */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

  /* Fluid type scale (phone → desktop). Nine steps, no ad-hoc sizes. */
  --fs-2xs: 0.6875rem;                          /* 11px  — badges, dot labels  */
  --fs-xs: clamp(0.75rem, 0.73rem + 0.1vw, 0.8125rem);      /* 12 → 13 */
  --fs-sm: clamp(0.8125rem, 0.79rem + 0.12vw, 0.875rem);    /* 13 → 14 */
  --fs-md: clamp(0.9375rem, 0.91rem + 0.14vw, 1rem);        /* 15 → 16 */
  --fs-base: clamp(1rem, 0.97rem + 0.16vw, 1.0625rem);      /* 16 → 17 — body */
  --fs-lg: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);       /* 17 → 19 — lead */
  --fs-xl: clamp(1.1875rem, 1.1rem + 0.4vw, 1.375rem);      /* 19 → 22 — h3   */
  --fs-2xl: clamp(1.375rem, 1.22rem + 0.75vw, 1.75rem);     /* 22 → 28 — h2   */
  --fs-3xl: clamp(1.625rem, 1.35rem + 1.4vw, 2.25rem);      /* 26 → 36 — h1   */
  --fs-4xl: clamp(2rem, 1.55rem + 2.3vw, 3.25rem);          /* 32 → 52 — hero */

  --lh-tight: 1.14;
  --lh-snug: 1.32;
  --lh-normal: 1.5;
  --lh-relaxed: 1.72;   /* long-form reading */

  --fw-normal: 400;
  --fw-medium: 550;
  --fw-semi: 650;
  --fw-bold: 750;
  --fw-black: 820;

  --track-tight: -0.02em;
  --track-normal: 0;
  --track-wide: 0.08em;
  --track-caps: 0.12em;

  /* ---- spacing: a 4px-based scale used for every gap and pad ---- */
  --sp-1: 0.25rem;   /*  4 */
  --sp-2: 0.5rem;    /*  8 */
  --sp-3: 0.75rem;   /* 12 */
  --sp-4: 1rem;      /* 16 */
  --sp-5: 1.25rem;   /* 20 */
  --sp-6: 1.5rem;    /* 24 */
  --sp-8: 2rem;      /* 32 */
  --sp-10: 2.5rem;   /* 40 */
  --sp-12: 3rem;     /* 48 */
  --sp-16: 4rem;     /* 64 */

  /* Rhythm between stacked blocks, and inner card padding: both grow with the
     viewport so a phone never wastes space and a desktop never feels cramped. */
  --stack: clamp(0.875rem, 0.6rem + 1.4vw, 1.5rem);
  --pad-card: clamp(1.125rem, 0.8rem + 1.6vw, 2rem);
  --gutter: clamp(1rem, 0.4rem + 3vw, 2.5rem);

  /* ---- containers ---- */
  --w-reading: 45rem;   /* 720px — long-form measure on phone and tablet */
  --w-wide: 71rem;      /* 1136px — list grids, galleries */

  /* ---- glass ----
     One material for everything that floats above the article — the topbar
     pill and the sticky "tanya AI" card. Kept in tokens so the two can never
     drift apart: change the glass here and both surfaces change together. */
  --glass-bg: rgba(11, 12, 15, 0.82);
  --glass-blur: saturate(150%) blur(16px);

  /* ---- shape + depth ----
     Shadows are pure black elevation — never a coloured glow. */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 20px;
  --r-pill: 999px;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.45);
  --shadow-md: 0 12px 32px -8px rgba(0, 0, 0, 0.5);
  --shadow-pop: 0 24px 60px rgba(0, 0, 0, 0.5);

  /* Hairline highlight on the top edge of raised surfaces. */
  --inset-top: inset 0 1px 0 rgba(255, 255, 255, 0.04);

  /* ---- motion ---- */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 0.16s;
  --dur: 0.24s;
  --dur-slow: 0.4s;

  /* Minimum comfortable hit area for anything interactive. */
  --tap: 44px;

  --z-sticky: 40;
  --z-pop: 60;
  --z-modal: 80;
}

/**
 * The desktop reading measure.
 *
 * A phone reads at 45rem minus gutters; a desktop has room to spare, and an
 * 800px column floating in a 1440px window reads as cramped rather than
 * focused — the void margins dominate the page. From 64rem up the measure
 * grows to 56rem, so the article uses the width a desktop actually has while
 * the type stays the same. This is a structural change (the column itself
 * changes width), so it is a media query, not a clamp.
 */
@media (min-width: 64rem) {
  :root {
    --w-reading: 56rem;   /* 896px — desktop long-form measure */
  }
}

/**
 * Reduced motion: entrance animations collapse to their final state rather than
 * being merely shortened, so nothing moves, fades, or counts up. The JS side
 * honours the same query (see lib/motion.ts) so observers are never even created.
 */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 0.01ms;
    --dur: 0.01ms;
    --dur-slow: 0.01ms;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
