/* ==========================================================================
   Unbounded design tokens
   Source: Template Style Guide (rev. 6 Aug 2026) + unboundedTokens.tsx

   These are the single source of truth for the rebuilt site. If a value
   changes here, it should also be reflected back to unboundedTokens.tsx if
   the Framer project is ever touched again.
   ========================================================================== */

:root {
  /* ---------------------------------------------------------------------
     Color — a single-hue neutral ramp (hue ~207) plus one accent.
     Neutral Color 07 is retired (near-duplicate of 06); every layer that
     referenced it should use 06 instead.
     --------------------------------------------------------------------- */
  --neutral-01: #FFFFFF; /* white surfaces, card fill */
  --neutral-02: #22313D; /* headings; also the navy hover state */
  --neutral-03: #3A4853; /* secondary headings, emphasis body */
  --neutral-04: #535F69; /* body paragraphs */
  --neutral-05: #666A6E; /* muted labels, captions */
  --neutral-06: #CED1D4; /* structural borders, dividers, image edges */
  --neutral-08: #86929C; /* interactive control borders — 3.18:1, meets WCAG 1.4.11 */
  --neutral-09: #EEF0F2; /* selected rows, hover fills */
  --neutral-10: #F8F9FA; /* page background */
  --main: #091A28;       /* brand dark, dark fills, selected states */
  --text-alt: #251B18;   /* alt warm dark — rarely used */

  /* Accent. #DF563B is only 3.80:1 against white — fails AA for small/bold
     text (e.g. white-on-accent CTA buttons). #CA3D21 is the same hue at
     5.00:1 and clears AA. Per the style guide's own recommendation:
     keep DF563B for large, non-text-contrast, decorative use; use CA3D21
     anywhere the accent carries or sits under small text. */
  --accent-display: #DF563B; /* large display use only (non-text-contrast) */
  --accent: #CA3D21;         /* small text, CTA backgrounds, labels, links */
  --accent-hover: #AC3319;

  /* ---------------------------------------------------------------------
     Type
     --------------------------------------------------------------------- */
  --font-display: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif;
  --font-body: 'Spline Sans', ui-sans-serif, system-ui, sans-serif;
  --font-figure: 'Spline Sans Mono', ui-monospace, SFMono-Regular, monospace;

  /* ---------------------------------------------------------------------
     Spacing
     --------------------------------------------------------------------- */
  --space-none: 0px;
  --space-tight: 10px;   /* dense element groups — the most common gap */
  --space-row: 16px;     /* list separators, row spacing */
  --space-gap: 24px;     /* default gap between columns and card list items */
  --space-loose: 32px;   /* fills the 24->80 gap the guide itself flagged — column padding, panel padding */
  --space-wide: 48px;    /* larger two-column gaps that don't need the full 80px section rhythm */
  /* Removed: --space-heading-after (40px) and --space-body-after (20px).
     Both were off-table additions, and --space-heading-after was the
     source of a real inconsistency — a heading sat 40px above its body
     on the pricing page and 16px on the homepage. Heading spacing now
     comes from the scale: --space-row under a heading before its own
     body copy, --space-block under a section header before its content. */
  --space-block: 80px;   /* compact section end padding */
  --space-section: 130px; /* large section end padding for primary content */
  --space-gutter: 30px;   /* site section side padding */
  --space-gutter-phone: 20px;

  /* Measured from the rendered header (logo/nav row + its padding), with a
     couple px of slack for font-metric differences once webfonts are
     actually loaded (measured against system-font fallback in testing). Used
     to offset anything sticky below the now-sticky header — see
     find-your-fit.css's .fyf__result. */
  --header-height: 84px;

  /* ---------------------------------------------------------------------
     Radius & shadow — flat throughout, no exceptions.
     --------------------------------------------------------------------- */
  --radius: 0px;
  --shadow-none: none;

  /* ---------------------------------------------------------------------
     Motion
     --------------------------------------------------------------------- */
  --ease: cubic-bezier(0.16, 1, 0.3, 1); /* overdamped, no overshoot */
  --motion-small-distance: 20px;  /* hero button, hero text */
  --motion-block-distance: 50px;  /* FAQ block, scroll-in reveals */
  --motion-state: 0.14s;          /* hover, focus, colour-only */
  --motion-in-place: 0.32s;       /* content changing without moving */
  --motion-entrance: 0.7s;        /* scroll-in reveals */
  --motion-base-delay: 0.2s;      /* FAQ appear effect */
  --motion-stagger: 0.05s;        /* per-item stagger step */

  /* Nav underline spring, taken directly from Framer's Transition panel for
     the Nav Button's Line IN/OUT variants: Physics, Stiffness 500,
     Damping 60, Mass 1. Solved as a damped harmonic oscillator step
     response (overdamped, damping ratio ~1.34 — no overshoot, same family
     as the FAQ spring but stiffer/faster) and sampled into a linear()
     easing function, since CSS has no native spring timing function.
     Duration 0.45s is where the curve reaches ~98.6% — the asymptotic tail
     never truly finishes, so this is "visually settled," not exact zero.
     Recompute both if the Framer values ever change. */
  --ease-nav-spring: linear(
    0, 0.083 5%, 0.229 10%, 0.372 15%, 0.495 20%, 0.595 25%, 0.676 30%,
    0.741 35%, 0.793 40%, 0.835 45%, 0.868 50%, 0.895 55%, 0.916 60%,
    0.933 65%, 0.946 70%, 0.957 75%, 0.966 80%, 0.973 85%, 0.978 90%,
    0.983 95%, 1
  );
  --duration-nav-spring: 0.45s;
  /* Scroll reveals observe with threshold 0 + a rootMargin inset rather
     than a fractional threshold — see js/reveal.js. Any fraction is a
     height trap: an element taller than 1/threshold viewports can never
     satisfy it and stays invisible for good. Not a CSS var; noted here
     because the motion tokens above describe the same effect. */
}

/* Phone section rhythm. --space-block is the section end padding everywhere
   below 1024px, so on a phone it was spending 80px above and below every
   section — 880px on the homepage alone, more than a full 844px screen of
   nothing but background.

   80px is doing a real job on desktop, where sections are wide and the eye
   needs a clear break between them. On a 390px screen the viewport itself
   already frames one section at a time, so the break reads at 56px and the
   page stops feeling padded out. Overriding the token rather than .section
   keeps the same rhythm on everything else measured against it — the
   note band's padding, the services header's margin, the footer's top. */
@media (max-width: 639px) {
  :root { --space-block: 56px; }
}

/* ============================================================================
   Self-hosted fonts
   Previously three render-blocking requests to fonts.googleapis.com and
   fonts.gstatic.com: two extra DNS lookups and TLS handshakes sitting on
   the critical path before a glyph could paint. Serving them from our own
   origin also stops every visitor's IP reaching Google before they have
   consented to anything, which matters given the privacy policy treats
   analytics and advertising as consent-based.

   All three families are variable fonts, so a single file per family and
   subset covers every weight the site uses — hence the font-weight ranges.
   font-display:swap paints fallback text immediately and swaps when the
   webfont arrives, instead of holding the text invisible.
   ============================================================================ */
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/instrument-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/instrument-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Spline Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/spline-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Spline Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/spline-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Spline Sans Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/spline-sans-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Spline Sans Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/spline-sans-mono-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ============================================================================
   Reset & base
   ============================================================================ */

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

html {
  -webkit-text-size-adjust: 100%;
  /* Animates the in-page jumps from the header nav (How it Works, Pricing,
     FAQs). The prefers-reduced-motion block below forces this back to
     auto, so anyone who has asked for less motion still gets an instant
     jump rather than a long slide. */
  scroll-behavior: smooth;
  /* Every anchored target stops this far below the top of the viewport, so
     the sticky header can't sit over the section you just jumped to.
     Set here rather than per-section so any future id lands correctly too. */
  scroll-padding-top: var(--header-height);
}

body {
  margin: 0;
  background: var(--neutral-10);
  color: var(--neutral-04);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.8;
}

img, picture, video {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
}

button, input {
  font: inherit;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================================
   Text styles — one class per row in the style guide's Text Styles table.
   Sizes are the desktop values; tablet/phone overrides follow per style.
   ============================================================================ */

.text-h1, .text-h1-big, .text-h2, .text-h3, .text-h4, .text-h5, .text-h6 {
  font-family: var(--font-display);
  color: var(--neutral-02);
  margin: 0;
}

.text-h1 {
  font-weight: 500;
  font-size: 69px;
  line-height: 1.2em;
  letter-spacing: -2px;
  text-wrap: balance;
}
.text-h1-big {
  font-weight: 500;
  font-size: 120px;
  line-height: 1.2em;
  letter-spacing: -3px;
  text-wrap: balance;
}
.text-h2 {
  font-weight: 400;
  font-size: 64px;
  line-height: 1.4em;
  letter-spacing: 0;
}
.text-h3 {
  font-weight: 500;
  font-size: 44px;
  line-height: 1.3em;
  letter-spacing: -1px;
}
.text-h4 {
  font-weight: 400;
  font-size: 36px;
  line-height: 1.4em;
  letter-spacing: -2px;
}
.text-h5 {
  font-weight: 500;
  font-size: 24px;
  line-height: 1.5em;
  letter-spacing: 0.5px;
}
.text-h6 {
  font-weight: 600;
  font-size: 16px;
  line-height: 1.4em;
  letter-spacing: -0.02em;
}

@media (max-width: 1023px) {
  .text-h1 { font-size: 48px; }
  .text-h1-big { font-size: 90px; letter-spacing: -2px; }
  .text-h2 { font-size: 48px; }
  .text-h3 { font-size: 32px; }
}
@media (max-width: 639px) {
  .text-h1 { font-size: 36px; letter-spacing: -1px; }
  .text-h1-big { font-size: 60px; letter-spacing: -2px; }
  .text-h2 { font-size: 36px; }
  .text-h3 { font-size: 28px; }
  /* h4/h5 previously had no phone size at all and rendered at their full
     desktop 36px/24px on a ~350px measure. They carry sub-headings inside
     cards and panels, where that outsized every heading around them. */
  .text-h4 { font-size: 26px; letter-spacing: -1px; }
  .text-h5 { font-size: 20px; line-height: 1.4em; }
}

.text-regular-20 {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 20px;
  line-height: 1.6em;
  color: var(--neutral-04);
  margin: 0;
}
.text-regular-16 {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.8em;
  color: var(--neutral-04);
  margin: 0;
}

/* Phone body copy. Two separate problems, both only visible below ~640px:

   .text-regular-20 carries every section intro and had no phone size, so a
   20px/32px paragraph sized for a 640px column was wrapping across a ~350px
   one — roughly nine words a line becoming four.

   The 1.8 leading (also body's default) is measured for that same wide
   column. Leading and measure trade off against each other: at 350px the
   lines are already short enough to track back to, and 1.8 just spaces a
   paragraph out over half a screen. 1.65 is still generous for body text. */
@media (max-width: 639px) {
  body { line-height: 1.65; }
  .text-regular-20 { font-size: 17px; line-height: 1.6em; }
  .text-regular-16 { line-height: 1.65em; }
}
.text-regular-12 {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 12px;
  line-height: 1.5em;
  color: var(--neutral-05);
  margin: 0;
}
.text-medium {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 1.2em;
  letter-spacing: -1px;
  color: var(--neutral-04);
}
.text-nav-link {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 20px;
  line-height: 1.6em;
  color: var(--neutral-04);
}
.text-figure-18 {
  font-family: var(--font-figure);
  font-weight: 700;
  font-size: 18px;
  line-height: 1.2em;
  color: var(--main);
  margin: 0;
}
.text-figure-13 {
  font-family: var(--font-figure);
  font-weight: 400;
  font-size: 13px;
  line-height: 1.5em;
  color: var(--neutral-05);
  margin: 0;
}
.text-label {
  font-family: var(--font-figure);
  font-weight: 500;
  font-size: 12px;
  line-height: 1.4em;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--neutral-05);
  margin: 0;
}

/* Link preset: white text; underline + Neutral 06 on hover/current. Intended
   for links on a dark (Main color) surface — see .link-on-dark. */
.link-on-dark {
  color: var(--neutral-01);
  text-decoration: none;
}
.link-on-dark:hover,
.link-on-dark[aria-current="page"] {
  text-decoration: underline;
  color: var(--neutral-06);
}

/* ============================================================================
   Layout helpers
   ============================================================================ */

.container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}

.section {
  width: 100%;
  padding: var(--space-section) var(--space-gutter);
  box-sizing: border-box;
}
@media (max-width: 1023px) {
  .section { padding: var(--space-block) var(--space-gutter); }
}
@media (max-width: 639px) {
  .section { padding: var(--space-block) var(--space-gutter-phone); }
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Scroll-reveal base — see js/reveal.js. Elements start hidden/offset and
   get .is-revealed added by the IntersectionObserver, matching the
   FAQ block's onInView-once behaviour from the Framer source. */
.reveal {
  opacity: 0;
  transform: translateY(var(--motion-block-distance));
  transition: opacity var(--motion-entrance) var(--ease),
              transform var(--motion-entrance) var(--ease);
  will-change: opacity, transform;
}
.reveal.is-revealed {
  opacity: 1;
  transform: none;
}
