/* ════════════════════════════════════════════════════════════════════
   NexFlow · Base styles · resets + typography
   ════════════════════════════════════════════════════════════════════ */

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

html {
  scroll-behavior: smooth;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  background: var(--bg-0);
}

body {
  background: var(--bg-0);
  color: var(--fg-0);
  font-family: var(--font-sans);
  font-feature-settings: "kern", "liga", "calt";
  font-weight: 400;
  line-height: var(--lh-base);
  overflow-x: hidden;
  min-height: 100vh;
}

/* ── Legibility containment (v10) ─────────────────────────────────────
   The full-viewport WebGL particle/cloud wash was both the strongest
   "generic AI page" tell and the reason text over the hero was hard to
   read. It is retired: the canvas host is hidden and the engine early-
   outs when it sees the host is display:none (engine/three-scene.js), so
   there is no idle render cost. The "alive" feeling now comes from the
   CONTAINED animations (hero workflow card, live ledger/terminal, the
   per-service demos) which all sit inside solid bordered panels.
   Every content surface is solid warm paper, so text never sits over
   motion. */
#three-stage, #three-fallback { display: none !important; }

/* Paper grain · a fixed, fine SVG noise specked above the 3D canvas
   but below content. Stops the large light surfaces from reading as
   sterile screen-flat; gives the page a tactile editorial feel.
   z-index sits between --z-3d (1) and --z-content (10). */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  opacity: .035;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 1 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}
@media (prefers-reduced-motion: reduce) {
  /* grain stays — it's static, not motion — but we kill any blend
     surprises by ensuring it can't be over-layered with animations. */
  body::before { will-change: auto; }
}

::selection { background: rgba(210,85,43,.20); color: var(--fg-0); }

::-webkit-scrollbar { width: 7px; height: 7px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(14,124,99,.30); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: rgba(14,124,99,.48); }

img, svg, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; border: 0; background: none; cursor: pointer; color: inherit; padding: 0; }
input, textarea { font: inherit; color: inherit; }

/* ── Typography scale ─────────────────────────────────────────────── */
.t-display {
  font-family: var(--font-serif); font-weight: 700;
  font-size: var(--t-display); line-height: var(--lh-display);
  letter-spacing: var(--tr-display);
}
/* Emphasis on display / heading copy. Bricolage Grotesque has no true
   italic, so the editorial "moment" is carried by the brand teal on the
   emphasised word rather than a synthesised slant. */
.t-display em { font-style: normal; color: var(--brand); }

.t-h1 {
  font-family: var(--font-serif); font-weight: 700;
  font-size: var(--t-h1); line-height: var(--lh-tight);
  letter-spacing: var(--tr-h);
}
.t-h1 em, .t-h2 em, .t-h3 em { font-style: normal; color: var(--brand); }

.t-h2 {
  font-family: var(--font-serif); font-weight: 700;
  font-size: var(--t-h2); line-height: var(--lh-tight);
  letter-spacing: var(--tr-h);
}
.t-h3 {
  font-family: var(--font-serif); font-weight: 600;
  font-size: var(--t-h3); line-height: var(--lh-snug);
  letter-spacing: -.012em;
}
.t-h4 {
  font-family: var(--font-sans); font-weight: 600;
  font-size: var(--t-h4); line-height: var(--lh-snug);
  letter-spacing: var(--tr-body);
}
.t-lead {
  font-size: var(--t-lead);
  color: var(--fg-1); line-height: var(--lh-base);
  max-width: 60ch;
}
.t-body { font-size: var(--t-body); color: var(--fg-1); line-height: var(--lh-loose); }
.t-small { font-size: var(--t-small); color: var(--fg-2); line-height: var(--lh-base); }
.t-mono {
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  letter-spacing: .04em;
}

/* eyebrow · editorial label with a clay tick-rule (v10)
   Replaces the mono-uppercase-with-pulsing-dot pattern — the single
   clearest "generic AI marketing page" tell. Now a Hanken label in the
   brand-adjacent clay, led by a short solid rule. The .dot element that
   older markup nests inside is hidden outright. */
.eyebrow {
  font-family: var(--font-sans);
  font-size: var(--t-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--clay);
  display: inline-flex; align-items: center; gap: 11px;
}
.eyebrow::before {
  content: ''; display: inline-block;
  width: 22px; height: 2px; border-radius: 2px;
  background: var(--clay); flex-shrink: 0;
}
.eyebrow .dot { display: none; }
.eyebrow.on-dark { color: #E8825C; }
.eyebrow.on-dark::before { background: #E8825C; }

@keyframes pulse {
  /* Retained only for the live demo's simulated activity indicators
     (those depict a process actually running). The default UI no longer
     pulses anything. */
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: .55; transform: scale(.78); }
}

/* ── Link styles ──────────────────────────────────────────────────── */
.link-underline {
  background-image: linear-gradient(currentColor, currentColor);
  background-position: 0% 100%;
  background-repeat: no-repeat;
  background-size: 100% 1px;
  transition: background-size var(--d-base) var(--ease-out);
}
.link-underline:hover { background-size: 100% 2px; }

/* ── Focus visible (a11y) ─────────────────────────────────────────── */
:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 2px; }

/* ── Tabular nums on surfaces that show changing numbers ─────────── */
/* Prevents digit width jitter when counters tick (live event stream,
   ROI calculator, hero metrics, stat grid, price amounts). */
.hero-metric-val,
.stat-grid .val,
.price-card .amt,
.roi-amount,
.tick,
.term { font-variant-numeric: tabular-nums; }

/* ── Skip-to-content link · screen-reader only until focused ─────── */
.nf-skip {
  position: fixed; top: 8px; left: 8px;
  z-index: 9999;
  padding: 10px 14px;
  background: var(--fg-0); color: var(--fg-inv);
  border-radius: var(--r-s);
  font-size: 14px; font-weight: 500;
  transform: translateY(-200%);
  transition: transform var(--d-base) var(--ease-out);
}
.nf-skip:focus { transform: translateY(0); outline: 2px solid var(--brand); outline-offset: 2px; }

/* ── Reduced motion · reveals should not translate ─────────────── */
@media (prefers-reduced-motion: reduce) {
  .reveal,
  .reveal-stagger > * { transform: none !important; }
}
