/* ==========================================================================
   FOTON — style.css
   Every component on the page. Owner: Agent C.

   Load order (BRAND-CONTRACT §8):  bootstrap → tokens → typography → style
   Nothing here re-declares a colour, a space step, a radius, an easing or a
   type size. Those come from tokens.css / typography.css.

   Order of sections below mirrors the order of sections in index.html.

    0.  Bootstrap variable overrides
    1.  Page substrate
    2.  Layout primitives
    3.  Icons, buttons, chips, notes
    4.  Skip link + scroll sentinel
    5.  Navbar + offcanvas menu
    6.  Hero
    7.  Polygon hex lattice (injected SVG)
    8.  Ticker strip
    9.  Proof strip
   10.  How it works
   16.  Security + contract panel
   17.  Roadmap
   18.  FAQ accordion
   20.  Final CTA
   21.  Footer
   22.  Breakpoints
   23.  Reduced motion
   ========================================================================== */


/* ==========================================================================
   0. Bootstrap variable overrides
      Bootstrap 5.3 ships a light theme. Rather than fight it selector by
      selector, its own custom properties are re-pointed at the FOTON tokens.
      ========================================================================== */
:root{
  --bs-body-bg:            var(--ft-bg);
  --bs-body-color:         var(--ft-text);
  --bs-body-font-family:   var(--font-body, "Open Sans","Segoe UI",Helvetica,Arial,sans-serif);
  --bs-heading-color:      var(--ft-text);
  --bs-emphasis-color:     var(--ft-text);
  --bs-secondary-color:    var(--ft-muted);
  --bs-tertiary-color:     var(--ft-dim);
  --bs-border-color:       var(--ft-line);
  --bs-border-color-translucent: var(--ft-line);
  --bs-link-color:         var(--ft-cyan);
  --bs-link-hover-color:   var(--ft-text);
  --bs-focus-ring-color:   rgba(34,211,238,.38);
  --bs-focus-ring-width:   var(--ft-bw-3);
  --bs-backdrop-bg:        #070311;
  --bs-backdrop-opacity:   .76;
  --bs-border-radius:      var(--r-btn);
}

/* The substrate is painted by body::before / ::after, which are fixed layers.
   overflow-x: clip (not hidden) keeps the sticky navbar working. */
html{ overflow-x: clip; }
body{ overflow-x: clip; position: relative; }


/* ==========================================================================
   1. Page substrate
      Near-black violet ground, two soft blooms, and a hairline ledger grid
      that fades away toward the middle of the viewport.
   ========================================================================== */
body::before{
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    radial-gradient(62vw 56vw at 6% 92%,  rgba(255,46,136,.20), transparent 62%),
    radial-gradient(54vw 48vw at 96% 4%,  rgba(30,134,255,.19), transparent 60%),
    radial-gradient(74vw 58vw at 48% -12%, rgba(139,43,255,.16), transparent 66%),
    var(--ft-bg);
}

body::after{
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    repeating-linear-gradient(to right,  rgba(255,255,255,.021) 0 1px, transparent 1px 64px),
    repeating-linear-gradient(to bottom, rgba(255,255,255,.021) 0 1px, transparent 1px 64px);
  -webkit-mask-image: radial-gradient(closest-side at 50% 42%, transparent 0%, rgba(0,0,0,.5) 58%, #000 100%);
          mask-image: radial-gradient(closest-side at 50% 42%, transparent 0%, rgba(0,0,0,.5) 58%, #000 100%);
}


/* ==========================================================================
   2. Layout primitives
   ========================================================================== */
.ft-wrap{
  width: 100%;
  max-width: calc(var(--wrap) + var(--gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.ft-wrap--tight{ max-width: calc(var(--wrap-tight) + var(--gutter) * 2); }

.ft-sec{ padding-block: var(--s-7); }

.ft-sechead{ margin-block-end: var(--s-7); }
.ft-sechead > h2{ max-width: 22ch; }
.ft-sechead > p{
  margin-block-start: var(--s-4);
  max-width: 58ch;
  color: var(--ft-muted);
}

/* The shared glass treatment. Used on panels, not on every card. */
.ft-glass{
  background: linear-gradient(180deg, rgba(255,255,255,.045), rgba(255,255,255,.012));
  border: var(--ft-border);
  -webkit-backdrop-filter: var(--blur-glass);
          backdrop-filter: var(--blur-glass);
}


/* ==========================================================================
   3. Icons, buttons, chips, notes
   ========================================================================== */

/* The sprite is inlined as the first child of <body>; keep it out of layout. */
.ft-sprite{
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.ft-ic{
  inline-size: 1.15em;
  block-size: 1.15em;
  flex: none;
  fill: none;
  stroke: currentColor;
  vertical-align: -.16em;
}

/* The sprite is stroke-based throughout. This flips a symbol to a filled
   glyph — used by the launch mark on the Launch App buttons, where a solid
   shape reads as a control rather than as one more outline. */
.ft-ic--solid{ fill: currentColor; stroke: none; }

.ft-btn{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-5);
  border: var(--ft-border-2);
  border-radius: var(--r-btn);
  background: rgba(255,255,255,.035);
  color: var(--ft-text);
  font-weight: 600;
  line-height: 1.15;
  text-decoration: none;
  cursor: pointer;
  transition:
    transform        var(--dur-1) var(--ease-spring),
    border-color     var(--dur-1) var(--ease-out),
    background-color var(--dur-1) var(--ease-out),
    box-shadow       var(--dur-1) var(--ease-out);
}
.ft-btn:active{ transform: translateY(1px); }

.ft-btn--primary{
  border: var(--ft-bw-1) solid transparent;
  background:
    linear-gradient(180deg, rgba(139,43,255,.36), rgba(43,75,255,.22)) padding-box,
    var(--ft-grad) border-box;
  box-shadow: var(--e-1);
}
.ft-btn--primary:hover{
  background:
    linear-gradient(180deg, rgba(139,43,255,.48), rgba(43,75,255,.3)) padding-box,
    var(--ft-grad) border-box;
  box-shadow: var(--e-2);
}

.ft-btn--ghost:hover{
  background: rgba(255,255,255,.08);
  border-color: var(--ft-line-2);
}

.ft-btn--sm{ padding: var(--s-2) var(--s-4); }
.ft-btn--lg{ padding: var(--s-4) var(--s-6); }
.ft-btn--block{ width: 100%; }

.ft-iconbtn{
  display: inline-grid;
  place-items: center;
  inline-size: 42px;
  block-size: 42px;
  padding: 0;
  border: var(--ft-border);
  border-radius: var(--r-btn);
  background: rgba(255,255,255,.04);
  color: var(--ft-text);
  cursor: pointer;
  transition: background-color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out);
}
.ft-iconbtn:hover{ background: rgba(255,255,255,.09); border-color: var(--ft-line-2); }
.ft-iconbtn .ft-ic{ inline-size: 20px; block-size: 20px; }

.ft-chip{
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  padding: var(--s-2) var(--s-3);
  border: var(--ft-border);
  border-radius: var(--r-chip);
  color: var(--ft-dim);
  font-size: var(--t-100);
  font-weight: 500;
  transition: color var(--dur-1) var(--ease-out), background-color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out);
}
.ft-chip.is-on{
  color: var(--ft-text);
  background: rgba(139,43,255,.22);
  border-color: rgba(139,43,255,.62);
}

/* A hairline aside under a block of content. Not a card. */
.ft-note{
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-3);
  align-items: start;
  margin-block-start: var(--s-6);
  padding-block-start: var(--s-5);
  border-block-start: var(--ft-border);
  max-width: 78ch;
  color: var(--ft-dim);
}
.ft-note .ft-ic{ inline-size: 20px; block-size: 20px; margin-block-start: .1em; }


/* ==========================================================================
   4. Skip link + scroll sentinel
   ========================================================================== */
.ft-skip{
  position: fixed;
  inset-block-start: var(--s-3);
  inset-inline-start: var(--s-3);
  z-index: 2000;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-btn);
  background: var(--ft-surface-2);
  border: var(--ft-border-2);
  color: var(--ft-text);
  font-weight: 500;
  text-decoration: none;
  transform: translateY(-160%);
  transition: transform var(--dur-2) var(--ease-out);
}
.ft-skip:focus{ transform: none; }

/* Watched by IntersectionObserver so the navbar never needs a scroll listener. */
.ft-sentinel{
  position: absolute;
  inset-block-start: 24px;
  inset-inline-start: 0;
  inline-size: 1px;
  block-size: 1px;
  pointer-events: none;
}


/* ==========================================================================
   5. Navbar + offcanvas menu
   ========================================================================== */
.ft-nav{
  position: sticky;
  inset-block-start: 0;
  z-index: 1040;
  display: flex;
  align-items: center;
  block-size: var(--nav-h);
  border-block-end: var(--ft-bw-1) solid transparent;
  transition:
    background-color var(--dur-2) var(--ease-out),
    border-color     var(--dur-2) var(--ease-out);
}
.ft-nav.is-stuck{
  background: rgba(10,4,26,.74);
  border-block-end-color: var(--ft-line);
  -webkit-backdrop-filter: var(--blur-glass);
          backdrop-filter: var(--blur-glass);
}

.ft-nav__inner{
  display: flex;
  align-items: center;
  gap: var(--s-5);
  inline-size: 100%;
  max-width: calc(var(--wrap) + var(--gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.ft-nav__brand{ display: inline-flex; align-items: center; flex: none; }
/* The raster lockup carries transparent padding — its ink fills only 60.5% of
   the file's height (594x133 ink inside a 660x220 box). The retired SVG was
   tight-cropped, so its 30px box was 30px of visible mark; the same 30px here
   would render an 18px logo. 50px of box is ~30px of ink, matching the old
   optical size. */
/* The small size is the base, because the burger runs all the way to
   991px — 62px of lockup beside a single hamburger is the loudest thing on
   the bar. The full size is restored at 992 alongside the anchor nav. */
.ft-nav__brand img{ block-size: 46px; inline-size: auto; }
.ft-nav.is-stuck .ft-nav__brand img{ block-size: 40px; }

.ft-nav__links{ display: none; }
.ft-nav__links a{
  position: relative;
  padding-block: var(--s-2);
  color: var(--ft-muted);
  text-decoration: none;
  font-weight: 500;
  transition: color var(--dur-1) var(--ease-out);
}
.ft-nav__links a:hover{ color: var(--ft-text); }
.ft-nav__links a::after{
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  block-size: var(--ft-bw-2);
  border-radius: var(--r-chip);
  background: var(--ft-grad);
  opacity: 0;
  transition: opacity var(--dur-1) var(--ease-out);
}
.ft-nav__links a[aria-current="true"]{ color: var(--ft-text); }
.ft-nav__links a[aria-current="true"]::after{ opacity: 1; }

.ft-nav__end{
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-inline-start: auto;
}
.ft-nav__cta{ display: none; }

.ft-menu{
  --bs-offcanvas-bg:           var(--ft-bg-2);
  --bs-offcanvas-color:        var(--ft-text);
  --bs-offcanvas-border-color: var(--ft-line);
  --bs-offcanvas-border-width: var(--ft-bw-1);
  --bs-offcanvas-width:        min(340px, 88vw);
  --bs-offcanvas-padding-x:    var(--s-5);
  --bs-offcanvas-padding-y:    var(--s-5);
  --bs-offcanvas-transition:   transform var(--dur-2) var(--ease-out);
}
/* Bootstrap declares --bs-backdrop-bg on .offcanvas-backdrop itself, so a
   :root override never reaches it. Matched at the same specificity instead;
   style.css loads after Bootstrap, so this wins. */
.offcanvas-backdrop{
  --bs-backdrop-bg: #070311;
  --bs-backdrop-opacity: .78;
}

/* Bootstrap's .offcanvas-header is a plain flex row — it pushes the dismiss
   control right with `margin-left:auto` on .btn-close, not with
   justify-content. This panel uses .ft-iconbtn instead of .btn-close, so
   nothing was doing the pushing and the close button sat jammed against the
   "Menu" title. The heading also has to give up the h2 bottom margin or it
   sits 6px above the button's centre line. */
.ft-menu__head{ border-block-end: var(--ft-border); }
.ft-menu__head > h2{ margin-block-end: 0; }
.ft-menu__logo{ block-size: 38px; inline-size: auto; }
.ft-menu__head > .ft-iconbtn{ margin-inline-start: auto; }
.ft-menu__body{ display: flex; flex-direction: column; gap: var(--s-5); }
.ft-menu__links{ display: flex; flex-direction: column; }
.ft-menu__links a{
  padding-block: var(--s-3);
  border-block-end: var(--ft-border);
  color: var(--ft-muted);
  text-decoration: none;
  font-weight: 500;
}
.ft-menu__links a:hover{ color: var(--ft-text); }


/* ==========================================================================
   6. Hero
   ========================================================================== */
.ft-hero{ padding-block-start: var(--s-7); }

.ft-hero__grid{
  display: grid;
  gap: var(--s-7);
  align-items: center;
}

.ft-hero__copy > .ft-lead{
  margin-block-start: var(--s-5);
  max-width: 56ch;
  color: var(--ft-muted);
}

.ft-hero__cta{
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-block-start: var(--s-6);
}

.ft-facts{
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-5) var(--s-6);
  margin-block-start: var(--s-7);
  padding-block-start: var(--s-5);
  border-block-start: var(--ft-border);
}
.ft-fact{ display: flex; flex-direction: column; gap: var(--s-1); }
.ft-fact dt{ color: var(--ft-dim); }
.ft-fact dd{ color: var(--ft-text); }

/* The column holds the lattice and nothing else. It used to carry a caption
   underneath, which is why this was a flex column pinned to `start`; with the
   caption gone that would shrink the graph to its intrinsic width instead of
   letting it fill the track. */
.ft-hero__visual{
  position: relative;
  display: grid;
}


/* ==========================================================================
   7. Polygon hex lattice
      polygon-hero.svg is inlined at the FT-NETWORK-INJECT marker: one centre
      cell carrying the Polygon glyph, a ring of six around it and an outer
      ring that dissolves at the edge of the frame. Classes fixed by
      CHANGE-BRIEF-2 §5:
        <g class="ft-hex" data-ring="0|1|2">  with .ft-hex__face / .ft-hex__edge
        .ft-edge connectors, <path> with pathLength="100"
        one .ft-pulse per edge, inside <g class="ft-pulses">

      Default state is the finished, static lattice. main.js adds .is-live when
      the hero scrolls into view, and only then does anything move, so a page
      with JS switched off still shows the whole graph.
   ========================================================================== */
.ft-hero__net{
  position: relative;
  inline-size: 100%;
  min-block-size: 220px;
}
.ft-hero__net > svg{
  inline-size: 100%;
  block-size: auto;
  display: block;
  overflow: visible;
}

/* Stroke colour and width are deliberately NOT set here. The inlined SVG
   carries stroke="url(#ph-flow)" — pink at the centre, through violet and
   blue, to cyan at the rim — plus a per-ring width taper (2.6 on the centre
   spokes, down through 1.9 to 1.5 on the outermost connectors) that reads as
   the lattice thinning as it goes out. A CSS stroke/stroke-width would beat
   those presentation attributes and flatten both. Same rule for
   .ft-hex__face and .ft-hex__edge: opacity and timing here, never paint. */
.ft-edge{
  fill: none;
  stroke-linecap: round;
  stroke-dasharray: 100;
  stroke-dashoffset: 0;
}
.ft-hero__net.is-live .ft-edge{
  animation: ft-edge-draw var(--dur-3) var(--ease-out) var(--d, var(--d-fb, 0ms)) both;
}
/* main.js writes --d per edge. --d-fb is the fallback used when it cannot, and
   it follows the file's own order: the six centre spokes, then the outer
   connectors behind them, so the lattice draws itself from the middle out. */
.ft-edge:nth-child(-n+6){ --d-fb: 0ms; }
.ft-edge:nth-child(n+7) { --d-fb: 200ms; }
@keyframes ft-edge-draw{
  from{ stroke-dashoffset: 100; }
  to  { stroke-dashoffset: 0; }
}

/* Cells. The face and rim gradients belong to the SVG; the glow and the
   entrance are the only things set here, and the glow is the one place the
   centre cell is allowed to read hotter than the ring around it. The entrance
   is opacity alone — no scale. A transform on an SVG <g> depends on
   transform-box support to have a sane origin, and the lattice already has a
   moment of its own in the edges drawing themselves. */
.ft-hex[data-ring="0"]{ filter: drop-shadow(0 0 26px rgba(255,46,136,.34)); --d-fb: 0ms; }
.ft-hex[data-ring="1"]{ filter: drop-shadow(0 0 14px rgba(139,43,255,.26)); --d-fb: 130ms; }
.ft-hex[data-ring="2"]{ --d-fb: 260ms; }
.ft-hero__net.is-live .ft-hex{
  animation: ft-hex-in var(--dur-3) var(--ease-out) var(--d, var(--d-fb, 0ms)) both;
}
@keyframes ft-hex-in{
  from{ opacity: 0; }
  to  { opacity: 1; }
}

/* Value travelling inward. main.js reads each edge's own path data and writes
   it onto the matching pulse as an offset-path, so this works whatever
   coordinates the illustration ends up using.
   `fill` is NOT set here: the circles carry fill="url(#ph-pulse-ink)", a
   white-hot centre falling off to pink, and a CSS fill would flatten it the
   way it flattened nt-pulse in the tree. Only the glow colour is ours. */
.ft-pulse{
  opacity: 0;
  color: var(--pulse-color, var(--ft-pink));
  filter: drop-shadow(0 0 7px currentColor);
}

@supports (offset-path: path("M 0 0 L 1 1")){
  .ft-hero__net.is-live .ft-pulse{
    offset-rotate: 0deg;
    animation: ft-pulse-flow 3.4s linear
      calc(var(--d, 0ms) + var(--ring-lag, 0ms) + var(--ring-jit, 0ms)) infinite;
  }
}

/* The six centre spokes come first in the file, so they are the ones held
   back: the outer connectors fire, and the wave arrives at the middle after
   them. --ring-lag is added to whatever main.js writes rather than replacing
   it, so the reading stays inward either way. */
.ft-pulses .ft-pulse:nth-child(-n+6){ --ring-lag: 900ms; }
.ft-pulses .ft-pulse:nth-child(4n+2){ --ring-jit: 150ms; }
.ft-pulses .ft-pulse:nth-child(4n+3){ --ring-jit: 300ms; }
.ft-pulses .ft-pulse:nth-child(4n+4){ --ring-jit: 450ms; }

/* Every edge is authored outward from the centre cell, so travelling
   100% → 0% reads as value settling in. */
@keyframes ft-pulse-flow{
  0%   { offset-distance: 100%; opacity: 0; }
  14%  { opacity: 1; }
  86%  { opacity: 1; }
  100% { offset-distance: 0%;   opacity: 0; }
}

/* Static fallback: no motion path support, or main.js could not read the edge
   geometry. The lattice still reads correctly, it just does not flow. */
@supports not (offset-path: path("M 0 0 L 1 1")){
  .ft-pulse{ display: none; }
}
.ft-hero__net.ft-net--static .ft-pulse{ display: none; }
/* No offset-path support: the pulses are hidden, so lift the edges slightly
   to carry the section on their own. Opacity, not a flat colour override,
   so the brand gradient survives. */
.ft-hero__net.ft-net--static .ft-edge{ opacity: 1; }


/* ==========================================================================
   8. Ticker strip
   ========================================================================== */
.ft-ticker{
  margin-block-start: var(--s-7);
  border-block: var(--ft-border);
  background: rgba(255,255,255,.02);
  overflow: clip;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.ft-ticker__track{
  display: flex;
  inline-size: max-content;
  animation: ft-marquee 48s linear infinite;
}
.ft-ticker.is-paused .ft-ticker__track{ animation-play-state: paused; }
/* typography.css caps every ul/ol at 68ch for prose measure. These two lists
   are a marquee track, not prose — the cap clamped each set to ~705px and the
   marquee tore open a gap on any viewport wider than that. */
.ft-ticker__set{ display: flex; max-width: none; }
.ft-ticker__set li{
  position: relative;
  padding: var(--s-3) var(--s-5);
  color: var(--ft-dim);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.ft-ticker__set li::after{
  content: "";
  position: absolute;
  inset-inline-end: 0;
  inset-block-start: 50%;
  translate: 0 -50%;
  inline-size: 1px;
  block-size: 14px;
  background: var(--ft-line-2);
}
@keyframes ft-marquee{
  from{ transform: translateX(0); }
  to  { transform: translateX(-50%); }
}


/* ==========================================================================
   9. Proof strip
      One wide panel split by hairlines. The 1px grid gap draws the hairlines,
      which keeps them perfectly even at every breakpoint.
   ========================================================================== */
.ft-proof{ padding-block: var(--s-7); }
.ft-proof__panel{
  display: grid;
  gap: 1px;
  background: var(--ft-line);
  border: var(--ft-border);
  border-radius: var(--r-panel);
  overflow: hidden;
  box-shadow: var(--e-1);
}
.ft-proof__cell{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-6) var(--s-5);
  background: linear-gradient(180deg, rgba(28,16,56,.78), rgba(12,5,32,.78));
}
.ft-proof__cell .ft-label{ color: var(--ft-dim); }
.ft-proof__note{ margin-block-start: var(--s-4); color: var(--ft-dim); }


/* ==========================================================================
   10. How it works
   ========================================================================== */
.ft-steps{
  position: relative;
  display: grid;
  gap: var(--s-6);
}
.ft-step{ position: relative; }
.ft-step__mark{
  display: grid;
  place-items: center;
  inline-size: 46px;
  block-size: 46px;
  margin-block-end: var(--s-4);
  border: var(--ft-border-2);
  border-radius: var(--r-chip);
  background: var(--ft-bg-2);
  box-shadow: var(--ft-hairline);
  position: relative;
  z-index: 1;
}
.ft-step h3{ margin-block-end: var(--s-3); }
.ft-step p{ color: var(--ft-muted); max-width: 44ch; }


/* ==========================================================================
   16. Security + contract panel
   ========================================================================== */
.ft-security__grid{ display: grid; gap: var(--s-7); align-items: start; }

.ft-seclist{ display: grid; }
.ft-seclist li{
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-4);
  padding-block: var(--s-5);
  border-block-start: var(--ft-border);
}
.ft-seclist li:last-child{ border-block-end: var(--ft-border); }
.ft-seclist > li > .ft-ic{
  inline-size: 24px;
  block-size: 24px;
  margin-block-start: .12em;
  color: var(--ft-cyan);
}
.ft-seclist h3{ margin-block-end: var(--s-2); }
.ft-seclist p{ color: var(--ft-muted); max-width: 62ch; }

.ft-netpanel{ display: grid; align-content: start; }
/* The illustration is the panel. No border, no card — it sits on the page
   ground with its own glow. */
.ft-netfig{
  display: grid;
  justify-items: center;
  gap: var(--s-4);
  margin: 0;
}
.ft-netfig img{
  inline-size: min(100%, 440px);
  block-size: auto;
  /* Drawn on a transparent ground, so it carries its own glow. */
  filter: drop-shadow(0 14px 40px rgba(139,43,255,.34));
}
.ft-netfig__cap{
  display: grid;
  justify-items: center;
  gap: var(--s-1);
  text-align: center;
}
.ft-netfig__net{
  font-family: var(--font-display);
  font-size: var(--t-600);
  font-weight: 600;
  letter-spacing: -.008em;
  color: var(--ft-text);
}
.ft-netfig__tok{ color: var(--ft-dim); font-size: var(--t-300); }

.ft-security__audit{ margin-block-start: var(--s-5); color: var(--ft-dim); max-width: 62ch; }




/* ==========================================================================
   17. Roadmap
       A vertical spine. The dot sits on the spine, the card sits beside it.
   ========================================================================== */
/* The gutter that holds the spine lives on the list items, not on the <ol>.
   tokens.css zeroes padding on any ol[class], and the dot has to share a left
   edge with the spine, so both are measured from the same box. */
.ft-road{
  position: relative;
  display: grid;
  gap: var(--s-5);
  /* Runs the full container. It was previously capped at --wrap-tight because
     a prose card at 1240px left its right third empty; the cards now carry a
     third column of phase deliverables, so the width is occupied rather than
     merely allowed. */
}
.ft-road::before{
  content: "";
  position: absolute;
  inset-block: var(--s-5);
  inset-inline-start: 8px;
  inline-size: 2px;
  border-radius: var(--r-chip);
  background: linear-gradient(180deg, var(--ft-pink), var(--ft-violet) 38%, var(--ft-blue) 72%, rgba(34,211,238,.15));
}

.ft-road__item{ position: relative; padding-inline-start: var(--s-6); }
.ft-road__dot{
  position: absolute;
  inset-block-start: var(--s-5);
  inset-inline-start: 0;
  inline-size: 18px;
  block-size: 18px;
  border: var(--ft-bw-3) solid var(--ft-line-2);
  border-radius: var(--r-chip);
  background: var(--ft-bg-2);
}
.ft-road__item.is-current .ft-road__dot{
  border-color: var(--ft-pink);
  background: var(--ft-pink);
  box-shadow: 0 0 0 5px rgba(255,46,136,.16);
}

.ft-road__card{
  display: grid;
  gap: var(--s-3);
  padding: var(--s-5);
  border: var(--ft-border);
  border-radius: var(--r-card);
  background: linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,.012));
}
.ft-road__item.is-current .ft-road__card{
  border-color: rgba(255,46,136,.34);
  background: linear-gradient(180deg, rgba(255,46,136,.09), rgba(255,255,255,.012));
}
.ft-road__meta{ display: flex; align-items: center; gap: var(--s-3); color: var(--ft-dim); }
.ft-road__now{
  padding: 2px var(--s-3);
  border: var(--ft-bw-1) solid rgba(255,46,136,.45);
  border-radius: var(--r-chip);
  background: rgba(255,46,136,.14);
  color: #FFC5DD;
  font-size: var(--t-100);
  font-weight: 500;
}
/* Was p:last-child; the deliverables list is now the last child, so target the
   prose directly. */
.ft-road__card > p.ft-body{ color: var(--ft-muted); max-width: 62ch; }

ul.ft-road__ships{
  display: grid;
  gap: var(--s-2);
  margin: 0;
  padding-block-start: var(--s-4);
  border-block-start: var(--ft-border);
  list-style: none;
}
.ft-road__ships li{
  position: relative;
  padding-inline-start: var(--s-4);
  color: var(--ft-muted);
  font-size: var(--t-300);
  line-height: 1.45;
}
.ft-road__ships li::before{
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: .58em;
  inline-size: 6px;
  block-size: 6px;
  border-radius: var(--r-chip);
  background: var(--ft-violet);
}
.ft-road__item.is-current .ft-road__ships li::before{ background: var(--ft-pink); }


/* ==========================================================================
   18. FAQ accordion
       Bootstrap's accordion is light-themed down to the chevron image, so
       every one of its custom properties is re-pointed here, including the
       two data-URI icons.
   ========================================================================== */
.ft-faq{
  --bs-accordion-color:                  var(--ft-text);
  --bs-accordion-bg:                     transparent;
  --bs-accordion-border-color:           var(--ft-line);
  --bs-accordion-border-width:           var(--ft-bw-1);
  --bs-accordion-border-radius:          var(--r-card);
  --bs-accordion-inner-border-radius:    var(--r-card);
  --bs-accordion-btn-color:              var(--ft-text);
  --bs-accordion-btn-bg:                 transparent;
  --bs-accordion-btn-padding-x:          var(--s-5);
  --bs-accordion-btn-padding-y:          var(--s-4);
  --bs-accordion-btn-focus-box-shadow:   none;
  --bs-accordion-btn-icon-width:         1.1rem;
  --bs-accordion-btn-icon-transform:     rotate(-180deg);
  --bs-accordion-btn-icon-transition:    transform var(--dur-2) var(--ease-out);
  --bs-accordion-btn-icon:               url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23A093C0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  --bs-accordion-btn-active-icon:        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FF2E88' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  --bs-accordion-active-color:           var(--ft-text);
  --bs-accordion-active-bg:              rgba(139,43,255,.14);
  --bs-accordion-body-padding-x:         var(--s-5);
  --bs-accordion-body-padding-y:         var(--s-4);
  --bs-accordion-transition:             var(--dur-2) var(--ease-out);
}
.ft-faq .accordion-item{
  margin-block-end: var(--s-2);
  border: var(--ft-border);
  border-radius: var(--r-card);
  background: linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,.012));
  overflow: hidden;
}
.ft-faq .accordion-item:last-child{ margin-block-end: 0; }
/* The <h3> wrapping each question carries .ft-h3 correctly, but Bootstrap's
   .accordion-button{font-size:1rem} styles the <button> inside it and one
   class beats one element selector — so every question was rendering at 16px,
   the exact default the brand contract bans. Restate the h3 role on the
   button itself. */
.ft-faq .accordion-button{
  font-family: var(--font-display);
  font-size: var(--t-500);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -.004em;
}
.ft-faq .accordion-button:hover{ color: var(--ft-text); }
.ft-faq .accordion-body p{ color: var(--ft-muted); max-width: 68ch; }


/* ==========================================================================
   20. Final CTA — the only centred block on the page
   ========================================================================== */
.ft-final{ padding-block: var(--s-8) var(--s-7); }
.ft-final__inner{
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-4);
  text-align: center;
}
.ft-final__inner h2{ max-width: 20ch; }
.ft-final__inner p{ max-width: 56ch; color: var(--ft-muted); }
.ft-final__inner .ft-btn{ margin-block-start: var(--s-3); }
.ft-final__inner .ft-legal{ color: var(--ft-dim); }


/* ==========================================================================
   21. Footer
   ========================================================================== */
.ft-foot{
  border-block-start: var(--ft-border);
  background: rgba(7,3,17,.55);
  padding-block: var(--s-7);
}
.ft-foot__top{ display: grid; gap: var(--s-7); }
/* align-content: start, because a grid whose tracks are all `auto` stretches
   them to fill a container sized by a taller sibling — the brand column was
   203px tall for ~110px of content and the badge, the line and the tagline
   drifted apart to fill it. */
.ft-foot__brand{
  display: grid;
  align-content: start;
  gap: var(--s-3);
  justify-items: start;
}
.ft-foot__brand img{ inline-size: 44px; block-size: 44px; }
.ft-foot__line{ color: var(--ft-muted); max-width: 34ch; }
.ft-foot__tag{ color: var(--ft-dim); letter-spacing: .12em; font-size: var(--t-100); }

.ft-foot__cols{ display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: var(--s-6) var(--s-5); }
.ft-foot__col .ft-label{ color: var(--ft-dim); }
.ft-foot__list{ display: grid; gap: var(--s-2); }
.ft-foot__col .ft-foot__list{ margin-block-start: var(--s-3); }
.ft-foot__col a{ color: var(--ft-muted); text-decoration: none; }
.ft-foot__col a:hover{ color: var(--ft-text); }
.ft-foot__col .ft-legal{ margin-block-start: var(--s-3); color: var(--ft-dim); max-width: 32ch; }

.ft-foot__bottom{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  margin-block-start: var(--s-7);
  padding-block-start: var(--s-5);
  border-block-start: var(--ft-border);
  color: var(--ft-dim);
}
.ft-social{ display: flex; gap: var(--s-2); }
.ft-social a{
  display: grid;
  place-items: center;
  inline-size: 40px;
  block-size: 40px;
  border: var(--ft-border);
  border-radius: var(--r-chip);
  color: var(--ft-muted);
  transition: color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out), background-color var(--dur-1) var(--ease-out);
}
.ft-social a:hover{ color: var(--ft-text); border-color: var(--ft-line-2); background: rgba(255,255,255,.05); }
.ft-social .ft-ic{ inline-size: 19px; block-size: 19px; }


/* ==========================================================================
   22. Breakpoints
       Verified at 360 / 390 / 768 / 1024 / 1280 / 1440 / 1600. Nothing below is
       allowed to introduce a horizontal scrollbar.
   ========================================================================== */

/* --- below 640px: phone rhythm, and the lattice goes full bleed ----------- */
@media (max-width: 639.98px){
  /* Every section on a phone is a single stacked column on a ~700px screen,
     so the desktop rhythm reads as dead ground rather than as rest. Section
     padding drops a step to 38px a side — 76px between sections — and the
     stacked grids come down with it, because a 38px gap between two cards
     that are already full-width is a gap the page ran out of things to fill.
     Desktop is untouched. */
  .ft-sec{ padding-block: var(--s-6); }
  .ft-sechead{ margin-block-end: var(--s-5); }
  .ft-proof,
  .ft-final{ padding-block: var(--s-7) var(--s-6); }
  .ft-foot{ padding-block: var(--s-6); }
  .ft-hero__grid{ gap: var(--s-5); }
  .ft-facts{ margin-block-start: var(--s-5); }
  .ft-ticker{ margin-block-start: var(--s-5); }

  /* Stacked card grids: four steps with a 38px gap spend 114px on air alone. */
  .ft-steps{ gap: var(--s-5); }
  .ft-core__grid,
  .ft-pillars,
  .ft-mvv__grid,
  .ft-road{ gap: var(--s-4); }
  .ft-what__grid{ gap: var(--s-5); }
  .ft-security__grid{ gap: var(--s-5); }
  .ft-why__close{ margin-block-start: var(--s-5); padding-block-start: var(--s-4); }

  .ft-seclist li{ padding-block: var(--s-4); }

  /* The lattice takes the whole screen: its outer ring is drawn dissolving,
     so holding it inside the gutter boxes in an illustration that is meant to
     run off the edge. Width and margin cancel exactly, so this cannot widen
     the page. */
  .ft-hero__net{
    margin-inline: calc(var(--gutter) * -1);
    inline-size: calc(100% + var(--gutter) * 2);
  }
}

/* --- 640 to 992: the lattice is capped -----------------------------------
   The column is wide enough here that a full-width lattice would be 700px of
   decorative element before the reader reaches the next section. Capped and
   centred in its own block; the copy above it stays left-aligned. */
@media (min-width: 640px) and (max-width: 991.98px){
  .ft-hero__net{ inline-size: min(100%, 560px); margin-inline: auto; }
}

/* --- 520px: the calculator output grid stops being one column ------------ */
@media (max-width: 519.98px){
  /* Two CTAs of different widths stacked on top of each other read as a
     mistake. On one column they share an edge. */
  .ft-hero__cta{ display: grid; grid-template-columns: minmax(0, 1fr); }

}

/* --- 640px --------------------------------------------------------------- */
/* The footer link columns stay at the base two. There used to be a third
   (Legal) and this block widened the grid to match; with two, a three-track
   grid left the right third empty. */

/* --- 768px --------------------------------------------------------------- */
@media (min-width: 768px){
  .ft-proof__panel{ grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Four steps now, not three. */
  .ft-steps{ grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-5); }
  .ft-steps::before{
    content: "";
    position: absolute;
    inset-block-start: 23px;
    inset-inline: 0;
    block-size: 1px;
    background: linear-gradient(90deg, transparent, var(--ft-line-2) 10%, var(--ft-line-2) 90%, transparent);
  }

  .ft-proof__panel{ grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --- 992px: the desktop layout ------------------------------------------- */
@media (min-width: 992px){
  /* The anchor nav and the CTA replace the burger. */
  .ft-nav__links{ display: flex; gap: var(--s-5); margin-inline: auto; }
  .ft-nav__cta{ display: inline-flex; }
  .ft-nav__brand img{ block-size: 62px; }
  .ft-nav.is-stuck .ft-nav__brand img{ block-size: 52px; }
  .ft-nav__burger{ display: none; }

  /* Copy left, lattice right. */
  .ft-hero__grid{ grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }

  /* The three-up and two-up blocks have the room from here; only the core
     strip's four columns wait for 1100. */
  .ft-what__grid{ grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: var(--s-7); align-items: center; }
  .ft-pillars{ grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ft-mvv__grid{ grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ft-faqsec__grid{ grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: var(--s-7); align-items: start; }
  .ft-faqsec__head{ margin-block-end: 0; position: sticky; top: calc(var(--nav-h) + var(--s-5)); }

  /* The lattice is allowed past the container edge — its outer ring is drawn
     dissolving, so the frame ending mid-cell is the point. body has
     overflow-x: clip, so nothing here can produce a scrollbar. */
  .ft-hero__visual{ margin-inline-end: calc(var(--gutter) * -1); }

  /* Brand line on the left, link columns on the right. The split was 1fr/2fr
     when there were three link columns to fill that track; with two, the
     wider track just spread them apart, so the brand column takes the space
     back. Below this width the footer is a single column. */
  .ft-foot__top{ grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr); }

  .ft-security__grid{ grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--s-8); }
  .ft-netpanel{ position: sticky; inset-block-start: calc(var(--nav-h) + var(--s-4)); }

  .ft-road__item{ padding-inline-start: var(--s-7); }
  .ft-road::before{ inset-inline-start: 12px; }
  .ft-road__dot{ inline-size: 26px; block-size: 26px; }

  /* Three tracks at full width: phase label, the prose, and what actually
     ships in the phase. The third column is why the roadmap can run the full
     container without leaving the right third empty. */
  .ft-road__card{
    grid-template-columns: 132px minmax(0, 1fr) minmax(0, 300px);
    column-gap: var(--s-6);
    align-items: start;
  }
  .ft-road__meta{
    grid-row: 1 / span 2;
    flex-direction: column;
    align-items: start;
    gap: var(--s-3);
  }
  /* :not() matters — .ft-road__meta is itself a <p>. */
  .ft-road__card > h3,
  .ft-road__card > p:not(.ft-road__meta){ grid-column: 2; }
  .ft-road__card > .ft-road__ships{
    grid-column: 3;
    grid-row: 1 / span 2;
    margin: 0;
    padding-inline-start: var(--s-5);
    border-inline-start: var(--ft-border);
    border-block-start: 0;
    padding-block-start: 0;
  }
}

/* --- 992–1200px: proof figures in a four-up panel ------------------------
   Four cells across a 948px panel leave each figure a 180px content box, and
   "4,182,650" set in tabular Open Sans 700 at --t-900 (41.6px here) measures
   198px — it crossed the hairline into the next cell. One step down for this
   band only; from 1200px the cell is wide enough for the full size. */
@media (min-width: 992px) and (max-width: 1199.98px){
  .ft-proof__cell .ft-num--lg{ font-size: var(--t-800); }
}

/* --- 1100px -------------------------------------------------------------- */
@media (min-width: 1100px){
  /* Four across needs the width: below this the strip drops to two columns
     and the one-line descriptions start wrapping to three. */
  .ft-core__grid{ grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-5); }
}

/* --- 1440px -------------------------------------------------------------- */
@media (min-width: 1440px){
  /* More bleed the wider it gets, so the lattice keeps growing with the
     viewport instead of leaving a widening margin down the right edge. */
  .ft-hero__visual{ margin-inline-end: min(-6vw, calc(var(--gutter) * -1)); }
}


/* ==========================================================================
   22a. What FOTON is  /  Why FOTON
        Two explanatory sections. The first pairs prose with a spec table so a
        reader who only scans the right-hand column still leaves with the four
        facts. The second is three pillars and a closing statement.
   ========================================================================== */
/* --- Core features: the 4-up strip the references open with ------------- */
.ft-core__grid{ display: grid; gap: var(--s-4); }
.ft-core__item{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding-block: var(--s-5);
  padding-inline-end: var(--s-5);
  border-block-start: var(--ft-bw-2) solid transparent;
  border-image: var(--ft-grad) 1;
  border-image-slice: 1;
  border-inline: 0;
  border-block-end: 0;
}
.ft-core__item h3{ font-size: var(--t-500); }
.ft-core__item p{ color: var(--ft-muted); font-size: var(--t-300); line-height: 1.55; max-width: 34ch; }

.ft-what__grid{ display: grid; gap: var(--s-6); }
.ft-what__copy{ display: grid; gap: var(--s-4); align-content: start; }

/* The About visual: the badge on a glass panel with the line the deck
   closes on. The references pair their About copy with an image here. */
/* Sized to sit close to the height of the copy beside it. At 176px with s-7
   padding the panel ran ~370px against the copy's ~150px, and the row's
   centring turned that difference into a band of empty ground above the
   prose. */
.ft-whatfig{
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--s-5);
  margin: 0;
  padding: var(--s-5);
  border: var(--ft-border);
  border-radius: var(--r-panel);
  background:
    radial-gradient(60% 70% at 22% 50%, rgba(139,43,255,.20), transparent 72%),
    linear-gradient(180deg, rgba(255,255,255,.045), rgba(255,255,255,.012));
}
.ft-whatfig img{ inline-size: 108px; block-size: 108px; }
.ft-whatfig figcaption{
  color: var(--ft-text);
  font-size: var(--t-500);
  line-height: 1.4;
  text-wrap: balance;
}

.ft-spec{
  margin: 0;
  border: var(--ft-border);
  border-radius: var(--r-card);
  background: linear-gradient(180deg, rgba(255,255,255,.045), rgba(255,255,255,.012));
  overflow: hidden;
}
/* Label and value share a line from 520px up. Stacked, four rows made the
   table half again as tall as the prose beside it and left a block of empty
   ground under the copy column. */
.ft-spec__row{
  display: grid;
  gap: var(--s-1) var(--s-4);
  padding: var(--s-4) var(--s-5);
  border-block-start: var(--ft-border);
}
@media (min-width: 520px){
  .ft-spec__row{
    grid-template-columns: 116px minmax(0, 1fr);
    align-items: baseline;
  }
}
.ft-spec__row:first-child{ border-block-start: 0; }
.ft-spec dt{
  color: var(--ft-dim);
  font-size: var(--t-200);
  font-weight: 500;
}
.ft-spec dd{
  margin: 0;
  color: var(--ft-text);
  font-size: var(--t-400);
}

.ft-pillars{ display: grid; gap: var(--s-4); }
.ft-pillar{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-5);
  border: var(--ft-border);
  border-radius: var(--r-card);
  background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.012));
  transition:
    border-color var(--dur-2) var(--ease-out),
    box-shadow   var(--dur-2) var(--ease-out);
}
.ft-pillar:hover{ border-color: var(--ft-line-2); box-shadow: var(--e-1); }
.ft-pillar p{ color: var(--ft-muted); font-size: var(--t-300); line-height: 1.55; }

/* --- Mission / vision / how we work, three up ---------------------------- */
.ft-mvv__grid{ display: grid; gap: var(--s-4); }
.ft-mvv__card{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-5);
  border: var(--ft-border);
  border-radius: var(--r-card);
  background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.012));
  transition: border-color var(--dur-2) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
}
.ft-mvv__card:hover{ border-color: var(--ft-line-2); box-shadow: var(--e-1); }
.ft-mvv__card p{ color: var(--ft-muted); font-size: var(--t-300); line-height: 1.55; }

ul.ft-mvv__list{
  display: grid;
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}
.ft-mvv__list li{
  position: relative;
  padding-inline-start: var(--s-4);
  color: var(--ft-muted);
  font-size: var(--t-300);
  line-height: 1.5;
}
.ft-mvv__list li::before{
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: .6em;
  inline-size: 6px;
  block-size: 6px;
  border-radius: var(--r-chip);
  background: var(--ft-cyan);
}

/* --- FAQ: heading column beside the accordion, as in the references ------ */
.ft-faqsec__grid{ display: grid; gap: var(--s-6); }
.ft-faqsec__aside{
  margin-block-start: var(--s-4);
  padding-block-start: var(--s-4);
  border-block-start: var(--ft-border);
  color: var(--ft-dim);
  max-width: 34ch;
}
.ft-faqsec__cta{ margin-block-start: var(--s-5); justify-self: start; }

/* The one line the section is arguing toward, so it is given the gradient
   rule and the room rather than being dropped in as another paragraph. */
.ft-why__close{
  margin-block-start: var(--s-6);
  padding-block-start: var(--s-5);
  border-block-start: var(--ft-border);
  max-width: 62ch;
  color: var(--ft-text);
  font-size: var(--t-500);
  line-height: 1.5;
}


/* ==========================================================================
   22aa. Page-load and interaction polish

   The reveal system below handles everything the reader scrolls to. This
   block covers the two moments it cannot: what the page does when it first
   arrives, and what it does under the cursor.
   ========================================================================== */

/* --- Hero entrance ------------------------------------------------------
   The hero is above the fold, so the scroll observer never fires for it and
   it used to simply be there, fully formed, the instant the CSS parsed. It
   now deals itself in once.

   `is-armed` is added by main.js, never written into the markup — the same
   guard the reveal system uses. If the script does not run, nothing is
   hidden and the hero renders normally. */
.ft-hero.is-armed .ft-hero__copy > *,
.ft-hero.is-armed .ft-hero__visual{
  opacity: 0;
  translate: 0 18px;
}
.ft-hero.is-ready .ft-hero__copy > *,
.ft-hero.is-ready .ft-hero__visual{
  animation: ft-hero-in 720ms var(--ease-out) var(--d, 0ms) both;
}
@keyframes ft-hero-in{
  from{ opacity: 0; translate: 0 18px; }
  to  { opacity: 1; translate: none; }
}

/* --- Navbar condenses on scroll -----------------------------------------
   The bar already takes its glass background at 24px. It now also tightens,
   which is what makes the transition read as the page responding rather than
   as a colour swap. */
.ft-nav__inner{
  padding-block: var(--s-3);
  transition: padding-block var(--dur-2) var(--ease-out);
}
.ft-nav.is-stuck .ft-nav__inner{ padding-block: var(--s-2); }
/* Only the transition lives here. The sizes themselves are declared with the
   rest of the navbar, above the 992 breakpoint — put the stuck size in this
   block and it would sit after that media query at equal specificity, and the
   mobile value would win on desktop too. */
.ft-nav__brand img{ transition: block-size var(--dur-2) var(--ease-out); }

/* --- Buttons ------------------------------------------------------------
   The icon leads the label by a hair on hover. Small enough that it reads as
   responsiveness rather than as a thing that moved. */
.ft-btn .ft-ic{ transition: translate var(--dur-2) var(--ease-spring); }
.ft-btn:hover .ft-ic{ translate: -2px 0; }

/* --- FAQ ----------------------------------------------------------------
   Bootstrap's collapse handles the height; this smooths the chevron and the
   row's own colour so the two land together. */
.ft-faq .accordion-button::after{ transition: transform var(--dur-2) var(--ease-out), background-image 0s; }
.ft-faq .accordion-button{ transition: background-color var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out); }
.ft-faq .accordion-collapse{ transition-timing-function: var(--ease-out); }


/* ==========================================================================
   22b. Scroll reveal and interaction motion

   Two rules govern everything here.

   1. Reveals use the `translate` property, never `transform`. Several elements
      already own their `transform` — the rank steps carry their stepped
      offset in it, the plan flag is centred on the card edge with it — and a
      reveal written as a transform would wipe those out. `translate` is a
      separate property and composes with them.
   2. The travel is short (12px) and the curve has no overshoot. A long slide
      or a spring reads as a page performing at the reader; a short settle
      reads as the page arriving.

   Elements are tagged by main.js rather than in the markup, so the HTML stays
   about content. Stagger is written to --rd per child.
   ========================================================================== */
[data-reveal]{
  opacity: 0;
  translate: 0 12px;
  transition:
    opacity   var(--dur-3) var(--ease-out) var(--rd, 0ms),
    translate var(--dur-3) var(--ease-out) var(--rd, 0ms);
}
[data-reveal].is-in{
  opacity: 1;
  translate: none;
}

/* Interaction: what the reader touches responds. Borders and glow rather than
   a lift on every card — six sections of cards all rising on hover is the
   thing that reads as a template. */
.ft-pillar,
.ft-mvv__card,
.ft-road__card{
  transition:
    border-color var(--dur-2) var(--ease-out),
    box-shadow   var(--dur-2) var(--ease-out),
    background   var(--dur-2) var(--ease-out);
}
.ft-pillar:hover,
.ft-mvv__card:hover,
.ft-road__card:hover{
  border-color: var(--ft-line-2);
  box-shadow: var(--e-1);
}

.ft-ic,
.ft-tileic{ transition: color var(--dur-2) var(--ease-out); }


.ft-foot a,
.ft-nav__links a{ transition: color var(--dur-1) var(--ease-out); }


/* ==========================================================================
   22c. Phone card padding

   These belong with the rest of the ≤640 rules further up, but the components
   they override are declared after that block — at equal specificity the
   later declaration wins, so put there they simply never applied. Kept at the
   end of the file instead, which is the only place that beats every one of
   them. 26px of padding inside a card only ~326px wide across is a frame
   rather than breathing room; one step down recovers ~16px on each of the
   eighteen cards down the page.
   ========================================================================== */
@media (max-width: 639.98px){
  .ft-core__item,
  .ft-pillar,
  .ft-mvv__card,
  .ft-road__card,
  .ft-netfig{ padding: var(--s-4); }

  .ft-faq .accordion-button,
  .ft-faq .accordion-body{ padding-inline: var(--s-4); }

  /* At 18.1px a question like "What happens if contributions slow down?" ran
     to three lines in a 326px row. One step down holds most of them to two. */
  .ft-faq .accordion-button{ font-size: var(--t-400); line-height: 1.34; }
}


/* ==========================================================================
   23. Reduced motion
       Everything that moves on its own is stopped here. These selectors are
       one class deeper than the rules they override and the block is last in
       the file, so no !important is needed anywhere.
   ========================================================================== */
@media (prefers-reduced-motion: reduce){
  .ft-ticker .ft-ticker__track{ animation: none; transform: none; }

  /* The lattice is drawn in its finished state and nothing travels it. */
  .ft-hero__net.is-live .ft-edge{ animation: none; stroke-dashoffset: 0; }
  .ft-hero__net.is-live .ft-hex{ animation: none; opacity: 1; }
  .ft-hero__net .ft-pulse{ display: none; }

  .ft-btn:active{ transform: none; }
  .ft-skip{ transition: none; }

  /* The hero arrives fully formed, as it did before the entrance existed. */
  .ft-hero.is-armed .ft-hero__copy > *,
  .ft-hero.is-armed .ft-hero__visual,
  .ft-hero.is-ready .ft-hero__copy > *,
  .ft-hero.is-ready .ft-hero__visual{ opacity: 1; translate: none; animation: none; }

  .ft-nav__inner,
  .ft-nav__brand img,
  .ft-btn .ft-ic,
  .ft-faq .accordion-button,
  .ft-faq .accordion-button::after{ transition: none; }
  .ft-btn:hover .ft-ic{ translate: none; }

  /* Reveals resolve to their finished state with no travel and no fade. The
     content is never withheld — the observer still runs and still adds
     .is-in, but there is nothing left to animate. */
  [data-reveal],
  [data-reveal].is-in{ opacity: 1; translate: none; transition: none; }

  .ft-pillar,
  .ft-mvv__card,
  .ft-road__card{ transition: none; }
}
