:root {
  /* Colors — the four tokens below are the actual configurable palette
     (light defaults here; dark overrides in the [data-theme='dark'] block),
     driven at runtime by settings.theme.{light,dark} via js/theme.js. Every
     other --color-* token is derived from these four with color-mix() so a
     custom palette picked in the macOS app always stays internally
     coherent instead of needing every shade configured by hand. */
  --color-bg: #ffffff;
  --color-text: #0a0a0a;
  --color-accent: #3effa3;
  --color-border: #e2e2e2;

  --color-bg-elevated: color-mix(in srgb, var(--color-bg) 96%, var(--color-text));
  --color-bg-elevated-2: color-mix(in srgb, var(--color-bg) 92%, var(--color-text));
  --color-border-strong: color-mix(in srgb, var(--color-border) 65%, var(--color-text) 35%);
  --color-text-dim: color-mix(in srgb, var(--color-text) 70%, var(--color-bg) 30%);
  /* 60/40 (not the visually-tidier 50/50) so small text using this token —
     nav step numbers, blog date labels, the footer copyright line — clears
     WCAG AA's 4.5:1 contrast minimum (50/50 only reached ~3.7:1). */
  --color-text-faint: color-mix(in srgb, var(--color-text) 60%, var(--color-bg) 40%);
  --color-accent-dim: color-mix(in srgb, var(--color-accent) 70%, black);
  --color-accent-glow: color-mix(in srgb, var(--color-accent-dim) 25%, transparent);

  /* Translucent "glass" panels (floating nav pill, mode switch, mobile nav
     overlay) — these sit on top of arbitrary page content so they need
     their own light/dark-appropriate translucent fill rather than a solid
     --color-bg, which would look like an opaque box instead of a blur. */
  --color-surface-glass: rgba(255, 255, 255, 0.85);
  --color-surface-glass-strong: rgba(255, 255, 255, 0.98);

  /* Type */
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  --fs-xs: 0.75rem;
  --fs-sm: 0.875rem;
  --fs-base: 1rem;
  --fs-md: 1.125rem;
  --fs-lg: 1.5rem;
  --fs-xl: 2rem;
  --fs-2xl: clamp(2.5rem, 6vw, 4.5rem);
  --fs-3xl: clamp(3.25rem, 10vw, 8rem);

  /* Spacing */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-24: 6rem;
  --space-32: 8rem;

  --section-padding-y: clamp(5rem, 12vw, 9rem);
  --page-margin-x: clamp(1.25rem, 5vw, 4rem);
  --max-width: 1280px;

  /* Motion */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --duration-fast: 0.2s;
  --duration-base: 0.4s;
  --duration-slow: 0.8s;

  --radius-sm: 4px;
  --radius-md: 10px;
  --radius-lg: 20px;
  --radius-xl: 28px;
  --radius-full: 999px;

  --z-nav: 100;
  --z-mode-switch: 200;
  --z-overlay: 300;
}

/* Dark defaults, used until settings.theme.dark overrides them at runtime
   (js/theme.js sets these same four custom properties inline once site
   settings load, same mechanism as the light values above). Kept in sync
   with the Swift-side ThemePalette defaults in SiteSettings.swift. */
:root[data-theme='dark'] {
  --color-bg: #0a0a0c;
  --color-text: #f5f5f5;
  --color-accent: #3effa3;
  --color-border: #2a2a30;

  --color-surface-glass: rgba(20, 20, 24, 0.85);
  --color-surface-glass-strong: rgba(14, 14, 18, 0.98);
}
