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

/* The browser's own [hidden] rule has specificity (0,1,0), and so does any
   class that sets display. Author styles win that tie, so a class like
   .radio-controls { display: flex } silently defeats el.hidden = true and the
   element stays painted while the code believes it is gone. Settle it here for
   every element rather than per component, since the next one would fail the
   same way and look like a JavaScript bug. */
[hidden] { display: none !important; }

html { scroll-padding-top: 5rem; }

body {
  margin: 0;
  background: var(--color-ink);
  color: var(--color-text-primary);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* Faint groove texture over the whole page so no area reads as flat void. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.03;
  background-image: repeating-radial-gradient(circle at 50% 40%, var(--color-text-primary) 0, var(--color-text-primary) 1px, transparent 1px, transparent 7px);
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.15;
  margin: 0 0 var(--space-2);
}
h1 { font-size: var(--fs-hero); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }

p { margin: 0 0 var(--space-2); color: var(--color-text-muted); }

a { color: var(--color-signal); text-decoration: none; }
a:hover { text-decoration: underline; }

img, canvas { max-width: 100%; display: block; }

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

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