/* ==========================================================================
   NaiGrowth — Base
   Reset, typography, layout primitives, atmosphere and accessibility.
   ========================================================================== */

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

/* Scrolling is the browser's job. scroll-padding-top keeps an anchored
   section clear of the fixed bar, and scroll-behavior gives the jump its
   easing, both without a line of JS between the finger and the page. */
html {
  -webkit-text-size-adjust: 100%;

  /* Deliberately NOT `smooth`.

     scroll-behavior applies to every scroll of this box, including the ones
     the browser starts on its own: scroll restoration after a load or a
     reload, and scrolls caused by focus moving. With `smooth` those stop
     being instant and become a visible glide, so a reader who starts
     scrolling while the page is still settling watches it slide back toward
     the top under them. That is the "it glitches and goes back up" report,
     and it is invisible to a test that waits for the page to finish loading
     before it scrolls, which is why it survived two attempts to find it.

     Anchor clicks still animate. That is done from a click handler in
     js/modules/ui.js, which only ever runs on a deliberate press and never
     touches the wheel. */
  scroll-behavior: auto;
  scroll-padding-top: 6rem;
  /* `clip`, never `hidden`. overflow-x:hidden turns the element into a scroll
     container, so anything focused or anchored inside it can shunt the page
     and snap the position back toward the top. `clip` cuts the overflow off
     and can never be scrolled, which is all this was ever meant to do. */
  overflow-x: clip;

  /* A two-finger trackpad scroll is never purely vertical: there is always a
     few pixels of horizontal drift in the gesture. This page has nothing to
     scroll sideways, so every one of those pixels becomes horizontal
     OVERSCROLL, and the browser's default action for that is the
     swipe-to-go-back navigation gesture. Scrolling down a long page would
     occasionally start navigating back instead, which lands you at the top.

     It got easier to trigger when overflow-x moved from `hidden` to `clip`:
     `hidden` made the element a scroll container, which quietly absorbed the
     horizontal delta, and `clip` correctly does not.

     Only the x axis is pinned. Vertical overscroll stays `auto` so pull to
     refresh and the usual rubber band still work. */
  overscroll-behavior-x: none;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  min-height: 100vh;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  transition: background-color var(--t-med) var(--ease-out), color var(--t-med) var(--ease-out);
}

/* A band that stays dark in either theme — it paints its own ground so the
   light page does not show through behind a translucent section. */
.on-dark {
  background-color: var(--hero-bg);
  color: var(--text);
}

/* Theme switching should feel like a dimmer, not a page reload. Transitions
   are suppressed for one frame while the attribute flips the other way. */
html.theme-switching *,
html.theme-switching *::before,
html.theme-switching *::after {
  transition: none !important;
}

/* --- Atmosphere ----------------------------------------------------------
   Two fixed, non-interactive layers sit above the WebGL canvas and below the
   content: a film grain and a vignette. They give the flat dark ground depth
   without costing a repaint — both are static and GPU-composited. */
body::before,
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
}

body::before {
  /* Grain. An inline SVG turbulence keeps it to zero extra requests. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.42'/%3E%3C/svg%3E");
  opacity: var(--grain-opacity);
  mix-blend-mode: var(--grain-blend);
}

body::after {
  background: var(--vignette);
}

/* --- Typography ---------------------------------------------------------- */

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: var(--lh-snug);
  letter-spacing: var(--track-h3);
  text-wrap: balance;
}

h1 {
  font-size: var(--t-hero);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-hero);
  font-weight: 600;
}

h2 {
  font-size: var(--t-h2);
  line-height: 1.08;
  letter-spacing: var(--track-h2);
}

h3 {
  font-size: var(--t-h3);
  letter-spacing: var(--track-h3);
}

h4 {
  font-size: var(--t-h4);
  letter-spacing: -0.012em;
}

p {
  text-wrap: pretty;
}

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

ul,
ol {
  list-style: none;
}

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

img {
  height: auto;
}

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

button {
  cursor: pointer;
}

strong,
b {
  font-weight: 650;
  color: var(--text-strong);
}

::selection {
  background: rgba(139, 92, 246, 0.42);
  color: var(--text-strong);
}

/* --- Layout primitives --------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* --section-y is the gap BETWEEN two sections, not the padding of one. Each
   section contributes a little under half of it, so neighbours sum to roughly
   one gap instead of stacking two full ones — which on a light ground read as
   a page that had run out of content. */
.section {
  position: relative;
  z-index: var(--z-content);
  padding-block: calc(var(--section-y) * 0.62);
}

/* A band owns its space: it paints a ground, so it needs the full measure. */
.section--band {
  padding-block: var(--section-y);
}

/* For a section that is one element with no heading — the stats strip. */
.section--tight {
  padding-block: calc(var(--section-y) * 0.32);
}

.stack {
  display: flex;
  flex-direction: column;
}

.row {
  display: flex;
  align-items: center;
}

.grid {
  display: grid;
}

.prose {
  max-width: var(--maxw-prose);
  color: var(--text-dim);
  font-size: var(--t-lead);
}

/* --- Shared text atoms --------------------------------------------------- */

/* Labels are mono. Tracking stays moderate — the very wide letter-spacing
   that used to signal "premium" now just signals "2021". */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--text-muted);
}

.eyebrow::before {
  content: "";
  width: 22px;
  height: 1px;
  background: var(--accent-grad);
  flex: none;
}

.eyebrow--center {
  justify-content: center;
}

.eyebrow--center::before {
  display: none;
}

.grad-text {
  background: var(--text-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* Painted fallback for engines that drop background-clip on text. */
  -webkit-text-fill-color: transparent;
}

/* One accent phrase per screen, and a two-stop gradient rather than three —
   the long blue-violet-purple sweep across whole headlines is the single most
   dated thing on a marketing page. The stops are theme tokens: the bright
   tints that read on black are invisible on a light ground. */
.accent-text {
  background: var(--accent-text-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

/* Where the accent should read as emphasis rather than decoration. */
.accent-solid {
  color: var(--accent-ink);
}

.section-head {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  margin-bottom: clamp(2.5rem, 5vw, 4.5rem);
  max-width: 54rem;
}

.section-head p {
  color: var(--text-dim);
  font-size: var(--t-lead);
  max-width: 48rem;
}

/* --- Accessibility ------------------------------------------------------- */

.visually-hidden {
  position: absolute !important;
  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;
}

.skip-link {
  position: fixed;
  top: 0;
  left: var(--s-4);
  z-index: 200;
  padding: var(--s-3) var(--s-5);
  /* Deeper than --violet: white on #8b5cf6 measures 4.2:1, under AA. */
  background: #6d28d9;
  color: #fff;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  font-weight: 600;
  /* Moved by transform rather than `top`, so it is reliably off-screen before
     focus and lands in one composited step after it. */
  transform: translateY(-110%);
  transition: transform var(--t-fast) var(--ease-out);
}

/* :focus as well as :focus-visible — some engines withhold :focus-visible from
   a programmatically focused skip link, which is exactly how screen readers
   reach it. */
.skip-link:focus,
.skip-link:focus-visible {
  transform: translateY(0);
}

:focus-visible {
  outline: 2px solid var(--blue-bright);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Scroll targets receive focus programmatically so keyboard users land inside
   the section they jumped to. They are not controls, so they should not draw
   a focus ring around a whole band of the page. */
main:focus,
section:focus,
[tabindex="-1"]:focus {
  outline: none;
}

/* Every motion in this build is additive polish, never the only way to read
   the page — so honouring the OS setting costs nothing in comprehension. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}
