/* ============================================================
   FBGM24 — core.css
   Design tokens, reset, continuous background field, typography.
   The whole site is one uninterrupted scroll surface: sections
   never paint their own background, so nothing reads as a "block".
   ============================================================ */

@layer tokens, reset, base, type, utils;

@layer tokens {
  :root {
    /* --- Ink scale: deep steel-blue, colder and darker than the usual
           corporate navy so the palette reads as its own system. --- */
    --ink-1000: #02060f;
    --ink-950:  #040a16;
    --ink-900:  #061020;
    --ink-800:  #0a1830;
    --ink-700:  #102442;
    --ink-600:  #18345c;
    --ink-500:  #244678;

    /* --- Signal blues --- */
    --sig-700: #123fb8;
    --sig-600: #1a56e8;
    --sig-500: #2e6dff;
    --sig-400: #5b8dff;

    /* --- Ice: the high-key accent that carries the "white" half --- */
    --ice-400: #6fd4ff;
    --ice-300: #a5e6ff;
    --ice-200: #d2f2ff;

    /* --- Paper: near-whites with a blue cast --- */
    --paper-100: #ffffff;
    --paper-200: #f2f7fd;
    --paper-300: #e2ecf8;
    --paper-400: #c6d7ec;

    /* --- Semantic --- */
    --bg:            var(--ink-1000);
    --fg:            #e8f1ff;
    --fg-dim:        #a9bfdd;
    --fg-faint:      #6d84a6;
    --accent:        var(--ice-400);
    --accent-strong: var(--sig-500);
    --up:            #3ee8a5;
    --down:          #ff6b7f;
    --warn:          #ffc46b;

    /* --- Surfaces: translucent only. Never opaque, so the WebGL
           layer and the light-wells stay visible through content. --- */
    --surface-1: rgba(255, 255, 255, 0.028);
    --surface-2: rgba(255, 255, 255, 0.045);
    --surface-3: rgba(255, 255, 255, 0.07);
    --hairline:  rgba(150, 195, 255, 0.13);
    --hairline-2:rgba(150, 195, 255, 0.24);
    --glow:      0 0 0 1px rgba(111, 212, 255, 0.16), 0 22px 70px -30px rgba(46, 109, 255, 0.55);

    /* --- Type --- */
    --font-display: 'Space Grotesk', 'Segoe UI', system-ui, sans-serif;
    --font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

    --step--2: clamp(0.72rem, 0.70rem + 0.10vw, 0.78rem);
    --step--1: clamp(0.82rem, 0.79rem + 0.16vw, 0.92rem);
    --step-0:  clamp(0.95rem, 0.91rem + 0.22vw, 1.06rem);
    --step-1:  clamp(1.14rem, 1.06rem + 0.40vw, 1.38rem);
    --step-2:  clamp(1.42rem, 1.26rem + 0.78vw, 1.95rem);
    --step-3:  clamp(1.78rem, 1.47rem + 1.55vw, 2.85rem);
    --step-4:  clamp(2.20rem, 1.63rem + 2.85vw, 4.15rem);
    --step-5:  clamp(2.65rem, 1.62rem + 5.15vw, 6.20rem);

    /* --- Rhythm --- */
    --gutter: clamp(1.15rem, 0.6rem + 2.6vw, 3.25rem);
    --shell: 1320px;
    --shell-narrow: 860px;
    --flow: clamp(3.4rem, 2rem + 3.8vw, 6.4rem);   /* total gap between two sections */
    --radius-s: 10px;
    --radius-m: 16px;
    --radius-l: 26px;
    --radius-xl: 38px;

    /* --- Motion --- */
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
    --dur-1: 0.42s;
    --dur-2: 0.78s;
    --dur-3: 1.25s;

    /* --- Live scroll state, written by js/scroll.js --- */
    --scroll: 0;
    --vh: 100vh;
    --pointer-x: 0.5;

    color-scheme: dark;
  }
}

@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  * { margin: 0; }
  html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; overflow-x: clip; }
  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
      animation-duration: 0.001ms !important;
      transition-duration: 0.001ms !important;
      animation-iteration-count: 1 !important;
    }
  }
  img, svg, canvas, video { display: block; max-width: 100%; }
  input, button, textarea, select { font: inherit; color: inherit; }
  button { background: none; border: 0; cursor: pointer; }
  a { color: inherit; text-decoration: none; }
  table { border-collapse: collapse; width: 100%; }
  ul[role='list'], ol[role='list'] { list-style: none; padding: 0; }
  :focus-visible {
    outline: 2px solid var(--ice-400);
    outline-offset: 3px;
    border-radius: 4px;
  }
  ::selection { background: rgba(46, 109, 255, 0.4); color: #fff; }
}

@layer base {
  html, body { min-height: 100%; }

  body {
    font-family: var(--font-body);
    font-size: var(--step-0);
    line-height: 1.68;
    color: var(--fg);
    /* One flat tone, no sky. This used to be a document-length gradient that
       ran #02060f → #0a2141 → #02060f, on the theory that a single screenful
       barely changes tone. Over a 9700px page that is true per screen and
       false per scroll: the wash reads as dark at the top of the document and
       visibly lighter through the middle, and the tonal front between them
       tracks you down the page as a band. Flat removes the band outright, and
       it makes the hero plate (#02060f, the same value) dissolve into the
       page with nothing left to see. The light wells above still carry the
       depth; they are soft radials and cannot draw an edge. */
    background: var(--bg);
    overflow-x: clip;
    font-feature-settings: 'ss01' 1, 'cv05' 1;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
  }

  /* ---- The continuous field ------------------------------------
     Fixed layers below all content (the sky itself is on <body>):
       .field-wells scroll-reactive radial light wells
       #webgl       the Three.js canvas
     Because they are fixed and full-bleed, scrolling reveals a
     single unbroken surface instead of a stack of sections.
  ---------------------------------------------------------------- */
  .field {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    contain: strict;
  }

  /* Light wells drift with scroll progress; they are what makes one
     zone read as "airy white-blue" and the next as "deep ink" without
     any hard edge between them.

     Each well is its own layer, painted once at rest and then moved with
     transform alone. Feeding --scroll into the gradient's `at` coordinates
     instead — as this did — re-rasterises four blurred gradients across
     140% of the viewport on every single frame, which is the one thing the
     compositor cannot absorb. Percentages in `translate` resolve against
     the same box the gradient positions did, so the motion is identical. */
  .field-wells { position: absolute; inset: -20%; }
  .field-wells > i {
    position: absolute;
    inset: 0;
    display: block;
    opacity: 0.95;
    will-change: transform;
  }
  /* No blur here. The original single layer carried filter: blur(6px); when
     this was split into four transform-driven layers that became four blurred
     render surfaces, and Chrome re-rasterises a filtered surface as its
     transform changes instead of just moving it. Measured on the home page
     under a 4x CPU throttle: 117ms per frame with the blur, 67ms without —
     identical to deleting the wells outright. On gradients that already fade
     over several hundred pixels a 6px blur changes nothing anyone can see, so
     it was costing 43% of the frame budget for no picture. */
  /* Each well eases out over its whole radius instead of ramping linearly to
     zero part-way. A straight ramp ends on a kink, and on a flat dark field
     the eye reads that kink as a ring around the light — which is what made
     the background look like two tones meeting rather than one wash. The
     stops below approximate a cosine falloff. Every well also reaches zero
     before the bottom of its own layer: that edge is the one that travels
     through the viewport as the layer slides with scroll. */
  .well-1 {
    background: radial-gradient(58% 42% at 18% 6%,
      rgba(111, 212, 255, 0.2) 0%,
      rgba(111, 212, 255, 0.17) 22%,
      rgba(111, 212, 255, 0.11) 44%,
      rgba(111, 212, 255, 0.055) 64%,
      rgba(111, 212, 255, 0.018) 82%,
      rgba(111, 212, 255, 0.0) 100%);
    transform: translate3d(calc(var(--pointer-x) * 8%), calc(var(--scroll) * -34%), 0);
  }
  .well-2 {
    background: radial-gradient(46% 38% at 88% 34%,
      rgba(46, 109, 255, 0.26) 0%,
      rgba(46, 109, 255, 0.221) 22%,
      rgba(46, 109, 255, 0.143) 44%,
      rgba(46, 109, 255, 0.072) 64%,
      rgba(46, 109, 255, 0.023) 82%,
      rgba(46, 109, 255, 0.0) 100%);
    transform: translate3d(calc(var(--pointer-x) * -6%), calc(var(--scroll) * -46%), 0);
  }
  /* Every well has to reach full transparency *inside* its own box. This one
     did not: centred at 78% with a 46% radius it still carried ~0.03 alpha
     where the layer ends, and since the layer slides up by 52% of its height
     that cut-off travelled across the viewport as a hard horizontal line on
     an otherwise smooth field. Same visible glow, re-centred so the fade
     lands just short of the edge instead of being clipped by it. */
  .well-3 {
    background: radial-gradient(70% 41% at 42% 57%,
      rgba(210, 242, 255, 0.13) 0%,
      rgba(210, 242, 255, 0.111) 22%,
      rgba(210, 242, 255, 0.072) 44%,
      rgba(210, 242, 255, 0.036) 64%,
      rgba(210, 242, 255, 0.012) 82%,
      rgba(210, 242, 255, 0.0) 100%);
    transform: translate3d(0, calc(var(--scroll) * -52%), 0);
  }
  .well-4 {
    background: radial-gradient(52% 25% at 72% 74%,
      rgba(26, 86, 232, 0.24) 0%,
      rgba(26, 86, 232, 0.204) 22%,
      rgba(26, 86, 232, 0.132) 44%,
      rgba(26, 86, 232, 0.066) 64%,
      rgba(26, 86, 232, 0.022) 82%,
      rgba(26, 86, 232, 0.0) 100%);
    transform: translate3d(calc(var(--scroll) * 12%), calc(var(--scroll) * -60%), 0);
  }

  /* The wells are sized in percentages of their own layer, and that layer is
     the viewport. On a 1440px desktop each one is a contained blob reading as
     ambient depth; on a 390px phone the same percentages stretch it the full
     width of the screen, so it stops being a glow and becomes a lit band —
     and because the layer is fixed and slides against --scroll, that band
     floats through the page as you scroll instead of belonging to anything.
     .well-3 is the worst of the four: the palest colour over the widest
     radius, sitting low. Phones get the flat ground the hero already sits on;
     the desktop keeps the depth, where it works. */
  @media (max-width: 980px) { .field-wells { display: none; } }

  /* Film grain kills gradient banding on wide dark washes. */
  .field-grain {
    position: absolute;
    inset: 0;
    opacity: 0.035;
    mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
  }

  #webgl {
    position: fixed;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    opacity: 0;
    transition: opacity 1.4s var(--ease-out);
  }
  #webgl.is-live { opacity: 1; }

  /* All real content floats above the field. */
  .shell-root { position: relative; z-index: 2; }

  .skip-link {
    position: absolute;
    left: 1rem;
    top: -100px;
    z-index: 100;
    padding: 0.7rem 1.15rem;
    background: var(--ice-400);
    color: var(--ink-1000);
    border-radius: var(--radius-s);
    font-weight: 600;
    transition: top var(--dur-1) var(--ease-out);
  }
  .skip-link:focus { top: 1rem; }
}

@layer type {
  h1, h2, h3, h4, h5 {
    font-family: var(--font-display);
    font-weight: 600;
    line-height: 1.06;
    letter-spacing: -0.028em;
    text-wrap: balance;
    color: var(--paper-100);
  }
  h1 { font-size: var(--step-5); letter-spacing: -0.042em; }
  h2 { font-size: var(--step-4); letter-spacing: -0.034em; }
  h3 { font-size: var(--step-2); }
  h4 { font-size: var(--step-1); line-height: 1.24; }
  h5 { font-size: var(--step-0); line-height: 1.3; }

  p { text-wrap: pretty; }
  p + p { margin-top: 0.95em; }

  strong { color: var(--paper-100); font-weight: 600; }
  em { font-style: normal; color: var(--ice-300); }

  .eyebrow {
    font-family: var(--font-mono);
    font-size: var(--step--2);
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--ice-400);
    display: inline-flex;
    align-items: center;
    gap: 0.65em;
  }
  .eyebrow::before {
    content: '';
    width: 26px;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--ice-400));
  }

  .lede {
    font-size: var(--step-1);
    line-height: 1.55;
    color: var(--fg-dim);
    max-width: 62ch;
  }

  .prose { max-width: 74ch; color: var(--fg-dim); }
  .prose h2 { margin-block: 1.7em 0.6em; font-size: var(--step-2); }
  .prose h3 { margin-block: 1.4em 0.5em; font-size: var(--step-1); }
  .prose ul, .prose ol { margin-block: 1em; padding-left: 1.3em; display: grid; gap: 0.5em; }
  .prose li::marker { color: var(--ice-400); }
  .prose a { color: var(--ice-300); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
  .prose a:hover { color: var(--paper-100); }

  .num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
}

@layer utils {
  .shell {
    width: min(100% - var(--gutter) * 2, var(--shell));
    margin-inline: auto;
  }
  .shell-narrow { width: min(100% - var(--gutter) * 2, var(--shell-narrow)); margin-inline: auto; }
  .stack > * + * { margin-top: var(--gap, 1.4rem); }
  .visually-hidden {
    position: absolute; width: 1px; height: 1px; padding: 0;
    margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .up { color: var(--up); }
  .down { color: var(--down); }
  .text-dim { color: var(--fg-dim); }
  .text-faint { color: var(--fg-faint); }
}
