/* ============================================================
   F2F WEB STANDARD — base.css
   Reset + document base + grain + shared utilities.
   Layer order: tokens.css → base.css → components.css → page css
   ============================================================ */

*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto!important}

body{
  font-family:var(--font-sans);
  font-size:var(--step-0);
  line-height:var(--lead-body);
  background:var(--paper);
  color:var(--ink);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}

::selection{background:var(--accent);color:#fff}

img,svg,video{display:block;max-width:100%}
a{color:inherit;text-decoration-color:var(--accent);text-underline-offset:.18em}
a:hover{text-decoration-color:currentColor}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:2px}

/* — film grain over large flat fields (C5). One fixed overlay on
     <body class="grain">; overlay blend reads on light AND dark. — */
.grain::after{
  content:"";position:fixed;inset:0;z-index:90;pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
  opacity:.07;mix-blend-mode:overlay;
}

/* — layout primitives — */
.wrap{max-width:var(--grid-max);margin-inline:auto;padding-inline:var(--gutter)}
.measure{max-width:var(--measure)}
section{padding-block:var(--space-section)}

/* — type utilities — */
.display{
  font-family:var(--font-display);
  font-weight:var(--w-display);font-variation-settings:"opsz" 144,"SOFT" 0,"WONK" 1;
  letter-spacing:var(--track-display);line-height:var(--lead-display);
}
.display em{font-style:italic;font-weight:var(--w-display-em);color:var(--accent)}
.eyebrow{
  font-family:var(--font-grotesk);font-size:var(--step--1);font-weight:500;
  letter-spacing:var(--track-label);text-transform:uppercase;color:var(--accent-text);
  display:flex;align-items:center;gap:.75em;
}
.eyebrow::before{content:"";width:2.2em;height:1px;background:var(--accent)}
.lede{font-size:var(--step-1);line-height:var(--lead-snug);color:var(--ink-soft);max-width:var(--measure)}
.note{font-size:var(--step--1);line-height:var(--lead-body);color:var(--muted);max-width:var(--measure)}
.small{font-size:var(--step--1);color:var(--muted)}
.num{font-family:var(--font-grotesk);font-variant-numeric:tabular-nums}

/* — reveal initial states are set by JS only (M5);
     no permanent will-change: the motion layer clears its own props — */

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

@media (max-width:680px){ .grain::after{opacity:.04} }
