/* FOTON — typography.css | @import must be the first rule; a comment may precede it. */
@import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700&display=swap");

/* ==========================================================================
   FOTON — typography.css
   Owner: Agent B (round 1) / Agent C2 (round 2 — display face).
   Colour/space/motion tokens live in tokens.css.
   Load order (BRAND-CONTRACT §8): bootstrap → tokens → typography → style

   --------------------------------------------------------------------------
   FOR AGENT C — paste these three tags into <head>, ABOVE the stylesheet
   links. The @import above is only a standalone-safety net; a <link> is
   faster because it does not block on this file being parsed first.

     <link rel="preconnect" href="https://fonts.googleapis.com">
     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
     <link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">

   Weights requested are exactly the weights used, no more:
     Open Sans 400 / 500 / 600 / 700 / 800 — one family for the whole page

   Unbounded is no longer requested anywhere. If you find it in a <link>,
   delete it — nothing in this file references the family.
   --------------------------------------------------------------------------

   Scale: base 17px, ratio 1.26. See docs/TYPE-SCALE.md for the derivation and
   the computed values at 360px and 1440px.
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. Metric-adjusted fallback faces

   Purpose: hold the layout still while the webfont downloads (display=swap
   paints the fallback first). The descriptors below are hand-calibrated to
   match apparent size and average advance width; they are not extracted from
   the font tables, so treat them as close enough to kill the visible reflow
   rather than as a claim of precision.

   These faces carry no url() source. If the local font is absent (most Linux,
   some macOS) the face simply fails to load and the stack falls through to
   the next family, which is the correct behaviour.
   -------------------------------------------------------------------------- */
/* One family, so one fallback face. Open Sans is a humanist sans with a large
   x-height and open counters; its closest local relative is Segoe UI on
   Windows and Helvetica on macOS, with Verdana as the wide-and-open backstop.
   Open Sans runs a little wider than Segoe UI, hence the 102% size-adjust; the
   ascent/descent overrides are divided by that adjust so the effective metrics
   land on Open Sans's own 106.9 / 29.3.

   These descriptors are hand-tuned from rendered measurements, NOT extracted
   from the font tables. They exist to kill the visible reflow on swap, not as
   a claim of precision. */
@font-face{
  font-family: "Open Sans Fallback";
  src: local("Segoe UI"), local("Helvetica Neue"), local("Verdana");
  font-weight: 400 800;
  font-style: normal;
  size-adjust: 102%;
  ascent-override: 104.8%;
  descent-override: 28.7%;
  line-gap-override: 0%;
}


/* --------------------------------------------------------------------------
   2. Families — BRAND-CONTRACT §3 stacks, with the metric-adjusted face
      slotted in behind the webfont and ahead of the real fallback.
   -------------------------------------------------------------------------- */
:root{
  /* Both roles resolve to the same family. They are kept as separate tokens
     so a future two-family pairing does not need every rule rewritten. */
  --font-display: "Open Sans","Open Sans Fallback","Segoe UI",Helvetica,Arial,sans-serif;
  --font-body:    "Open Sans","Open Sans Fallback","Segoe UI",Helvetica,Arial,sans-serif;
}


/* --------------------------------------------------------------------------
   3. The scale — base 17px, ratio 1.26

      Below the base the ratio is deliberately compressed (≈1.09 → 1.14).
      A full 1.26 step under 17px lands on 13.5 / 10.7 — too coarse for the
      three distinct small sizes dense financial UI needs (label, caption,
      legal). From --t-500 up, the clean 1.26 takes over:

        19.3 ×1.26 → 24.2 → 30.6 → 38.5 → 48.5

      and then the ladder leaves the ratio: --t-1000 (61.1) is retired and
      --t-1100 is held at a 63px ceiling, so the top three rungs read
      38.5 → 48.5 → 63. Both decisions are argued in place below.

      --t-700 and above are fluid between 360px and 1440px. The coefficients
      are solved, not guessed:

        B(vw) = (max − min) / 10.8        A(px) = min − B × 3.6

      Each one lands within 0.005px of its target at both ends.
   -------------------------------------------------------------------------- */
:root{
  /* fixed — small end, identical at every viewport */
  --t-100: 12px;     /* legal, disclaimer footnotes  */
  --t-200: 12.8px;   /* labels, table headers        */
  --t-300: 14.1px;   /* captions, secondary UI       */
  --t-400: 16px;     /* BODY                         */
  --t-500: 18.1px;   /* lead paragraph, h4           */
  --t-600: 22.7px;   /* h3                           */
  /* Fluid, not fixed. Held at 30.6px it overtook the fluid --t-800 below
     ~685px, so on a phone a metric figure outranked the section heading above
     it. Ramped to 24.2px at 360 it stays a step under h2 at every width.
     B = (30.6-24.2)/10.8 = .5926vw ; A = 24.2 - B*3.6 = 22.067px  */
  --t-700: clamp(22.7px, 20.667px + 0.5648vw, 28.8px);  /* metric figures (.ft-num) */

  /* fluid — 360px → 1440px */
  --t-800:  clamp(25.6px, 22.067px + 0.9815vw, 36.2px);  /* h2                     */
  --t-900:  clamp(28.8px, 23.2px + 1.5556vw, 45.6px);    /* h1, big figs, sub-disp */

  /* --t-1000 (32.2px -> 61.1px) is RETIRED. It sat 3% under --t-1100 from
     ~1200px up and 5% under it at 360px, so the "one rung down" the doc
     claimed did not exist to the eye. Round 1 left it open as a judgement
     call; it is closed here because the Sora swap removed the escape route.
     Sora is ~18% narrower than Unbounded, so the obvious fix — put the 77px
     ceiling back and let --t-1000 sit a real rung under it — was measured and
     rejected. See the ceiling note below. The convergence therefore had to be
     resolved at the other end: .ft-display--sm takes --t-900, and the weight
     step (700 against the 600 of the heading roles) carries the distinction.
     Top of the ladder is a clean 38.5 -> 48.5 -> 63.
     Do not reintroduce --t-1000; the gap in the numbering is deliberate. */

  /* Hero ceiling 63px, unchanged — and this was measured, not assumed. Round 1
     pulled it from 77px because Unbounded wrapped the headline to five lines.
     Sora is much narrower, so the ceiling was re-tested at 1440px against the
     real string in the 701.2px hero well, at line-height 1.02 / -0.018em:

       Unbounded 700 / 63px / -0.030em / lh .98  ->  3 lines, 185.2px tall
       Sora      700 / 63px                      ->  3 lines, 192.8px, 559.9px widest
       Sora      700 / 69px                      ->  3 lines, 211.1px, 613.2px widest
       Sora      700 / 77px                      ->  3 lines, 235.6px, 684.3px widest

     So Sora does NOT buy a line back: the breaks are set by "Stake on Polygon."
     being a sentence that has to hold one line, not by the width of the face,
     and the count is three at every size on the list. 77px stays inside the
     well, but line 1 then fills 684.3 of 701.2px — 97.6% — so one more word of
     copy or one narrower container puts it on four lines, which is the exact
     fragility round 1 pulled the ceiling to escape, and it adds 43px to the
     hero block above the CTAs. Nothing is bought and two risks are taken on.
     63px stays. Still meets the sub-640 ramp at 640px (51.96px).
     B = (63-51.96)/8 = 1.38vw ; A = 51.96 - B*6.4 = 43.128px  */
  --t-1100: clamp(40.6px, 40.48px + 1.3vw, 59.2px);      /* hero display */
}


/* --------------------------------------------------------------------------
   4. Element defaults — raw markup must already look right.
   -------------------------------------------------------------------------- */
body{
  font-family: var(--font-body);
  font-size: var(--t-400);
  font-weight: 400;
  line-height: 1.65;
  letter-spacing: 0;
  font-variant-ligatures: common-ligatures;
  -webkit-font-smoothing: antialiased;      /* light-on-dark needs this */
  -moz-osx-font-smoothing: grayscale;
}

h1,h2,h3,h4,h5,h6{
  font-family: var(--font-display);
  color: var(--ft-text);
  margin: 0 0 var(--s-3);
  text-wrap: balance;
  overflow-wrap: break-word;
}

/* Opening quotes and punctuation hang into the margin where supported —
   cheaper and far more robust than a hand-tuned negative margin. */
@supports (hanging-punctuation: first){
  h1,h2,h3,h4,h5,h6,blockquote{ hanging-punctuation: first; }
}

p{
  margin: 0 0 var(--s-4);
  max-width: 68ch;          /* BRAND-CONTRACT §3. Escape with .ft-measure-full */
  text-wrap: pretty;
}
p:last-child{ margin-bottom: 0; }

strong,b{ font-weight: 600; }     /* Roboto 700 is loaded */
small{ font-size: var(--t-300); }
/* Prose measure and prose rhythm, scoped to lists that are actually prose.
   tokens.css already fixes the convention — "only lists that have been given
   a class are treated as UI, not prose" — and these two rules have to honour
   it or they reach into every layout list on the page. Unscoped they were:
     · clamping .ft-steps / .ft-ladder / .ft-rail / .ft-road to 705px inside a
       1240px container, which cropped the rank volume figures to "1,500, POL"
     · adding 8px on top of every grid `gap`, which knocked steps 2 and 3 of
       "How it works" and three of the four footer social icons out of line. */
ul:not([class]),
ol:not([class]){ max-width: 68ch; }

ul:not([class]) > li + li,
ol:not([class]) > li + li{ margin-top: var(--s-2); }


/* --------------------------------------------------------------------------
   5. Heading roles

      Retuned for Open Sans. Open Sans is a humanist sans — wider than Roboto
      glyph for glyph, with a notably large x-height and open counters. Two
      consequences, and they pull in opposite directions:

        · It is wider, so the display end needs MORE negative tracking than
          Roboto did, not less, or a 63px headline sprawls.
        · Its large x-height makes lines look closer together than they are,
          so leading opens a step at every rung to compensate.

        role             was (Roboto)     now (Open Sans)
        .ft-display      1.04 / -.022em   1.06 / -.026em
        .ft-display--sm  1.08 / -.020em   1.10 / -.024em
        .ft-h1           1.06 / -.018em   1.08 / -.022em
        .ft-h2           1.12 / -.014em   1.14 / -.018em
        .ft-h3           1.24 / -.008em   1.26 / -.010em
        .ft-h4           1.34 / -.002em   1.36 / -.003em

      The curve keeps its shape: tracking tightens as size grows, leading
      opens as size shrinks.

      Weights: Open Sans is loaded at 400 / 500 / 600 / 700 / 800. There is no
      900 in the family, so the two display roles move from Roboto's Black to
      Open Sans's 800 ExtraBold — still a clear step above the 700 headings.
      Nothing here asks for a weight the request does not carry.
   -------------------------------------------------------------------------- */
h1,.ft-h1{
  font-family: var(--font-display);
  font-size: var(--t-900);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -.022em;
}

h2,.ft-h2{
  font-family: var(--font-display);
  font-size: var(--t-800);
  font-weight: 600;
  line-height: 1.14;
  letter-spacing: -.018em;
}

h3,.ft-h3{
  font-family: var(--font-display);
  font-size: var(--t-600);
  font-weight: 600;
  line-height: 1.26;
  letter-spacing: -.010em;
}

/* 600, not the old 500. Sora is requested at 600/700 only, and .ft-h4 is the
   busiest display role on the page — the three "How it works" steps, three of
   the four income tiles, all six rank cards and the four security points. A
   role asking for a weight that is not loaded is how a page ends up with a
   synthesised face in its most repeated heading. */
h4,.ft-h4{
  font-family: var(--font-display);
  font-size: var(--t-500);
  font-weight: 600;
  line-height: 1.36;
  letter-spacing: -.003em;
}

h5{
  font-family: var(--font-display);
  font-size: var(--t-400);
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0;
}

h6{
  font-family: var(--font-display);
  font-size: var(--t-300);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: .006em;
}


/* --------------------------------------------------------------------------
   6. Display roles — declared after the heading roles so .ft-display wins
      when it is applied to an <h1>.

      .ft-display      the one hero headline
      .ft-display--sm  the closing CTA headline, one rung down

      .ft-display--sm sits on --t-900 now, not the retired --t-1000, so it is
      genuinely a rung below the display instead of 3% below it. Sora 700
      against the 600 the heading roles use keeps the two apart at that size.
   -------------------------------------------------------------------------- */
.ft-display{
  font-family: var(--font-display);
  font-size: var(--t-1100);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -.026em;
  text-wrap: balance;
}

.ft-display--sm{
  font-family: var(--font-display);
  font-size: var(--t-900);
  font-weight: 700;
  line-height: 1.10;
  letter-spacing: -.024em;
  text-wrap: balance;
}


/* --------------------------------------------------------------------------
   7. Prose roles
   -------------------------------------------------------------------------- */
.ft-lead{
  font-family: var(--font-body);
  font-size: var(--t-500);
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: 0;
  max-width: 62ch;
  color: var(--ft-muted);
  margin: 0 0 var(--s-5);
  text-wrap: pretty;
}

.ft-body{
  font-family: var(--font-body);
  font-size: var(--t-400);
  font-weight: 400;
  line-height: 1.65;
  max-width: 68ch;
  text-wrap: pretty;
}

/* Small sizes take positive tracking — the opposite of the display end. */
.ft-small{
  font-family: var(--font-body);
  font-size: var(--t-300);
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: .006em;
  color: var(--ft-muted);
}

.ft-legal{
  font-family: var(--font-body);
  font-size: var(--t-100);
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: .012em;
  color: var(--ft-dim);
  max-width: 76ch;
}


/* --------------------------------------------------------------------------
   8. Numerals — every figure on the page. Tabular so digits stay in column
      when a value ticks; lining so they sit on the cap line.
   -------------------------------------------------------------------------- */
/* The modifiers are self-sufficient on purpose — .ft-num--lg works with or
   without .ft-num next to it, so a missing base class cannot silently drop
   the tabular figures. */
.ft-num,
.ft-num--sm,
.ft-num--lg{
  font-family: var(--font-body);
  font-weight: 600;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;   /* belt and braces */
}

.ft-num{     font-size: var(--t-700); line-height: 1.02; }
.ft-num--sm{ font-size: var(--t-500); line-height: 1.15; }
.ft-num--lg{ font-size: var(--t-900); line-height: .98; letter-spacing: -.024em; }


/* --------------------------------------------------------------------------
   9. Labels — form fields, table headers, small captions.

      Sentence case. Not uppercase, not tracked out: BRAND-CONTRACT §9 bans
      the ALL-CAPS tracked eyebrow. text-transform is pinned to none so an
      inherited uppercase can never reintroduce it.
   -------------------------------------------------------------------------- */
.ft-label{
  font-family: var(--font-body);
  font-size: var(--t-200);
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ft-muted);
}


/* --------------------------------------------------------------------------
   10. Gradient text — the brand gradient painted through the glyphs.

       Whole headings or a standalone figure ONLY. Never one word inside a
       sentence (BRAND-CONTRACT §9). Counts against the "max 3 gradient
       placements per viewport" budget in §2.
   -------------------------------------------------------------------------- */
.ft-gradient-text{
  background-image: var(--ft-grad);
  background-size: 100% 100%;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

/* Safari only ever shipped the prefixed form, so both are tested. */
@supports not ((background-clip: text) or (-webkit-background-clip: text)){
  .ft-gradient-text{
    background-image: none;
    color: var(--ft-text);
    -webkit-text-fill-color: currentColor;
  }
}


/* --------------------------------------------------------------------------
   11. Measure escape hatch — for prose inside a narrow card or grid cell
       where the 68ch cap would leave a ragged, half-empty column.
   -------------------------------------------------------------------------- */
.ft-measure-full{ max-width: none; }


/* --------------------------------------------------------------------------
   12. Narrow viewports (≤640px)

       a) --t-1100 gets a steeper, lower ramp: 34px at 360 → 51.9px at 640.
          The base clamp would still be sitting at 43.2px on a 360px screen,
          which overflows a long word inside a 324px content box. The two
          ramps meet at 640px within 0.06px, so there is no visible step at
          the breakpoint.
       b) Tracking relaxes further. Negative tracking that reads as confident
          at 63px reads as cramped at 34px. The desktop values are already
          about half what Unbounded needed, so these land close to zero.
   -------------------------------------------------------------------------- */
@media (max-width: 640px){
  /* The upper half of the scale steps down again on a phone. The fluid ramps
     for --t-700 to --t-900 are still climbing at 390px (h2 computes to 25.9,
     not its 25.6 floor), so lowering the floors would have changed nothing —
     the values are fixed outright for this range instead. The body end of the
     ladder is untouched: 16px body and 14.1px captions are already at the
     small end of comfortable. */
  :root{
    --t-600: 20.4px;   /* h3            */
    --t-700: 21px;     /* metric figure */
    --t-800: 23.5px;   /* h2            */
    --t-900: 26.5px;   /* h1, big figs  */
    --t-1100: clamp(29px, 9.4px + 5.44vw, 44px);
  }

  .ft-display{ letter-spacing: -.01em; line-height: 1.06; }
  .ft-display--sm{ letter-spacing: -.008em; line-height: 1.1; }
  h1,.ft-h1{ letter-spacing: -.008em; line-height: 1.08; }
  h2,.ft-h2{ letter-spacing: -.006em; line-height: 1.14; }
  h3,.ft-h3{ letter-spacing: -.003em; }
  .ft-num,.ft-num--lg{ letter-spacing: -.014em; }

  .ft-display,.ft-display--sm{ overflow-wrap: break-word; }
}
