/* ============================================================
   Anna Kemp — WEBSITE DESIGN SYSTEM
   02 / base.css — document reset, fonts, defaults.
   Import order: tokens.css → base.css → components.css
   ============================================================ */

/* ---------- Fonts. Self-hosted. ----------
   Was an @import from fonts.googleapis.com until 2026-08-27. Four reasons it
   is not any more, in the order they matter:

     1. An @import inside a stylesheet is a request the browser cannot even
        begin until that stylesheet has arrived and been parsed. It is the
        slowest way there is to load a font: two round trips to two hosts
        (googleapis for the CSS, gstatic for the files) chained behind a third.
     2. It made the privacy notice list Google as a processor, because a font
        request carries the visitor's IP to a third party. Nothing on this site
        needs that, and a notice with a row in it that did not have to be there
        is a notice nobody trusts.
     3. It blocked a Content-Security-Policy. Two of the three external origins
        on this site were these; DEPLOYMENT.md said a CSP was cheaper to write
        after this work than before it.
     4. Google Fonts is unreachable from the build environment, so every
        screenshot and every generated product mock had to work around it.

   Eleven faces, latin subset, 224KB in total — the exact set the browser was
   observed to resolve across all thirteen routes at 390px and 1280px, measured
   rather than guessed. Karla 700 and 800 and Karla italic are there for the
   Home Ed Collective system; nothing on the website layer uses them.

   Both families are OFL-1.1, which permits this. Files came from the
   @fontsource packages (karla 5.3.0, newsreader), which repackage the Google
   Fonts originals unmodified.

   font-display: swap on every face, which is what &display=swap did before.
   The two faces above the fold are preloaded in the head — see index.html.

   To add a weight: put the woff2 in /fonts, add a block here, and re-run
   tools/font-audit.mjs to confirm nothing else is missing. */

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 200;
  font-display: swap;
  src: url('/fonts/newsreader-latin-200-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('/fonts/newsreader-latin-300-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url('/fonts/newsreader-latin-300-italic.woff2') format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/newsreader-latin-400-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/newsreader-latin-400-italic.woff2') format('woff2');
}

@font-face {
  font-family: 'Karla';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/karla-latin-400-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Karla';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/karla-latin-400-italic.woff2') format('woff2');
}

@font-face {
  font-family: 'Karla';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/karla-latin-500-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Karla';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/karla-latin-600-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Karla';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/karla-latin-700-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Karla';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('/fonts/karla-latin-800-normal.woff2') format('woff2');
}

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

/* The `hidden` attribute must beat any component's own display value.
   Without this, [hidden] does nothing on .menu-drawer, .cluster, .btn,
   .action, .social-link, .hub-row, .footer-col or any grid — the drawer
   never closes and every config-gated link flashes before it is removed. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  /* A word that cannot wrap sets the width of everything around it. Nothing in
     the shipped copy does — every word of it is English and happens to break
     politely — but a visitor's email address echoed into a form message, a URL
     pasted into a paragraph, a German compound, or Thai (which has no spaces at
     all) is one unbreakable token. tools/hostile-audit.mjs injected each of
     those and the home page scrolled 364px sideways.

     `break-word`, deliberately, and NOT `anywhere`. The two look identical
     until intrinsic sizing is involved: `anywhere` counts toward min-content
     width, so it collapses a table column to one character and wraps a name
     that would have fitted — the exact bug `.t-code` hit on the privacy page's
     cookie table on 26 August, where `ak_consent` rendered as "ak_consen / t".
     `break-word` breaks only a word that genuinely does not fit in the box it
     has already been given, and leaves every measurement alone. */
  overflow-wrap: break-word;
  background: var(--color-page);
  color: var(--color-text-primary);
  font-family: var(--font-ui);
  font-size: var(--type-body);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 300; text-wrap: balance; }
p { text-wrap: pretty; }

ul, ol { margin: 0; padding: 0; }
li { list-style: none; }

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }

/* Links. Never browser blue: Anna's brand owns every link colour. */
a { color: var(--color-text-primary); text-decoration: none; }
a:hover { color: var(--color-brand); }
a:focus-visible,
button:focus-visible,
input:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

button { font: inherit; color: inherit; }
input, textarea, select { font: inherit; }

/* Anchor targets clear the sticky header. */
[id] { scroll-margin-top: var(--scroll-offset); }

/* Skip link — first focusable element in <body>. */
.skip-link {
  position: absolute; left: var(--space-4); top: calc(var(--space-4) * -4);
  z-index: var(--z-drawer);
  background: var(--color-surface-dark); color: var(--color-text-inverse);
  padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm);
  font-size: var(--type-body-sm);
  transition: top var(--hover-duration) ease;
}
.skip-link:focus { top: var(--space-4); color: var(--color-text-inverse); }

/* Screen-reader-only. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

::selection { background: var(--color-tint-mint); color: var(--color-text-primary); }
