/* ============================================================
   VELOCITY - Website Design System (prototype)
   Ported from the app's baby-blue theme. Owns tokens, glass,
   buttons, badges, motion. Marketing-site tuned (scrolls).
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=Space+Grotesk:wght@500;600;700&display=swap');

/* ---------- Tokens ---------- */
:root {
  /* baby blue scale (sampled from logo) */
  --blue-50:  #EAF5FF;
  --blue-100: #D4EBFF;
  --blue-200: #B6DCFB;
  --blue-300: #97CCF7;
  --blue-400: #7CC0F2;   /* primary-light */
  --blue-500: #5FAEEC;   /* primary */
  --blue-600: #4A9AE0;
  --blue-700: #3B82C7;

  --accent: var(--blue-400);
  --accent-strong: var(--blue-500);
  --accent-grad: linear-gradient(135deg, #A9D6FB 0%, #6FB8F0 55%, #4A9AE0 100%);
  --accent-grad-soft: linear-gradient(135deg, rgba(169,214,251,.18), rgba(79,154,224,.10));

  /* ink / surfaces (cool near-black with blue undertone) */
  --bg-0: #080B11;
  --bg-1: #0A0E16;
  --bg-2: #0E1420;
  --surface: rgba(255,255,255,0.032);
  --surface-2: rgba(255,255,255,0.055);
  --surface-3: rgba(255,255,255,0.085);
  --hairline: rgba(255,255,255,0.075);
  --hairline-strong: rgba(255,255,255,0.13);

  /* text */
  --text: #EAF2FB;
  --text-dim: #A2B4C8;
  /* --text-mute carries every caption, hint and quiet label on the page, so it is
     the token that decides whether the small print is readable. It was #667891,
     which measures 4.3:1 on --bg-0 and 4.3:1 on --bg-1: just under the 4.5:1 that
     WCAG AA asks of text this size. Lifted three steps of lightness (same hue, same
     family, no new colour) to clear 4.9:1 without changing how quiet it reads. */
  --text-mute: #6E819B;
  /* Decoration only: separator glyphs, disabled controls and the labels inside the
     simulated app window. Never put real copy on this. */
  --text-faint: #47566a;

  /* status */
  --safe: #57D9A3;
  --moderate: #F5C451;
  --advanced: #FF8B6B;
  --danger: #FF6B7A;

  /* radii */
  --r-xs: 8px;
  --r-sm: 12px;
  --r-md: 16px;
  --r-lg: 22px;
  --r-xl: 30px;
  --r-pill: 999px;

  /* shadows / glow */
  --shadow-sm: 0 2px 8px rgba(0,0,0,.28);
  --shadow-md: 0 10px 30px -8px rgba(0,0,0,.55);
  --shadow-lg: 0 30px 70px -20px rgba(0,0,0,.7);
  --glow: 0 0 0 1px rgba(122,197,240,.35), 0 8px 40px -6px rgba(95,174,236,.45);
  --glow-soft: 0 0 34px -4px rgba(95,174,236,.32);

  /* motion */
  --e-out: cubic-bezier(.22,1,.36,1);
  --e-in-out: cubic-bezier(.65,0,.35,1);
  --e-spring: cubic-bezier(.34,1.56,.64,1);
  --t-fast: .16s;
  --t: .28s;
  --t-slow: .48s;

  /* layout */
  --maxw: 1160px;          /* page shell: nav, footer, wide media */
  --maxw-mid: 1040px;      /* card grids: a touch narrower than the shell */
  --maxw-text: 900px;      /* every heading block and body column. The tightening. */
  --maxw-nav: 900px;       /* the floating nav island: sized to hug its content, not the page */
  /* 14px dock offset + 64px island = the height anchors and the mobile drawer sit below it */
  --nav-h: 78px;

  /* vertical rhythm. One uniform section step, used by EVERY section, so the page
     scans at a steady beat instead of the irregular gaps it grew. */
  --sec-pad: clamp(72px, 8vw, 96px);
  --spot-size: 560px;      /* diameter of the cursor-revealed grid patch */
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px; --space-4: 16px;
  --space-5: 20px; --space-6: 24px; --space-7: 32px; --space-8: 40px;
  --space-9: 48px; --space-10: 64px; --space-11: 80px;

  /* the one instrument face for all measured numbers (FPS, ping, prices, counts) */
  --font-price: 'Space Grotesk', 'Inter', system-ui, sans-serif;

  /* ink color for text sitting on the baby-blue accent */
  --on-accent: #06121f;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: auto; }   /* JS momentum scroller (site.js) drives smoothness */
html, body { min-height: 100%; }
body {
  font-family: 'Inter', system-ui, 'Segoe UI', sans-serif;
  color: var(--text);
  background: var(--bg-0);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  letter-spacing: -0.01em;
  overflow-x: hidden;
  line-height: 1.5;
}
button, input, textarea { font-family: inherit; color: inherit; }
a { color: var(--accent); text-decoration: none; }
img { max-width: 100%; display: block; }
/* 700 not 800: headlines should read calm and confident, not shouted. */
h1,h2,h3,h4 { font-weight: 700; letter-spacing: -0.028em; line-height: 1.07; }
::selection { background: rgba(122,197,240,.28); color: #fff; }

/* global keyboard focus ring (baby-blue, no new hue) */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.btn:focus-visible { outline-offset: 3px; }

/* Every measured figure on the page sets font-family: var(--font-price) directly,
   and the one gradient word per section is handled by that section (.hero-acc,
   .features-acc, .cta-acc), so the old .display and .grad-text helpers are gone. */

/* ---------- Ambient background (fixed, behind everything) ----------
   Kept deliberately cheap: one static wash on a solid base. No animated
   mesh, no full-page blur filter, no blend-mode grain. Those forced
   continuous GPU recompositing and were the main cause of scroll stutter. */
.bg-layer { position: fixed; inset: 0; z-index: 0; pointer-events: none; }

/* Base: solid ink, plus TWO soft ambient glows on a diagonal.
   Both are fixed, so they read as light in the room rather than decoration
   attached to one section, and the lower page stops going flat black the
   moment the hero scrolls away.
   The diagonal (high right, low left) is deliberate: it keeps the brighter
   pool away from the centre column where all the reading happens, and it is
   its own composition rather than a mirror of anyone else's. */
.bg-base { background:
  radial-gradient(34vw 30vw at 84% 6%,   rgba(95,174,236,.11),  transparent 62%),
  radial-gradient(32vw 28vw at 8% 66%,   rgba(122,197,240,.07), transparent 60%),
  var(--bg-0);
}

/* Blueprint grid: 1px lines on a 44px square, drawn with two linear gradients.
   Masked so it is a vignette rather than wallpaper. Under about 4% opacity a
   grid stops reading as a pattern and starts reading as quality, which is the
   whole point; anything heavier turns the page into graph paper.
   Static, no blur, no animation, so it costs nothing on scroll. */
.bg-mesh {
  background-image:
    linear-gradient(to right, rgba(176,212,245,.028) 1px, transparent 1px),
    linear-gradient(rgba(176,212,245,.028) 1px, transparent 1px);
  background-size: 44px 44px, 44px 44px;
  -webkit-mask-image: radial-gradient(115vw 88vh at 50% 0%, #000 18%, rgba(0,0,0,.45) 58%, transparent 88%);
          mask-image: radial-gradient(115vw 88vh at 50% 0%, #000 18%, rgba(0,0,0,.45) 58%, transparent 88%);
}
/* ---------- Cursor spotlight ----------
   A brighter patch of the SAME 44px grid, revealed through a circular mask that
   follows the pointer, so the squares are barely there until you move over them.

   Two details do the real work:
   1. The patch is sized in CSS and offset by half its size, so its centre lands
      on the cursor and JS only has to write one transform.
   2. JS counter-offsets background-position by the same amount it translates.
      Without that the grid lines slide along with the pointer, which reads as
      dragging the pattern around rather than uncovering it.

   Starts hidden and is only shown once a real pointer moves (js adds .is-on),
   so it never flashes on load and never appears on a touch device. */
.bg-spot {
  position: fixed; top: 0; left: 0; z-index: 0; pointer-events: none;
  width: var(--spot-size); height: var(--spot-size);
  margin-left: calc(var(--spot-size) / -2);
  margin-top: calc(var(--spot-size) / -2);
  background-image:
    linear-gradient(to right, rgba(150,203,245,.16) 1px, transparent 1px),
    linear-gradient(rgba(150,203,245,.16) 1px, transparent 1px);
  background-size: 44px 44px, 44px 44px;
  -webkit-mask-image: radial-gradient(circle at center, #000 0%, rgba(0,0,0,.55) 42%, transparent 72%);
          mask-image: radial-gradient(circle at center, #000 0%, rgba(0,0,0,.55) 42%, transparent 72%);
  opacity: 0;
  transition: opacity .35s var(--e-out);
  will-change: transform, background-position;
}
.bg-spot.is-on { opacity: 1; }

/* A pointer that cannot hover has no cursor to follow, so the layer is removed
   outright rather than left as dead weight in the compositor. */
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .bg-spot { display: none; }
}

/* fine static grain to kill banding (no mix-blend-mode, so no repaint cost) */
.bg-grain {
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ============================================================
   COMPONENTS (shared - agents reuse these)
   ============================================================ */

/* glass card */
.card {
  position: relative; background: var(--surface-2); border: 1px solid var(--hairline);
  border-radius: var(--r-md); padding: 22px;
  transition: transform var(--t) var(--e-out), border-color var(--t), box-shadow var(--t), background var(--t);
}
.card::before {
  content:''; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  background: linear-gradient(180deg, rgba(255,255,255,.06), transparent 40%);
  -webkit-mask: linear-gradient(#000,transparent 45%); mask: linear-gradient(#000,transparent 45%);
}
.card.hover:hover { transform: translateY(-3px); border-color: var(--hairline-strong); box-shadow: var(--shadow-md); background: var(--surface-3); }
/* There is no .card.glow variant: every card family on the page is deliberately
   flat (see the "no glow" notes in 06-compare.css, 07-pricing.css, 08-partners.css). */

/* buttons */
/* a 3-tier system at ONE small radius (not pills). Primary is the only filled
   accent; secondary is a quiet hairline; tertiary is a bare text link. Full pills
   are reserved for tags and status only, so pills stop reading as every button. */
/* The primary button was a 3-stop diagonal gradient carrying an inset highlight
   AND a coloured glow, at 143px wide. Three effects and a small footprint read
   as a fussy chip. It is now a flat accent fill with one hairline highlight, and
   it is given room: a confident slab reads more expensive than a decorated one.
   The signature gradient is not lost, it just moves to where it counts, the one
   accent word in the hero headline. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  border: 1px solid transparent; border-radius: var(--r-sm); cursor: pointer;
  font-size: 14px; font-weight: 600; padding: 12px 22px; white-space: nowrap;
  letter-spacing: -0.01em;
  transition: transform var(--t-fast) var(--e-out), box-shadow var(--t), background var(--t), border-color var(--t), opacity var(--t), color var(--t);
}
.btn svg { width: 17px; height: 17px; }
.btn:active { transform: scale(.985); }
.btn-primary {
  background: var(--accent-strong);
  color: var(--on-accent);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.2);
}
.btn-primary:hover { background: var(--blue-400); box-shadow: inset 0 1px 0 rgba(255,255,255,.28); }
.btn-ghost { background: transparent; border-color: var(--hairline-strong); color: var(--text); }
.btn-ghost:hover { background: var(--surface); border-color: rgba(255,255,255,.22); }
.btn-outline { background: transparent; border-color: rgba(122,197,240,.45); color: var(--blue-100); }
.btn-outline:hover { background: var(--accent-grad-soft); border-color: rgba(122,197,240,.7); }
/* the hero and closing asks: wide enough to read as the page's main action */
.btn-lg { padding: 16px 34px; font-size: 16.5px; border-radius: var(--r-sm); min-width: 210px; }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .4; pointer-events: none; }

/* Removed in the 2026-08 tidy, each verified unused by every page and every script
   before deletion. They were the components the redesign superseded, and leaving
   them made this file read as a bigger system than the site actually uses:
     .btn-text     tertiary text-link button. The redesign deleted every one of them
                   ("See pricing", "use their profile"): one primary action only.
     .badge*       the desktop app's risk badges. They never shipped on the site.
     .chip         the old hero trust pills, now the one-line .hero-marks strip.
     .eyebrow      superseded by .eyebrow-pill, which every section head uses.
   Git history has them if a future section wants one back. */

/* grid helpers */
.grid { display: grid; gap: 20px; }
.g-2 { grid-template-columns: repeat(2, 1fr); }
.g-3 { grid-template-columns: repeat(3, 1fr); }
.g-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 940px) { .g-3, .g-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .g-2, .g-3, .g-4 { grid-template-columns: 1fr; } }
.row { display: flex; align-items: center; gap: 12px; }
.wrap { flex-wrap: wrap; }
.center { text-align: center; }
.muted { color: var(--text-mute); }
.dim { color: var(--text-dim); }

/* One shared keyframe, not six. fadeUp, pop, pulse, floatY and shimmer were all
   unreferenced: entrance motion is the .reveal transition in site.css, and the only
   two loops left on the page (the hero caret, the games marquee) own their keyframes
   in their own section files, next to the prefers-reduced-motion rule that stops each.
   `spin` stays because buy.html's checkout spinner uses it and buy.html loads this
   stylesheet and nothing else. Do not remove it without editing buy.html. */
@keyframes spin { to { transform: rotate(360deg); } }
