/* Reset + document defaults. */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

/* Native cross-page fade instead of a hard cut, on browsers that support it (currently Chromium/
   Safari; Firefox just keeps its normal navigation - progressive enhancement, zero JS, zero cost
   where unsupported). docs/DESIGN-SYSTEM.md §6. */
@view-transition {
  navigation: auto;
}
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--fs-2);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  position: relative;
}
/* Paper grain: one cheap SVG turbulence layer on the page ground only (docs/DESIGN-SYSTEM.md §2). */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0.35;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.2 0 0 0 0 0.16 0 0 0 0 0.12 0 0 0 0.16 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}
/* Lifts the theme's own top-level sections above the paper-grain layer (body::before, z-index: 0)
   without a blanket `body > *` rule - that used to also catch third-party markup appended straight
   to <body> by other plugins via wp_footer() (a cookie-consent banner, a chat widget, etc.), forcing
   it into a z-index:1 stacking context and trapping its own much-higher internal z-index behind
   .primary-nav's z-index:50/.sub-menu's z-index:60 (production trial finding, 2026-09-14) - a
   plugin's own overlay must be free to stack itself however it needs to. */
.skip-links, .topbar, .masthead, .primary-nav, .site-main, .site-footer { position: relative; z-index: 1; }

img, svg, video { max-width: 100%; height: auto; display: block; }
h1, h2, h3, h4 { margin: 0; font-family: var(--font-display); font-weight: 700; line-height: var(--lh-snug); letter-spacing: -0.005em; }
h1 { font-size: var(--fs-6); }
h2 { font-size: var(--fs-5); }
h3 { font-size: var(--fs-4); }
h4 { font-size: var(--fs-3); }
p { margin: 0 0 var(--space-4); }
a { color: inherit; text-decoration-thickness: 0.08em; text-underline-offset: 0.12em; }
a:hover { color: var(--red); }
ul, ol { margin: 0; padding: 0; }
ul[role="list"], nav ul { list-style: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }
:focus-visible { outline: 3px solid var(--red); outline-offset: 2px; }
.visually-hidden { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.skip-link { position: absolute; left: var(--space-4); top: -100px; background: var(--ink); color: var(--paper-2); padding: var(--space-2) var(--space-4); z-index: 100; }
.skip-link:focus { top: var(--space-4); }

/* Display type utilities */
.display { font-family: var(--font-display); text-transform: uppercase; line-height: var(--lh-tight); font-weight: 700; }
.caps { font-family: var(--font-display); text-transform: uppercase; letter-spacing: var(--tracking-caps); font-weight: 600; font-size: var(--fs-0); }
.mark { font-family: var(--font-mark); font-weight: 400; text-transform: none; letter-spacing: 0; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* Scroll-driven reveal: a section quietly rises/fades in as it enters the viewport (native CSS,
   no JS/library, ~0 KB). Opt-in per section (.reveal) rather than global, so above-the-fold
   content (hero/rail) never risks a flash-of-invisible on a slow first paint. Browsers without
   scroll-driven animations (docs/CACHING-AND-PERFORMANCE.md notes graceful degradation
   throughout) just show the section normally - no @supports fallback needed since the un-animated
   state (no timeline = no animation runs) is simply "always visible", which is correct either way.
   Reduced-motion is already covered by the blanket animation:none rule above. */
@supports (animation-timeline: view()) {
  .reveal {
    animation: gg-reveal-in linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 30%;
  }
  @keyframes gg-reveal-in {
    from { opacity: 0; transform: translateY(1.25rem); }
    to { opacity: 1; transform: translateY(0); }
  }
}
