/* ============================================================
   NORLAN SOLUTIONS — nordlys design system (concept mockups)
   Dark-only. Canvas #06181F. Aurora ramp rationed.
   ============================================================ */

@font-face {
  font-family: 'Michroma';
  src: url('/assets/fonts/Michroma-Regular.woff2') format('woff2');
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: 'Schibsted Grotesk';
  src: url('/assets/fonts/SchibstedGrotesk-Variable.woff2') format('woff2');
  font-weight: 400 900; font-display: swap;
}
/* 'Schibsted Grotesk Static' er fjernet. Den sto som reserve etter den
   variable fila i --font-ui, og Chrome hentet den derfor på hver kalde last
   mens den variable var underveis — 47 kB, ukomprimert, den tyngste enkeltfila
   på siden. CDPs CSS.getPlatformFontsForNode viser at den tegnet NULL glyfer:
   den variable fila vant alltid. Reserven som faktisk brukes er den bredde-
   matchede lokale ('Schibsted Fallback'), som ikke koster en forespørsel. */
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('/assets/fonts/IBMPlexMono-Regular.woff2') format('woff2');
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('/assets/fonts/IBMPlexMono-Medium.woff2') format('woff2');
  font-weight: 500; font-display: swap;
}
/* Bredde-matchet reserveskrift (Schibsteds bredde ~0.90x Arial) — hindrer at
   overskrifter «hopper» smalere når web-fonten byttes inn (FOUT-reflow, iOS Safari). */
@font-face {
  font-family: 'Schibsted Fallback';
  src: local('Arial'), local('Helvetica Neue'), local('Liberation Sans'), local('Roboto');
  size-adjust: 90%;
  ascent-override: 97.7%;
  descent-override: 25.8%;
  line-gap-override: 0%;
}
/* Display-specific width-matched fallback. Measured: at 88px/640/-0.03em the real
   face is 1.1295x the width of the 90%-adjusted body fallback, so the headline
   reflowed ~118px when the font landed (CLS 0.0179 on a cold load, 0 warm) —
   the hard-refresh jank. Body text is only 2.5% off at 19px, so it keeps the
   90% face; large display type needs its own. */
@font-face {
  font-family: 'Schibsted Fallback Display';
  src: local('Arial'), local('Helvetica Neue'), local('Liberation Sans'), local('Roboto');
  size-adjust: 100%;
  ascent-override: 97.7%;
  descent-override: 25.8%;
  line-gap-override: 0%;
}

:root {
  /* canvas + ink */
  --bg: #06181F;
  --bg-lift: #081D26;
  --ink: #E9F2F2;
  --muted: #93ABB0;
  --ghost: #849AA0;         /* raised to clear WCAG AA (4.5:1) on --bg and --s2 */

  /* aurora ramp — rationed */
  --a1: #0F6E7C;
  --a2: #18B9C4;
  --a3: #3DE8A0;
  --aurora-grad: linear-gradient(135deg, var(--a1) 0%, var(--a2) 50%, var(--a3) 100%);
  /* button fill starts one stop brighter than --aurora-grad: the dark end of the
     full ramp grazed 4.16:1 under the label, this clears 4.5:1 across all of it */
  --aurora-grad-btn: linear-gradient(135deg, var(--a2) 0%, #29C9C0 45%, var(--a3) 100%);

  /* shift colours — day → night luminance ramp (one mapping everywhere) */
  --dag: var(--a3);      /* #3DE8A0 brightest */
  --kveld: var(--a2);    /* #18B9C4 */
  --natt: var(--a1);     /* #0F6E7C dimmest */
  --varsel: #D07A63;     /* the only non-ramp hue — violations / understaffing only */
  --varsel-soft: rgba(139, 47, 30, 0.35);
  --a2-tint: 127, 216, 205;  /* light a2 tint (rgb triplet) — hairline hovers / faint fills only */

  /* 4-step surface ladder (Raycast/Linear pattern) + hairlines as depth */
  --s1: #06181F;            /* canvas */
  --s2: #0A222C;            /* surface */
  --s3: #0D2934;            /* elevated */
  --s4: #11303C;            /* card top */
  --line: rgba(233, 242, 242, 0.08);
  --line-strong: rgba(233, 242, 242, 0.16);
  /* Hairlines stay hairlines for decoration, but WCAG 1.4.11 wants 3:1 from any
     border that is the ONLY thing saying "this is a control". 0.45 alpha measures
     3.98:1 on --s2 and 4.08:1 on --bg; 0.34 measures 2.86:1 and fails. */
  --line-control: rgba(233, 242, 242, 0.45);
  --surface: var(--s2);
  --surface-solid: var(--s2);

  /* exactly ONE atmospheric glow per section, reserved for the product frame */
  --glow-frame: 0 40px 110px -48px rgba(24, 185, 196, 0.30);

  /* type */
  --font-ui: 'Schibsted Grotesk', 'Schibsted Fallback', system-ui, sans-serif;
  --font-logo: 'Michroma', var(--font-ui);
  --font-mono: 'IBM Plex Mono', ui-monospace, monospace;

  /* geometry + motion */
  --maxw: 1180px;
  --pad: clamp(20px, 5vw, 64px);
  --r-s: 8px;
  --r-m: 14px;
  --r-btn: 10px;
  --nav-h: 68px;

  /* ---- motion scale ----------------------------------------------------
     Four durations, two curves. Pick from these; do not invent a fifth.
     Duration follows travel: an 8-16px nudge is --dur-fast, a full-height
     mask-wipe is --dur-slow. Entrances decelerate, exits accelerate. */
  --dur-instant: 120ms;   /* micro state flips */
  --dur-fast:    200ms;   /* hover / focus on controls */
  --dur-base:    320ms;   /* standard reveal, card lift */
  --dur-slow:    560ms;   /* headline wipes, large surfaces */
  --stagger:      48ms;   /* item(i) delay = i * this, capped at 6 */
  --ease:     cubic-bezier(0.22, 1, 0.36, 1);   /* entrances (kept: already sitewide) */
  --ease-in:  cubic-bezier(0.64, 0, 0.78, 0);   /* exits */
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; scrollbar-gutter: stable; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
/* film grain — one fixed layer, ~5% */
body::after {
  content: ''; position: fixed; inset: -50%; z-index: 60; pointer-events: none;
  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.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  /* Was mix-blend-mode: soft-light. A full-viewport blend layer has to re-read
     its backdrop, which forces a whole-screen re-composite on every animated
     frame — the same thing that pinned vardenturnus.no to 30fps. Plain opacity
     composites for free and, at this strength on a dark canvas, reads the same. */
  opacity: 0.10;
}
::selection { background: rgba(61, 232, 160, 0.25); }
img, svg, canvas { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; }
.wrap { max-width: var(--maxw); margin: 0 auto; padding-inline: var(--pad); }
/* ---------- typography ---------- */
.eyebrow {
  font-family: var(--font-logo);
  font-size: 11px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--a2);
  display: flex; align-items: center; gap: 14px;
  /* the flanking rules plus tracked-out caps overran 320px viewports */
  flex-wrap: wrap; row-gap: 6px; min-width: 0;
  /* Reserve the second line rather than gain one when Michroma arrives.
     --font-logo is Michroma, a wide geometric face: "Grunnlegger, Norlan
     Solutions" measures 393px in it against 293px in the local fallback, a 34 %
     jump. On a phone there are only 280-331px of text width once the 26px rule
     and its 14px gap are subtracted, so the fallback fits on one line and
     Michroma cannot — the label gained a line ~1.2s into every mobile load and
     pushed the whole page down (CLS 0.016 on /daniel-norlan, the only non-zero
     page left). It is not fixable by tightening: Michroma's bare glyphs alone
     need 291px at 11px, so even zero tracking overflows a 360px viewport.
     min-height holds both states at the two-line box instead. */
}
.eyebrow::before {
  content: ''; width: 26px; height: 1px;
  background: rgba(24, 185, 196, 0.5);
  flex: none;
}
.eyebrow--center { justify-content: center; }
.eyebrow--center::after {
  content: ''; width: 26px; height: 1px; background: rgba(24, 185, 196, 0.5); flex: none;
}
.display {
  font-family: 'Schibsted Grotesk', 'Schibsted Fallback Display', system-ui, sans-serif;
  font-weight: 640;
  font-size: clamp(2.6rem, 7.2vw, 5.6rem);
  line-height: 1.02;
  letter-spacing: -0.022em;
  text-wrap: balance;
  /* Norwegian compounds get long: "Personvernerklæring" alone is wider than a
     320px column and was pushing the document to 347px (WCAG 1.4.10). */
  overflow-wrap: break-word;
}
h2.display { font-size: clamp(1.9rem, 3.6vw, 3.1rem); line-height: 1.08; }
.lede {
  font-size: clamp(1.02rem, 1.4vw, 1.19rem);
  line-height: 1.7;
  color: var(--muted);
  max-width: 56ch;
}
.lede strong { color: var(--ink); font-weight: 560; }
.mono { font-family: var(--font-mono); }
.strap {
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.14em;
  color: var(--ghost);
  text-transform: uppercase;
}
/* masked line reveal (.split > .lnw > .ln). Visible by DEFAULT so the page is
   readable with no JS / blocked scripts; shared.js adds `.js` to opt into the
   hidden pre-reveal state, then `.in` reveals. Each line rises behind its clip
   mask with a micro-blur and a variable-weight "resolve" (wght 385 → 640) —
   the signature settle that mirrors the chaos→order brand story in the type. */
/* padding-bottom + like negativ margin: linjeboksen er 1,02 av skriftstørrelsen,
   så underlengdene på g, j, p og y faller utenfor den og ble klippet av
   overflow: hidden. Padding gir dem plass inne i masken, den negative margen
   tar plassen tilbake så linjeavstanden er uendret. Målt fram: 0,09em holdt
   ikke på 89,6px, 0,12em gjør det. Varden har samme retting i varden.css:396. */
.lnw { overflow: hidden; display: block; padding: 0 0.06em 0.12em; margin-bottom: -0.12em; }
/* Transform only. This used to animate `filter` (repaint per frame) and
   `font-variation-settings` (RELAYOUT of the whole line per frame). On a warm
   load the main thread absorbed it; on a hard refresh it competed with parse,
   font loading and WebGL init, and the wipe stuttered to ~18fps. The weight
   still differs between states — it just snaps instead of tweening, and the
   line is masked behind overflow:hidden at that instant, so it snaps unseen. */
.ln {
  display: block;
  transition: transform var(--dur-slow) var(--ease);
}
.js .split .ln { transform: translateY(112%); font-variation-settings: 'wght' 385; }
.js .split.in .ln { transform: translateY(0); font-variation-settings: 'wght' 640; }
.js .split .lnw:nth-child(2) .ln { transition-delay: calc(var(--stagger) * 1.4); }
.js .split .lnw:nth-child(3) .ln { transition-delay: calc(var(--stagger) * 2.8); }
/* generic reveal — visible by default; JS hides pre-reveal, `.in` reveals.
   16px of travel is a --dur-base move, not a 900ms one. */
/* opacity + transform only: both run on the compositor. The 6px blur that
   used to be here forced a main-thread repaint every frame, for every
   revealing element at once. */
.rv {
  transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease);
  transition-delay: calc(min(var(--i, 0), 6) * var(--stagger));
}
.js .rv { opacity: 0; transform: translateY(16px); }
.js .rv.in { opacity: 1; transform: none; }
/* word-level blur-to-sharp reveal (ledes only, via data-split="words") */
.rv-word { display: inline-block; }
.js .rv-words .rv-word {
  opacity: 0; transform: translateY(10px);
  transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease);
  transition-delay: calc(var(--i, 0) * 26ms);
}
.js .rv-words.in .rv-word { opacity: 1; transform: none; }
/* ---------- nav ---------- */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 40;
  height: var(--nav-h);
  display: flex; align-items: center;
  transition: background 0.4s var(--ease), border-color 0.4s var(--ease),
              backdrop-filter 0.4s var(--ease);
  border-bottom: 1px solid transparent;
}
.nav.scrolled {
  background: rgba(6, 24, 31, 0.72);
  backdrop-filter: blur(14px);
  border-bottom-color: var(--line);
}
.nav .wrap { display: flex; align-items: center; gap: 24px; width: 100%; }
.brand { display: flex; align-items: center; gap: 12px; margin-right: auto; }
.brand svg { width: 22px; height: 32px; }
.brand-name {
  font-family: var(--font-logo);
  font-size: 12.5px; letter-spacing: 0.24em;
  color: var(--ink);
}
.nav-menu { display: flex; align-items: center; gap: 28px; }
.nav-links { display: flex; gap: 28px; }
.nav-links a {
  font-size: 14px; color: var(--muted);
  /* 22px tall was under the 24x24 minimum (WCAG 2.5.8) */
  display: inline-flex; align-items: center; min-height: 24px;
  font-variation-settings: 'wght' 450;
  /* weight snaps, colour tweens: animating font-variation-settings relayouts
     the nav item on every frame of the hover */
  transition: color var(--dur-fast) var(--ease);
}
.nav-links a:hover { color: var(--ink); font-variation-settings: 'wght' 620; }
/* mobile hamburger */
.nav-toggle { display: none; }
@media (max-width: 760px) {
  .nav-toggle {
    display: flex; flex-direction: column; justify-content: center; gap: 5px;
    width: 44px; height: 40px; padding: 0 11px; cursor: pointer;
    background: transparent; border: 1px solid var(--line-strong); border-radius: 10px;
  }
  .nav-toggle span { display: block; height: 1.5px; background: var(--ink);
    transition: transform 0.3s var(--ease), opacity 0.2s var(--ease); }
  .nav.open .nav-toggle span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
  .nav.open .nav-toggle span:nth-child(2) { opacity: 0; }
  .nav.open .nav-toggle span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }
  .nav-menu {
    position: fixed; top: var(--nav-h); left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 2px;
    background: rgba(6, 24, 31, 0.97); backdrop-filter: blur(16px);
    border-bottom: 1px solid var(--line); padding: 10px var(--pad) 20px;
    transform: translateY(-10px); opacity: 0; pointer-events: none; visibility: hidden;
    transition: opacity 0.25s var(--ease), transform 0.25s var(--ease), visibility 0.25s;
  }
  .nav.open .nav-menu { transform: none; opacity: 1; pointer-events: auto; visibility: visible; }
  .nav-links { flex-direction: column; gap: 0; }
  .nav-links a { padding: 14px 4px; font-size: 16px; border-bottom: 1px solid var(--line); }
  .nav-menu .btn { margin-top: 14px; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .nav-menu { transition: none; } .nav-toggle span { transition: none; }
}
/* ---------- cross-document view transitions (one-app feel between pages) ---------- */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
.nav { view-transition-name: site-nav; }
.brand { view-transition-name: site-brand; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.32s; }
/* ---------- buttons ---------- */
.btn-row { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }
/* ONE button language across both sites. They previously disagreed on every
   property: 46px vs 56px tall, 8px radius vs a full pill, solid white fill vs
   the aurora gradient. Settled on the gradient primary (it is the brand's own
   signature and reads as one company across both domains) with the calmer
   10px radius rather than the pill, which suits a public-sector buyer better. */
.btn {
  display: inline-flex; align-items: center; gap: 10px;
  height: 48px; padding-inline: 26px;
  border-radius: var(--r-btn);
  font-size: 15px; font-weight: 600;
  border: 1px solid transparent;
  transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease),
              filter var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.btn-primary { background: var(--aurora-grad-btn); color: #052018; }
.btn-primary:hover { transform: translateY(-1px); filter: brightness(1.07);
  box-shadow: 0 0 40px rgba(61, 232, 160, 0.26); }
.btn-ghost { border-color: var(--line-control); color: var(--ink); background: transparent; }
.btn-ghost:hover { border-color: rgba(var(--a2-tint), 0.6); background: rgba(24, 185, 196, 0.06); }
.btn.small { height: 38px; padding-inline: 18px; font-size: 13.5px; }
/* ---------- sections ---------- */
.act { padding: clamp(90px, 13vh, 150px) 0; position: relative; }
.act-head { display: grid; gap: 22px; margin-bottom: clamp(40px, 6vh, 64px); max-width: 720px; }
.act-head.center { margin-inline: auto; text-align: center; justify-items: center; }
@media (max-width: 900px) { .grid-3 { grid-template-columns: 1fr; } }
.card {
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: linear-gradient(180deg, var(--s3), var(--s2));
  padding: 28px 26px;
  display: grid; gap: 12px; align-content: start;
  transition: border-color 0.4s var(--ease), transform 0.4s var(--ease);
}
.card:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.card .tag {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--a2);
}
.card h3 { font-size: 18.5px; font-weight: 620; letter-spacing: -0.01em; }
.card p { font-size: 14.5px; color: var(--muted); line-height: 1.65; }
/* ---------- browser frame ---------- */
.frame {
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  background: var(--s2);
  box-shadow: var(--glow-frame);
  overflow: hidden;
}
.frame-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 16px;
  background: var(--s3);
  border-bottom: 1px solid var(--line);
}
.frame-bar i { width: 9px; height: 9px; border-radius: 50%; background: var(--line-strong); }
.frame-bar .url {
  margin-left: 12px;
  font-family: var(--font-mono); font-size: 11.5px; color: var(--ghost);
  background: rgba(6, 24, 31, 0.6);
  border: 1px solid var(--line);
  border-radius: 6px; padding: 3px 12px;
}
.frame-body { padding: clamp(16px, 3vw, 32px); }
/* roster grid (product visual) */
.roster {
  display: grid;
  grid-template-columns: repeat(14, 1fr);
  gap: 5px;
}
.roster i {
  aspect-ratio: 1.6;
  border-radius: 3px;
  background: rgba(147, 171, 176, 0.10);
  opacity: 0;
  transform: scale(0.6);
  transition: background 0.6s var(--ease), opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
.roster.on i { opacity: 1; transform: scale(1); }
/* day → night luminance ramp (unified with the field engine + demo grid) */
.roster i.d { background: var(--dag); opacity: 0.85; }
.roster i.k { background: var(--kveld); opacity: 0.8; }
.roster i.n { background: var(--natt); }
.roster i.hole { background: var(--varsel-soft); }
.roster.on i.filled { background: var(--dag); opacity: 0.85; }
.readout {
  display: flex; gap: 26px; flex-wrap: wrap;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.1em;
  color: var(--muted); text-transform: uppercase;
}
.readout b { color: var(--a3); font-weight: 500; }
/* ---------- tag row (promoted from concept mockups) ---------- */
.tagrow { display: flex; flex-wrap: wrap; gap: 10px; }
.tagrow span {
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.06em;
  color: var(--muted); border: 1px solid var(--line);
  background: var(--s2); padding: 8px 14px; border-radius: 999px;
}
/* ---------- bounded cursor-spotlight (fine pointer only) ---------- */
@media (hover: hover) and (pointer: fine) {
  .spotlight { position: relative; isolation: isolate; }
  .spotlight::after {
    content: ''; position: absolute; inset: 0; border-radius: inherit; z-index: 1;
    pointer-events: none;
    background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%),
      rgba(24, 185, 196, 0.10), transparent 68%);
    opacity: var(--sp, 0); transition: opacity 0.45s var(--ease);
  }
}
/* ---------- screen-reader-only utility ---------- */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
/* <main> carries tabindex="-1" purely so the skip link can move focus into it
   (WCAG 2.4.1). It is not an interactive control, so it must not draw a ring
   around the whole page when it receives that programmatic focus. */
main[tabindex="-1"]:focus, main[tabindex="-1"]:focus-visible { outline: none; }
/* ---------- skip link + shared site footer (all pages) ---------- */
.skip { position: fixed; top: -60px; left: 12px; z-index: 100; background: var(--ink); color: #06181F;
  padding: 10px 16px; border-radius: 8px; font-weight: 600; transition: top 0.2s var(--ease); }
.skip:focus { top: 12px; }
.site-footer { border-top: 1px solid var(--line); position: relative; z-index: 2; background: var(--bg); }
.site-footer .inner { max-width: var(--maxw); margin: 0 auto; padding: 46px var(--pad) 20px;
  display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 28px; }
/* Grid children default to min-width:auto, so the unbreakable mailto address
   forced the track wider than the viewport at =<414px. Because body has
   overflow-x:hidden that overflow was CLIPPED, not scrollable — WCAG 1.4.10
   (Reflow) with no way for the user to recover it. */
.site-footer .inner > * { min-width: 0; }
.site-footer a { overflow-wrap: anywhere; }
@media (max-width: 760px) { .site-footer .inner { grid-template-columns: 1fr 1fr; } }
.site-footer .brandline { display: flex; align-items: center; gap: 10px; margin-bottom: 12px;
  flex-wrap: wrap; row-gap: 6px; }
.site-footer .brandline svg { width: 18px; height: 26px; }
.site-footer p { font-size: 13px; color: var(--muted); line-height: 1.6; }
.site-footer .foot-h { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ghost); margin-bottom: 12px; }
/* inline prose links carry an underline (not colour alone) — WCAG 1.4.1 */
.contact-note a, .founder a, .article a, .press-note a, .disclaimer a, .demo-note a, .lede a {
  text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
  text-decoration-color: rgba(24, 185, 196, 0.5);
}
.site-footer ul { list-style: none; display: grid; gap: 4px; }
.site-footer a { font-size: 13.5px; color: var(--muted); display: inline-flex; align-items: center;
  min-height: 24px; }
.site-footer a:hover { color: var(--ink); }
.site-footer .bottom { max-width: var(--maxw); margin: 0 auto; padding: 18px var(--pad); border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.1em; color: var(--ghost); }
/* ---------- stats ---------- */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
@media (max-width: 900px) { .stats { grid-template-columns: repeat(2, 1fr); } }
.stat {
  border-top: 1px solid var(--line);
  padding-top: 22px;
  display: grid; gap: 8px;
}
.stat b {
  font-family: var(--font-mono); font-weight: 500;
  font-size: clamp(1.9rem, 3.2vw, 2.7rem);
  letter-spacing: -0.01em;
  color: var(--ink);
}
.stat b .unit { color: var(--a2); }
.stat span { font-size: 13.5px; color: var(--muted); line-height: 1.5; }
/* ---------- footer ---------- */
.footer {
  border-top: 1px solid var(--line);
  padding: 44px 0 60px;
  margin-top: clamp(60px, 8vh, 100px);
}
.footer .wrap { display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap; align-items: center; }
.footer .strap { letter-spacing: 0.12em; }
/* ---------- hero scrim guarantee (text zone stays dark) ---------- */
.scrim {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(6, 24, 31, 0.10) 0%,
    rgba(6, 24, 31, 0.42) 46%,
    rgba(6, 24, 31, 0.88) 72%,
    #06181F 96%);
}
/* aurora canvas host */
.sky {
  position: absolute; inset: 0; z-index: 0; overflow: hidden;
  /* CSS fallback layer — always underneath, doubles as pre-compile paint */
  background:
    radial-gradient(90% 55% at 18% -12%, rgba(15, 110, 124, 0.34), transparent 60%),
    radial-gradient(70% 45% at 72% -8%, rgba(24, 185, 196, 0.22), transparent 62%),
    radial-gradient(46% 30% at 46% -4%, rgba(61, 232, 160, 0.12), transparent 65%),
    var(--bg);
}
.sky canvas { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; transition: opacity 1.2s var(--ease); }
.sky canvas.live { opacity: 1; }
/* the N mark */
.mark-n path {
  stroke: url(#auroragrad);
  stroke-width: 13;
  fill: none;
  stroke-linejoin: miter;
  stroke-linecap: butt;
}
/* ---------- reduced motion: designed static states ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .rv, .ln, .rv-word { opacity: 1 !important; transform: none !important; filter: none !important; transition: none !important; }
  .js .split .ln { font-variation-settings: 'wght' 640 !important; }
  .roster i { opacity: 1 !important; transform: none !important; transition: none !important; }
  .sky canvas { display: none; }
  *, *::before, *::after { animation-duration: 0.001s !important; animation-iteration-count: 1 !important; }
  /* view-transition pseudos aren't matched by the universal selector above */
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}
