
/*
 * Global stylesheet — element defaults, the Newsreader/Inter identity signature, link and
 * focus rules, layout utilities. Astro scoped <style> blocks are reserved for genuinely
 * component-local rules only (D-05/D-06). Everything here is driven by the :root tokens in
 * tokens.css — no bare hex values below this line.
 */

/* 1. Self-hosted variable fonts (D-07/D-08). Both families ship as a single variable woff2
   covering their full weight range — no italic faces are shipped (none exist in the design). */
@font-face {
  font-family: 'Newsreader';
  src: url('/fonts/newsreader-variable.woff2') format('woff2');
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
  font-optical-sizing: auto;
}

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-variable.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

/* 1b. Metric-matched fallback faces (A11Y-02, Phase 1 gate step 4).
 *
 * `font-display: swap` means a first-time visitor reads the fallback face until the webfont
 * arrives. Without these overrides the fallback sets text at a different average glyph width, so
 * the swap re-wraps paragraphs and visibly jumps the page. Measured cold-cache CLS before this
 * block existed: 0.0182 (`/`) and 0.0169 (`/about/`) at 1280px, 0.0391 (`/`) and 0.0878
 * (`/about/`) at 375px — the last of those close to the 0.1 "needs improvement" boundary, and
 * attributed by the browser to the footer tagline re-wrapping. With the block: 0.0002 / 0.0000 /
 * 0.0052 / 0.0000 respectively. These two faces re-declare the local fallbacks scaled to the
 * webfonts' own metrics so the fallback occupies the same space and the swap is invisible.
 *
 * The numbers were measured, not guessed: each value is
 *   size-adjust      = avgWidth(webfont)  / avgWidth(fallback)
 *   ascent-override  = ascent(webfont)  / size-adjust   (size-adjust scales overrides too)
 *   descent-override = descent(webfont) / size-adjust
 * taken from Chromium's own `TextMetrics` for a representative sentence rendered at 1000px in
 * each family. Georgia and Arial are the concrete targets because both ship on Windows and
 * macOS, and Liberation Sans (metric-compatible with Arial) stands in on Linux.
 * `line-gap-override: 0%` matches the webfonts, whose leading is supplied by the unitless
 * `--lh-*` line-height tokens rather than by font metrics.
 */
@font-face {
  font-family: 'Newsreader Fallback';
  src: local('Georgia'), local('Times New Roman');
  size-adjust: 100.73%;
  ascent-override: 72.97%;
  descent-override: 26.31%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Inter Fallback';
  src: local('Arial'), local('Liberation Sans'), local('Helvetica');
  size-adjust: 106.81%;
  ascent-override: 90.72%;
  descent-override: 22.56%;
  line-gap-override: 0%;
}

/* 2. Minimal reset */
*,
*::before,
*::after {
  box-sizing: border-box;
}

body,
h1,
h2,
h3,
h4,
h5,
h6,
p,
figure,
blockquote,
ul,
ol {
  margin: 0;
}

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

/* 3. Root/body defaults */
html {
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  text-wrap: pretty;
}

/* 4. The identity signature (D-22) — never scoped to a class; every heading, everywhere. */
h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--font-display);
  font-weight: 500;
  font-variant: small-caps;
  letter-spacing: 0.02em;
  line-height: var(--lh-heading);
  color: var(--sapphire);
  text-wrap: pretty;
}

h1 {
  font-size: var(--fs-h1);
}

h2 {
  font-size: var(--fs-h2);
}

h3 {
  font-size: var(--fs-h3);
}

/* 5. Paragraph wrapping (D-25) */
p {
  text-wrap: pretty;
}

/* 6. Global link rules (D-31) — links are never left browser-default blue. */
a,
a:visited {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  color: var(--accent-hover);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* 7. Focus (D-31) — focus rings must remain visible everywhere in this project.
   The contracted geometry (2px width, 2px offset) is unchanged; only the colour is
   surface-aware. Sapphire clears 3:1 on --paper but measures 1.27:1 on --sapphire-deep and
   1.69:1 on --night, so every dark surface switches to the light ring token instead. The
   selector is the surface, not the element, so anything dropped onto a dark band inherits the
   correct ring without a per-component override. */
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

/* Dark surfaces: the site footer (--sapphire-deep, present on every route) and any element
   opting into a dark band via .on-dark (--night / --sapphire-deep, Phase 2 hero onward). */
footer :focus-visible,
.on-dark :focus-visible,
.on-dark:focus-visible {
  outline-color: var(--focus-ring-dark);
}

/* `<main id="main" tabindex="-1">` is the skip link's target and is deliberately focusable so
   activating the link genuinely moves focus (see BaseLayout). Being focusable also makes it
   click-focusable, so guard the pointer case only: no ring when the user clicks into the page
   body, full ring preserved when focus arrives by keyboard (:focus-visible still matches, and
   the rule above is untouched). */
main[tabindex="-1"]:focus:not(:focus-visible) {
  outline: none;
}

/* 8. Motion (D-43) — only these three properties transition; nothing bounces, slides, or
   parallaxes. */
a,
button,
input,
textarea,
select {
  transition: color var(--transition), background-color var(--transition), border-color var(--transition);
}

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

/* 9. Layout utilities */
.content-column {
  max-width: var(--content-max);
  padding: 0 var(--content-pad);
  margin-left: auto;
  margin-right: auto;
}

.section {
  padding-block: var(--section-gap);
}

.editorial {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--editorial-gap);
}

.hairline-grid {
  display: grid;
  gap: 2px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.hairline-grid > * {
  background: var(--paper);
  padding: 26px 24px;
}

/* data-cols convention (D-28, plan 07): the desktop column count lives on the element, not
   hand-written per page, so the responsive collapse below has a single place to target. */
.hairline-grid[data-cols="2"] {
  grid-template-columns: repeat(2, 1fr);
}

.hairline-grid[data-cols="4"] {
  grid-template-columns: repeat(4, 1fr);
}

/* Plan 02-03 — the two grid wrappers the design system was missing. Both are wrappers only;
   neither restyles a component. */
.card-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--card-gap);
}

.band-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 56px;
  align-items: center;
}

.eyebrow {
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--accent);
}

.lead {
  font-family: var(--font-display);
  font-size: var(--fs-lead);
  font-weight: 400;
  font-variant: normal;
  letter-spacing: normal;
  line-height: var(--lh-lead);
  color: var(--sapphire);
  text-wrap: pretty;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The skip link must be fully offscreen until focused. Do NOT hide it with a negative `top`
   tied to a guessed height: the element inherits body's 17px/1.72 line box plus 12px padding
   and computes 53.23px tall, so `top: -40px` left a 13.2px sliver of sapphire painted over the
   header at z-index 100 on every page and every viewport. `translateY(-100%)` is measured
   against the element's own height, so it stays correct if the type scale, line-height, or
   padding ever change. */
.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  transform: translateY(-100%);
  z-index: 100;
  padding: 12px 20px;
  background: var(--sapphire);
  color: var(--paper);
  font-family: var(--font-body);
  font-weight: 600;
  text-decoration: none;
}

.skip-link:focus {
  transform: translateY(0);
}

/* 10. Responsive layer (D-38/D-39, RESP-01) — three contracted breakpoints, non-overlapping
   max-width queries at 1079px and 767px only. No min-width queries, no container queries, no
   fluid type scale — the handoff specifies fixed values per band so the built site stays
   verifiable against the approved comps. Body text (17px) is never touched by either query;
   the 16px floor is a hard constraint (D-39), not a target to shrink toward. */
@media (max-width: 1079px) {
  :root {
    /* Tighten vertical rhythm proportionally rather than leaving desktop-sized whitespace
       on a tablet viewport. */
    --section-gap: 72px;
  }

  .content-column {
    padding: 0 40px;
  }

  /* The eyebrow-left / content-right pattern stacks, eyebrow above. */
  .editorial {
    grid-template-columns: 1fr;
    gap: 24px;
  }

  /* Stat grid steps 4 -> 2. Uses the same specificity as the desktop rule so the later
     767px query below can still win on the same selector. */
  .hairline-grid[data-cols="4"] {
    grid-template-columns: repeat(2, 1fr);
  }

  /* .band-grid collapses here, one band above .card-grid's 767px query — two equal columns
     of prose at tablet width produce a measure of roughly 28 characters, too narrow to read
     comfortably, unlike the card grid's two ~490px-wide cards, which are fine at this width. */
  .band-grid {
    grid-template-columns: 1fr;
    gap: 40px;
  }
}

@media (max-width: 767px) {
  :root {
    --section-gap: 56px;
  }

  .content-column {
    padding: 0 24px;
  }

  /* Heading step-downs. Body stays at var(--fs-body) (17px) — do NOT touch it here; the
     handoff is explicit that body copy never shrinks, and D-39 sets a hard 16px floor. */
  h1 {
    font-size: 34px;
  }

  h2 {
    font-size: 28px;
  }

  h3 {
    font-size: 23px;
  }

  /* .lead is display type, not body copy, so it may step down. */
  .lead {
    font-size: 22px;
  }

  .editorial {
    gap: 20px;
  }

  /* Every hairline-grid collapses to a single column at phone width, regardless of its
     data-cols value (matched at equal specificity to the 1079px rule above so source order
     — this block runs later — decides the winner) or absence of one. */
  .hairline-grid,
  .hairline-grid[data-cols="2"],
  .hairline-grid[data-cols="4"] {
    grid-template-columns: 1fr;
  }

  /* .card-grid collapses here, not in the 1079px band above — two ~490px-wide cards at
     tablet width are fine per the handoff, which shows no tablet-specific collapse for them. */
  .card-grid {
    grid-template-columns: 1fr;
  }
}
