/* =========================================================
   BASE — reset, document typography, layout primitives.
   No decoration here; that lives in components/sections.
========================================================= */

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

html{
  scroll-behavior:smooth;
  /* nav sits at the bottom, so anchors only need breathing room */
  scroll-padding-top:var(--sp-5);
  -webkit-text-size-adjust:100%;
  /* base colour lives on <html> so the fixed, negative-z-index
     .backdrop (a body child) can paint above it and still sit
     beneath every section's own content. */
  background:var(--c-bg);
}

body{
  margin:0;
  color:var(--c-text);
  font-family:var(--font-body);
  font-size:var(--fs-base);
  font-weight:400;
  line-height:var(--lh-body);
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  /* `clip`, not `hidden`: overflow-x:hidden makes this a scroll container,
     which breaks the position:sticky pin used by the zoom section.
     overflow-x:clip contains stray horizontal overflow without that side
     effect. */
  overflow-x:clip;
}

h1,h2,h3,h4{
  margin:0;
  font-family:var(--font-display);
  font-weight:600;
  line-height:var(--lh-tight);
  letter-spacing:var(--tracking-tight);
  text-wrap:balance;
}
h3,h4{ line-height:var(--lh-snug); letter-spacing:-0.02em; }
p{ margin:0; text-wrap:pretty; }
ul,ol,dl{ margin:0; padding:0; list-style:none; }
dd{ margin:0; }
img,svg,video{ display:block; max-width:100%; }
figure{ margin:0; }
blockquote{ margin:0; }

a{ color:inherit; text-decoration:none; }

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

::selection{ background:var(--c-accent); color:var(--c-on-accent); }

:focus-visible{
  outline:2px solid var(--c-accent);
  outline-offset:3px;
  border-radius:var(--radius-sm);
}

/* ---------- ambient backdrop ----------
   Fixed behind all content. Deep space with a faint starfield and a
   slow wash of accent light — ambient, never decorative. */
.backdrop{
  position:fixed;
  inset:0;
  z-index:-1;
  overflow:hidden;
  pointer-events:none;
}
.backdrop__stars{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
}
.backdrop__nebula{
  position:absolute;
  inset:0;
  background:
    radial-gradient(ellipse 1100px 640px at 15% -10%, rgba(79,140,255,.14), transparent 66%),
    radial-gradient(ellipse 820px 560px at 88% 18%, rgba(138,92,255,.10), transparent 68%),
    radial-gradient(ellipse 760px 520px at 55% 108%, rgba(73,214,255,.07), transparent 70%);
}

/* ---------- layout primitives ---------- */
.shell{
  width:100%;
  max-width:var(--shell-max);
  margin-inline:auto;
  padding-inline:var(--shell-pad);
}

/* 12-column grid, available where a section wants real column control */
.grid12{
  display:grid;
  grid-template-columns:repeat(var(--grid-cols), minmax(0,1fr));
  gap:var(--grid-gap);
}

/* long-form text keeps a readable measure inside the wide shell */
.measure{ max-width:var(--measure); }

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

.skip-link{
  position:absolute;
  left:var(--sp-4);
  top:-100%;
  z-index:1000;
  padding:var(--sp-3) var(--sp-4);
  background:var(--c-accent);
  color:var(--c-on-accent);
  border-radius:var(--radius-pill);
  font-weight:600;
  transition:top var(--dur-fast) var(--ease-out);
}
.skip-link:focus{ top:var(--sp-4); }

/* ---------- prose ---------- */
.prose p + p{ margin-top:var(--sp-5); }
.prose strong{ color:var(--c-text); font-weight:600; }
.lede{
  font-size:var(--fs-md);
  color:var(--c-text-muted);
  letter-spacing:-0.01em;
}

.eyebrow{
  font-family:var(--font-mono);
  font-size:var(--fs-xs);
  font-weight:500;
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--c-text-faint);
}

/* ---------- scroll reveal ----------
   Blur-to-sharp: content resolves into focus rather than merely sliding.
   Scoped to .js so a scripting failure can never leave the page blank;
   reveal.js also runs a timeout fallback. */
.js .reveal{
  opacity:0;
  transform:translateY(26px);
  filter:blur(14px);
  transition:opacity var(--dur-slow) var(--ease-out),
             transform var(--dur-slow) var(--ease-out),
             filter var(--dur-slow) var(--ease-out);
}
.js .reveal.is-visible{
  opacity:1;
  transform:none;
  filter:blur(0);
}

@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
  .js .reveal{ opacity:1; transform:none; filter:none; }
}
