  /* ---------- ALBERT SANS ----------
     One face for the whole site, headings and body alike, requested as a
     single 400..800 variable file. Nothing else is loaded; --display, --body
     and --mono all point here, so a rule that names the wrong one still lands
     on Albert Sans.

     The hierarchy is carried by weight, size and tracking rather than by a
     second face:

       400  body copy
       500  secondary lines and the labels inside the calculator
       600  buttons, navigation, eyebrows, card and column titles
       700  section headings
       800  hero and the closing display line, plus financial figures

     Albert Sans is a geometric sans: rounder bowls, a narrower set and a
     shorter x-height than the Manrope it replaces, so the same string sets
     both shorter and lighter at the same font-size. Two things follow, and
     both are done here rather than left to chance - the display tracking
     below is eased off, because a geometric face tightened as hard as a wide
     grotesk closes its counters and the words go to one dark shape, and the
     type ladder is left where it is rather than pulled down a second time.

     Google serves the family as a 100..900 variable file. This page asks for
     400..800, which is the range the ladder above actually uses. */



  :root{
    /* One theme, one value. The page is true black - the same colour the
       footer runs at, which is bleap.finance's. There is no longer a step
       between the two: the document is a single unbroken ground from the
       header to the copyright line, and what separates the footer from the
       page above it is the hairline along its top edge, not a change in value.

       Everything layered on that ground is an rgba white overlay (--surface-1,
       --surface-2, --hairline) rather than a fixed colour, so the whole
       elevation system still reads at this depth without retuning.

       color-scheme tells the browser the same thing the palette does, which is
       what gets scrollbars, form controls and the tap highlight rendered dark
       instead of leaving light-mode widgets stranded on a dark page. */
    color-scheme:dark;
    --brand:#000000;
    --ink:#000000;
    --paper:#EEF1F5;
    --off:#EDEBFB;
    --gold:#EEF1F5;
    --gold-rgb:238,241,245;
    --line:rgba(255,255,255,0.14);
    --line-soft:rgba(0,0,0,0.14);
    --muted:rgba(255,255,255,0.65);
    --muted-dark:rgba(0,0,0,0.6);
    --header-bg:rgba(0,0,0,0.88);
    --eyebrow-bg:rgba(255,255,255,0.12);
    --eyebrow-border:rgba(255,255,255,0.28);
    --section-eyebrow-bg:rgba(0,0,0,0.06);
    --section-eyebrow-border:rgba(0,0,0,0.16);
    --tag-bg:rgba(255,255,255,0.08);
    --tag-border:rgba(255,255,255,0.2);
    --avatar-bg:rgba(255,255,255,0.14);
    --avatar-text:var(--gold);
    --pillars-line:rgba(0,0,0,0.14);
    --hover-tint:var(--off);
    --visual-shadow:rgba(0,0,0,0.35);
    --hero-shadow:rgba(0,0,0,0.55);
    /* True black, the value bleap.finance runs its own footer at - and now
       the value the page runs at too, so this token and --brand resolve to the
       same colour. It is kept as its own name rather than collapsed into
       --brand: the footer and the compliance band both read this one, and
       giving the page a different ground later should not mean hunting down
       every rule that meant "the footer's colour". */
    --footer-bg:#000000;
    --social-ink:rgba(255,255,255,0.78);
    /* wise.com runs a strict two-face system: Wise Sans Heavy for display type
       and Inter for absolutely everything else. The layout metrics below still
       come from Wise; the face is Albert Sans, described at the top of this sheet.

       All three tokens now resolve to it. --mono is kept as a name because ~70
       rules reference it; what it means is "the label face", and the eyebrows
       it styles are 600, sentence case, with the old 0.14em tracking removed. */
    --display: 'Albert Sans', sans-serif;
    --body: 'Albert Sans', sans-serif;
    --mono: 'Albert Sans', sans-serif;

    /* ---------- TYPE SCALE ----------
       One ladder, nothing outside it. Section body sits at 17px rather than
       the 18 it started at, and nav and footer links at 15 rather than 14.
       Both moves were made against a tall-x-height grotesk; Albert Sans reads
       a shade smaller at the same value, so nothing here goes back down - if
       anything the ladder is now a touch conservative.

       The steps are in rem (1rem = 16px at the browser default), so a reader
       who has raised their default text size gets the whole ladder scaled with
       it; px would pin it. Fine print sits at 13px rather than 12, and nothing
       a reader taps or must read to act - links, buttons, instructions - goes
       below 14px. */
    --t-mono:0.875rem;  /* 14px  eyebrows, labels */
    --t-fine:0.8125rem; /* 13px  legal, captions */
    --t-sm:0.9375rem;   /* 15px  nav, footer links, buttons */
    --t-base:1rem;      /* 16px  card body */
    --t-body:1.0625rem; /* 17px  section body */
    --t-lead:1.25rem;   /* 20px  hero lead */
    --t-h3:1.25rem;     /* 20px */
    --t-h2:clamp(1.875rem, 3.6vw, 3rem);
    /* The hero is no longer the same size as a section heading. It is the
       first thing on the page and it should be the largest thing on it after
       the closing line; 58px is the ceiling that keeps "Beyond borders." on
       one line inside its column. */
    --t-h1:clamp(2.375rem, 4.6vw, 3.625rem);

    /* ---------- DISPLAY METRICS ----------
       Albert Sans sets narrower than the Manrope this page used to run, so
       it wants less pulling in: -0.03em on the hero and -0.022em on section
       headings, which is where the letterforms stop reading as separate
       objects and start reading as a word without the round counters of a
       geometric face closing up on themselves. The
       leading is crushed to match - just over 1 for the hero, just under 1.05
       for sections - so a two-line heading holds together as a block.

       Weight climbs with size rather than staying flat: 700 carries section
       headings, 800 is kept for the hero and the closing line, so scale and
       weight say the same thing rather than competing. */
    --lh-display:1.02;
    --ls-display:-0.03em;
    --wt-display:800;
    --lh-h2:1.04;
    --ls-h2:-0.022em;
    --wt-h2:700;

    /* ---------- SPACING (8px base) ----------
       Every margin and pad below routes through these, so vertical rhythm is
       consistent instead of a drift of 26/34/44/56/64px one-offs. */
    --sp-1:4px;  --sp-2:8px;   --sp-3:12px; --sp-4:16px;
    --sp-5:24px; --sp-6:32px;  --sp-7:40px; --sp-8:56px;
    --sp-9:72px; --sp-10:96px; --sp-11:128px;

    --radius-sm:12px; --radius-md:18px; --radius-lg:24px; --radius-xl:32px;

    /* Shared height for the band visuals. It lives up here, in the first
       :root, rather than down beside the badge tokens where it started -
       custom properties are resolved by cascade order like anything else, and
       from there it was re-declaring itself AFTER the max-width:860px block
       that lowers it to 340. Same specificity, later wins, so the phone value
       never applied and every band reserved 480px of height on a 375px screen.
       Declared before the media query, it is overridable again. */
    --band-visual-h:480px;

    /* One easing curve for the whole page. Mixed curves read as inconsistent
       motion even when no single transition looks wrong. */
    --ease:cubic-bezier(.22,.61,.36,1);
    --ease-soft:cubic-bezier(.16,1,.3,1);

    /* Layered elevation. A flat rgba fill has no light source; the inset
       hairline gives each surface a lit top edge, which is most of what makes
       dark UI read as crafted. */
    --surface-1:rgba(255,255,255,0.045);
    --surface-2:rgba(255,255,255,0.07);
    --hairline:rgba(255,255,255,0.09);
    --shadow-md:0 18px 40px -24px rgba(0,0,0,0.7);
    --shadow-lg:0 40px 80px -40px rgba(0,0,0,0.85);
    /* No wash. The page is the flat --brand grey from top to bottom.
       This used to carry five very wide radial tints (green over the hero,
       blue and violet through the middle bands, amber into the closing block)
       stacked down the length of the document. They are gone deliberately, not
       lost: put a gradient stack back on this one token and the whole page
       picks it up again, because body::before is the only thing that reads it. */
    --ground:none;
  }



  body{transition:background 0.25s ease, color 0.25s ease;}

  *{margin:0;padding:0;box-sizing:border-box;}
  html{scroll-behavior:smooth;}
  section[id]{ scroll-margin-top:var(--sp-10); }
  body{
    /* Containing block for the ::before wash below. */
    position:relative;
    background:var(--brand);
    color:var(--paper);
    font-family:var(--body);
    font-weight:400;
    /* 1.55 rather than 1.5: the paragraphs on this page want air rather
       than density, and Albert Sans' open counters hold at the looser
       setting where a denser face would start to look sparse. */
    line-height:1.55;
    letter-spacing:-0.005em;
    overflow-x:hidden;
    /* Without this, Albert Sans renders noticeably heavier on macOS than it does
       on the sites this page is being measured against. */
    -webkit-font-smoothing:antialiased;
    -moz-osx-font-smoothing:grayscale;
    font-feature-settings:"kern" 1,"liga" 1,"calt" 1;
  }
  /* Figures should never wobble in width when they change. */
  .tabular{font-variant-numeric:tabular-nums;}

  /* The ground layer behind the page. It paints --ground, which is now `none`
     in both themes, so this currently renders nothing and the flat --brand
     colour shows through.

     It is kept rather than deleted because it is the whole mechanism: it stays
     absolute rather than fixed so that anything put back into --ground is as
     tall as the document and stays with the section it was placed over, where
     fixed would park it in the viewport and slide the page past it. */
  body::before{
    content:""; position:absolute; inset:0; pointer-events:none; z-index:0;
    background:var(--ground);
  }
  header,main,footer{position:relative; z-index:1;}
  a{color:inherit;text-decoration:none;}
  img{max-width:100%;display:block;}
  .wrap{max-width:1180px;margin:0 auto;padding:0 var(--sp-6);}
  ::selection{background:var(--gold);color:var(--brand);}

  @media (prefers-reduced-motion: reduce){
    *{animation-duration:0.001ms !important; animation-iteration-count:1 !important; transition-duration:0.001ms !important;}
  }

  /* ---------- NAV ---------- */
  /* At the top the header should be invisible against the hero; it only earns
     its border and blur once content is passing underneath it. */
  header{
    position:sticky; top:0; z-index:50;
    background:transparent;
    border-bottom:1px solid transparent;
    transition:background .3s var(--ease), border-color .3s var(--ease), backdrop-filter .3s var(--ease);
  }
  header.is-scrolled{
    background:var(--header-bg);
    backdrop-filter:blur(14px) saturate(140%);
    border-bottom-color:var(--line);
  }
  /* The mobile panel needs an opaque header behind it whether scrolled or not. */
  header.nav-open{ background:var(--brand); border-bottom-color:var(--line); }
  nav{
    display:flex; align-items:center; justify-content:space-between;
    padding:var(--sp-4) 0;
    transition:padding .3s var(--ease);
  }
  .logo-img{height:34px; width:auto;}
  .foot-brand .logo-img{height:34px;}
  @media (max-width:860px){
    .logo-img{height:30px;}
  }
  @media (max-width:560px){
    .logo-img{height:28px;}
    .foot-brand .logo-img{height:26px;}
  }
  /* The links sit in a dark pill centred on the row, and Product opens by
     growing that same pill downward rather than dropping a separate panel -
     bleap.finance's header, measured off their site: #1a1a1a fill, the
     menu scaling up from 0.4 at its top-left corner while the pill's height
     runs out to fit it, 32px icon tiles at 5% white that go to 10% on hover
     as the row slides 8px right.

     The positioner is a fixed 48px box centred on the nav row, so the pill
     can grow out of it downward without changing the row's height and
     shifting the logo and the call to action. Width and height are set from
     the script: the pill has to be as wide as the wider of its tabs and its
     menu, and a transition cannot run to or from `auto`. */
  nav{ position:relative; }
  .nav-links{
    position:absolute; left:50%; top:50%; height:48px; margin-top:-24px;
    transform:translateX(-50%); z-index:2;
  }
  .nav-pill{
    position:relative; height:48px; border-radius:24px; overflow:hidden;
    background:#1a1a1a;
    transition:height .5s var(--ease-soft), width .5s var(--ease-soft);
  }
  /* Centred, so the tabs stay put while the pill widens around them to fit
     the menu. */
  .nav-tabs{ display:flex; width:max-content; margin:0 auto; align-items:center; padding:4px; white-space:nowrap; }
  .nav-tab{
    height:40px; display:flex; align-items:center; padding:0 16px;
    background:none; border:0; cursor:pointer;
    font-family:var(--body); font-size:var(--t-sm); font-weight:600; letter-spacing:-0.005em;
    color:var(--muted); transition:color .2s var(--ease);
  }
  .nav-tab:hover, .nav-tab[aria-expanded="true"]{ color:#fff; }
  .nav-tab:focus-visible{ outline:2px solid var(--gold); outline-offset:-4px; border-radius:20px; }
  .nav-drop-clip{ position:absolute; top:56px; left:0; right:0; bottom:0; overflow:hidden; }
  .nav-drop{
    position:absolute; top:0; left:0; width:360px;
    display:flex; flex-direction:column; gap:2px; padding:0 8px 8px;
    opacity:0; transform:scale(.4); transform-origin:left top;
    transition:opacity .3s var(--ease), transform .5s var(--ease-soft);
  }
  /* One pill, several menus (Product, Company, Support): only the open tab's
     list shows, the others stay collapsed and inert inside the same clip. */
  .nav-drop:not(.is-active){ pointer-events:none; }
  .nav-pill.is-open .nav-drop.is-active{ opacity:1; transform:none; }
  .nav-tab .nav-tab-chev{ width:12px; height:12px; margin-left:6px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; transition:transform .3s var(--ease); }
  .nav-tab[aria-expanded="true"] .nav-tab-chev{ transform:rotate(180deg); }
  /* The rows inside are spenda.africa's product list - the product's name
     and one line on what it does - led by bleap's 32px icon tile. */
  .nav-drop-item{
    display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-3);
    border-radius:14px; color:#fff; transition:background .15s var(--ease);
  }
  .nav-drop-item:hover, .nav-drop-item:focus-visible{ background:rgba(255,255,255,0.06); outline:none; }
  .nav-drop-ic{
    width:32px; height:32px; flex-shrink:0; border-radius:8px;
    display:flex; align-items:center; justify-content:center;
    background:rgba(255,255,255,0.05); transition:background .15s var(--ease);
  }
  .nav-drop-item:hover .nav-drop-ic, .nav-drop-item:focus-visible .nav-drop-ic{ background:rgba(255,255,255,0.1); }
  .nav-drop-ic svg{ width:18px; height:18px; fill:none; stroke:#fff; stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round; }
  .nav-drop-text{ display:flex; flex-direction:column; gap:2px; min-width:0; }
  .nav-drop-title{ font-size:var(--t-sm); font-weight:600; line-height:1.3; }
  .nav-drop-desc{ font-size:var(--t-mono); line-height:1.35; color:var(--muted); }
  .nav-cta{display:flex; align-items:center; gap:var(--sp-4);}

  /* Buttons run one notch tighter than body copy. A pill is a small closed
     shape and the label has to read as a single object inside it. */
  .btn{
    font-family:var(--body); font-weight:600; font-size:var(--t-sm);
    padding:var(--sp-3) var(--sp-5); border-radius:100px; cursor:pointer; border:none;
    display:inline-flex; align-items:center; gap:var(--sp-2);
    letter-spacing:-0.015em;
  }
  .btn-primary{background:var(--paper); color:var(--brand);}
  .btn-primary:hover{background:var(--hover-tint);}
  .btn-ghost{color:var(--paper); font-weight:600;}
  .btn:focus-visible,.store-badge:focus-visible{
    outline:2px solid var(--gold); outline-offset:3px; border-radius:100px;
  }

  .menu-toggle{
    display:none; position:relative; width:34px; height:34px;
    background:none; border:0; padding:0; cursor:pointer;
  }
  .menu-toggle .menu-bar{
    position:absolute; left:7px; width:20px; height:1.5px; background:var(--paper);
    transition:transform .3s cubic-bezier(.22,.61,.36,1);
  }
  .menu-toggle .menu-bar:nth-child(1){ top:14px; }
  .menu-toggle .menu-bar:nth-child(2){ top:20px; }
  .menu-toggle[aria-expanded="true"] .menu-bar:nth-child(1){ transform:translateY(3px) rotate(45deg); }
  .menu-toggle[aria-expanded="true"] .menu-bar:nth-child(2){ transform:translateY(-3px) rotate(-45deg); }
  .menu-toggle:focus-visible{ outline:2px solid var(--gold); outline-offset:2px; border-radius:6px; }

  /* Panel drops out of the sticky header, which is its containing block. */
  .mobile-nav{
    position:absolute; left:0; right:0; top:100%;
    background:var(--brand); border-bottom:1px solid var(--line);
    display:flex; flex-direction:column; padding-bottom:8px;
    opacity:0; visibility:hidden; transform:translateY(-10px);
    transition:opacity .25s ease, transform .25s cubic-bezier(.22,.61,.36,1), visibility .25s;
  }
  header.nav-open .mobile-nav{ opacity:1; visibility:visible; transform:none; }
  .mobile-nav a{
    padding:var(--sp-4) 20px; font-size:16px; font-weight:600; color:var(--paper);
    border-top:1px solid var(--line);
  }
  .mobile-nav a:first-child{ border-top:0; }
  .mobile-nav a:active{ background:var(--eyebrow-bg); }
  .mobile-nav .mobile-nav-legal{ font-size:14px; color:var(--muted); }
  /* Product in the phone menu is the same list as the desktop pill's, opened
     in place under its row. Rows collapse on a 0fr/1fr grid track so the
     list animates to its own height without a measured max-height. */
  .mobile-nav-group{
    display:flex; align-items:center; justify-content:space-between; width:100%;
    padding:var(--sp-4) 20px; background:none; border:0; cursor:pointer; text-align:left;
    font-family:var(--body); font-size:16px; font-weight:600; color:var(--paper);
  }
  .mobile-nav-group svg{ width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; transition:transform .3s var(--ease); }
  .mobile-nav-group[aria-expanded="true"] svg{ transform:rotate(180deg); }
  .mobile-nav-sub{ display:grid; grid-template-rows:0fr; transition:grid-template-rows .35s var(--ease-soft); }
  .mobile-nav-group[aria-expanded="true"] + .mobile-nav-sub{ grid-template-rows:1fr; }
  .mobile-nav-sub > div{ overflow:hidden; display:flex; flex-direction:column; }
  .mobile-nav-group[aria-expanded="true"] + .mobile-nav-sub > div{ padding-bottom:12px; }
  .mobile-nav .mobile-nav-sub a{
    display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-3) 20px; border-top:0;
  }
  /* The panel's own call to action, under the links rather than among them.
     It is the one thing in this menu that is not navigation, so it stops
     being a list row: no rule above it, centred, and inset from the edges
     the links run to. */
  .mobile-nav .btn{
    margin:var(--sp-4) 20px var(--sp-2); padding:var(--sp-3) var(--sp-5); border-top:0;
    justify-content:center; font-size:15px; color:var(--brand);
  }
  .mobile-nav .btn:active{ background:var(--hover-tint); }
  @media (min-width:861px){ .mobile-nav{ display:none; } }
  @media (prefers-reduced-motion: reduce){
    .mobile-nav{ transition:opacity .25s ease, visibility .25s; transform:none; }
    .menu-toggle .menu-bar{ transition:none; }
  }

  @media (max-width:860px){
    .nav-links{display:none;}
    .menu-toggle{display:block;}
  }

  /* Below ~560px the logo, the pill and the toggle stop fitting on one line:
     tightened as far as it goes, the pill still ends up flush against the
     wordmark with no gap at all. So the pill leaves the row here and the one
     at the bottom of the menu takes over. Same button, one tap further in,
     and the header gets its logo back. */
  @media (max-width:560px){
    nav{padding:var(--sp-4) 0;}
    .nav-cta{gap:12px;}
    .nav-cta .btn{display:none;}
  }

  /* ---------- HERO ---------- */
  .hero{
    padding:var(--sp-10) 0 var(--sp-9);
    position:relative;
  }
  .hero-grid{
    display:grid; grid-template-columns:1.05fr 0.95fr; gap:var(--sp-8); align-items:center;
  }
  .eyebrow{
    display:inline-flex; align-items:center; gap:var(--sp-2);
    font-family:var(--body); font-size:var(--t-mono); font-weight:600;
    letter-spacing:-0.008em;
    color:var(--muted); background:none; border:0;
    padding:0; margin-bottom:var(--sp-4);
  }
  h1{
    font-family:var(--display); font-weight:var(--wt-display);
    font-size:var(--t-h1);
    line-height:var(--lh-display); letter-spacing:var(--ls-display);
    margin-bottom:var(--sp-5);
  }

  /* ---------- HERO WORD ROTATOR ----------
     bleap.finance's hero device: the first word is fixed and the one after it
     is exchanged on a timer, so one line carries two claims. Taken at the
     mechanism rather than at the effect, because the effect falls apart
     without it:

       - the words are stacked absolutely on top of one another, so a swap has
         no reflow to fight and nothing below the hero ever moves;
       - the box's width is animated to the incoming word rather than snapped,
         which is what keeps the full stop travelling with the word instead of
         jumping ahead of it;
       - each word is split into letters that arrive on a stagger. They fall in
         from above and leave downward, so the exchange reads as one motion
         carrying on through the line rather than as two opposing ones.

     Only transform and opacity are animated, so the whole thing composites and
     never lays out. Width is the one exception and it is on a box no other
     element is sized from.

     The no-JS shape is the first word sitting in normal flow, which is why the
     layers are only lifted out of it under .is-live - a class the script adds.
     Without it the hero still reads "Beyond money." */
  .hero-title{ display:flex; flex-wrap:wrap; align-items:baseline; column-gap:0.24em; }
  .hero-rot{ position:relative; display:inline-block; white-space:nowrap; }
  .hero-rot.is-live{ transition:width .52s var(--ease-soft); }
  /* Holds the current word at visibility:hidden purely to give the box its
     height. Width comes from the script, because an inline-block's implicit
     width is not a transitionable value. */
  .hero-rot__size{ visibility:hidden; white-space:pre; }
  .hero-rot.is-live .hero-rot__word{ position:absolute; left:0; top:0; white-space:nowrap; }
  .hero-rot__l{
    display:inline-block; will-change:transform, opacity;
    transition:transform .52s var(--ease-soft), opacity .3s linear;
  }
  .hero-rot__word.is-in .hero-rot__l{ opacity:0; transform:translateY(-0.62em); }
  .hero-rot__word.is-out .hero-rot__l{ opacity:0; transform:translateY(0.62em); }
  /* The letters are split for the stagger and are hidden from assistive tech
     because a per-character run is read out character by character. The word
     reaches the accessibility tree once, whole, through this instead. */
  .sr-only{
    position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
  }
  @media (prefers-reduced-motion: reduce){
    .hero-rot.is-live, .hero-rot__l{ transition:none; }
  }
  /* 540px rather than 440: the lead runs to two sentences now, and anything
     under 540 leaves it five lines deep under the heading. 540 is the width
     where it breaks to four, and there is still ~80px of air before the hero
     visual beside it. */
  .hero p.lead{
    font-size:var(--t-lead); font-weight:500; line-height:1.5; letter-spacing:-0.012em;
    color:var(--muted); max-width:540px; margin-bottom:var(--sp-7);
  }
  .hero-actions{display:flex; gap:var(--sp-3); flex-wrap:wrap; align-items:center;}

  .hero-visual{
    position:relative;
    display:flex; flex-direction:column; align-items:center; justify-content:center;
  }
  .hero-visual img{width:100%; max-width:400px; height:auto; display:block; margin:0 auto;}

  /* ---------- SECTION HEADERS ---------- */
  /* 128px between sections rather than 96px. The reference sites all breathe
     harder than this page did; cramped rhythm is what made it feel busy. */
  section{padding:var(--sp-9) 0;}
  h2{
    font-family:var(--display); font-weight:var(--wt-h2);
    font-size:var(--t-h2); letter-spacing:var(--ls-h2); line-height:var(--lh-h2);
    margin-bottom:var(--sp-4);
  }
  .band-copy{color:var(--muted); font-size:var(--t-body); line-height:1.6; max-width:46ch; margin-bottom:var(--sp-6);}
  /* The closing line under a band's body copy. It is a claim rather than more
     explanation, so it steps back up to full-strength ink where the paragraph
     above it is --muted, and takes weight instead of size - the same trick the
     trust list uses to sit brighter than the copy it follows without becoming
     a second heading. */
  .band-kicker{
    color:var(--paper); font-size:var(--t-base); font-weight:600;
    line-height:1.5; letter-spacing:-0.005em;
    max-width:46ch; margin-top:var(--sp-4);
  }

  /* Light section variant */
  .section-light{
    background:var(--paper); color:var(--ink); border-radius:32px;
  }
  .section-light .eyebrow{
    color:var(--muted-dark); background:none; border:0;
  }


  /* ---------- SECTION BOXES ----------
     The middle of the page is bleap.finance's product grid: one wide panel,
     then two half panels beneath it, all on a true-black document. The hero
     stays on the bare ground because the first block should read as the page
     itself; the FAQ's rule-and-divider list has its own structure and does not
     want a second frame; and the live rates section is a calculator whose two
     fields are already cards, so a panel behind them was a card on a card.

     The fill is bleap's own: a short vertical gradient from #232323 down to
     #131313, no border, no shadow. It is a gradient rather than a flat tint
     because a single dark grey on black has no light source and reads as a
     hole; falling ten values over the height of the panel gives it a lit top
     edge and a shaded bottom one, which is the whole effect.

     Tokens, not literals, because three panels read them and the nested
     surfaces have to move together if the fill is ever retuned. */
  :root{
    --box-fill:linear-gradient(180deg, #232323 0%, #131313 100%);
    --box-radius:24px;
    /* bleap's own figure, and the same on every panel whatever its size: 24px
       inside a card, 32px from 768 up. The wide panel used to run to 56 at the
       top of the range on the reasoning that 1180px holding a two-column band
       wants more room than a half card. True in isolation, but it pushed that
       panel's heading 17px right of the one below it, and a stack of panels
       reads as a system mainly because every heading starts on the same
       vertical line. One value for all three buys the rail; bleap runs it flat
       across their whole grid for what is presumably the same reason. */
    --box-pad:clamp(24px, 2.6vw, 32px);
    /* The gap between the wide panel and the row, and between the two panels
       in it. bleap's own figure at this breakpoint. */
    --box-gap:24px;
    /* How far the fill takes to fall from #232323 to #131313. A fixed length,
       not the height of the box - see .section-box below. */
    --box-grad:640px;
  }

  .section-box{
    /* The same colour on every panel, whatever height it happens to be.

       A linear-gradient is normalised to the element it paints, so #232323
       lands on the top edge and #131313 on the bottom edge of EACH box
       independently. Three panels of three different heights therefore run the
       same two endpoints over three different distances and read as three
       slightly different greys side by side - and the wide panel's #131313
       bottom edge meets the row's #232323 top edge as a visible step.

       Pinning the ramp to a fixed 640px measured from the top of every panel,
       over a #131313 base colour that carries anything past it, makes the fill
       identical at identical distance from the top edge on all three. Set
       --box-grad to a value taller than any panel to get the per-element
       behaviour back. */
    background-color:#131313;
    background-image:var(--box-fill);
    background-repeat:no-repeat;
    background-size:100% var(--box-grad);
    border-radius:var(--box-radius);
    padding:var(--box-pad);
    /* bleap lifts a card 4px under the cursor. The transition lives on the
       box rather than the hover state so the card settles back down when the
       pointer leaves instead of snapping. */
    transition:transform .4s var(--ease-soft);
  }
  /* .wrap sets its own padding, and the max-width:860px block at the foot of
     this sheet re-sets it at equal specificity and later in source order, so
     the wide panel needs the two-class selector to hold its padding on a
     phone. */
  .wrap.section-box{ padding:var(--box-pad); }

  /* The gutter moves off .wrap (which is now the panel itself) and onto the
     section, so the panel keeps a margin from the window edge instead of
     bleeding into it. Same 32px the wrap uses. Panels are their own
     separation, so the 72px of section padding that used to do that job would
     read as dead ground under a card; the wide panel keeps its full distance
     from the hero above and hands the row below it --box-gap. */
  #cards{
    padding:var(--sp-8) var(--sp-6) calc(var(--box-gap) / 2);
  }

  /* ---------- THE ROW ----------
     Two panels side by side under the wide one. #crypto and #trust stay real
     sections inside it - they are nav targets and document landmarks - so the
     row grid places the sections and each section hands its full height down
     to the panel inside it, which is what keeps the two panels the same
     height when one carries a list and the other does not. */
  .box-row{
    display:grid; grid-template-columns:1fr 1fr; gap:var(--box-gap);
    /* The gutter is a width reduction, not padding. .wrap is border-box, so
       the wide panel above measures 1180px INCLUDING its 32px gutter; giving
       this row the same max-width plus 32px of padding would inset it a
       further 28px on each side and the two left edges would not line up.
       Taking the gutter out of the width instead lands the row on exactly the
       same 1180px column as the panel above it. */
    width:calc(100% - 2 * var(--sp-6));
    max-width:1180px; margin:0 auto;
    padding:calc(var(--box-gap) / 2) 0 var(--sp-8);
  }
  .box-row > section{ padding:0; display:flex; }
  .box-row .section-box{ width:100%; }
  .box-row .section-box:hover{ transform:translateY(-4px); }

  /* Half the width, so the two-column bands inside collapse to one column.
     These are viewport media queries elsewhere in the sheet, which never fire
     for a 578px column on a 1440px screen - the stack has to be stated here.

     auto/1fr rather than two auto rows: the copy takes what it needs and the
     art gets the remainder, so the shorter of the two panels grows its picture
     to match the taller instead of leaving a band of empty fill at the bottom.
     Order puts the picture last in both, which is bleap's own card order:
     title, then description, then art. */
  .box-row .section-box{
    grid-template-columns:1fr; grid-template-rows:auto 1fr;
    gap:var(--box-gap);
  }
  .box-row .coins-band .visual-frame, .box-row .trust-shield{ order:2; align-self:center; }
  .box-row .coins-band .visual-frame{ min-height:0; }

  /* The section heading ladder is set for a full-width block. At 48px it runs
     to four lines in a 514px column, so the half panels take bleap's own 32px
     card title instead. */
  .box-row h2{ font-size:clamp(26px, 2.2vw, 32px); }
  .box-row .band-copy, .box-row .trust-copy p{ margin-bottom:0; }

  /* The art in a half panel would otherwise run the full width of the column
     and tower over the copy above it. The #crypto rule needs the id to outrank
     the min(100%, 480px) cap set for that image in the wide layout. */
  .box-row .visual-frame.frameless img,
  .box-row #crypto .visual-frame.frameless img{
    max-height:260px; width:auto; max-width:100%; margin:0 auto;
  }
  .box-row .trust-shield img{ max-width:170px; }
  @media (max-width:860px){
    /* One column. The row is now just a stack, and it takes the phone gutter
       and the tighter gap bleap uses below 768. */
    .box-row{
      grid-template-columns:1fr; gap:16px;
      width:calc(100% - 40px);
    }
    #cards{ padding-left:20px; padding-right:20px; }
  }
  @media (prefers-reduced-motion:reduce){
    .box-row .section-box:hover{ transform:none; }
  }

  /* ---------- SECURITY SPLIT ---------- */
  .split{
    display:grid; grid-template-columns:1fr 1fr; gap:var(--sp-8); align-items:center;
  }

  .visual-frame{
    border-radius:24px; overflow:hidden; border:1px solid var(--line-soft);
    box-shadow:0 30px 60px -25px var(--visual-shadow);
  }
  .visual-frame img{width:100%; display:block;}
  .visual-frame.frameless{border-radius:0; overflow:visible; border:none; box-shadow:none;}
  .visual-frame.frameless img{width:100%; height:auto; display:block;}

  @media (max-width:860px){
    .split{grid-template-columns:1fr;}
    /* Scoped to .split. Unscoped, this reached every .visual-frame on the
       page, including the one in the Global payments band, and pulled the art
       above the copy on a phone - the opposite of the order that band is now
       built in. */
    .split .visual-frame{order:-1;}
  }

  /* ---------- COINS FEATURE BAND ---------- */
  .coins-band{
    display:grid; grid-template-columns:1fr 1fr; gap:56px; align-items:center;
  }
  .coins-band .visual-frame{border-radius:24px;}

  /* Every band visual gets the same vertical room, whatever shape the art is.
     Left to themselves these ran 266px, 659px and 401px tall, so the three
     sections read as three different layouts rather than one series. The image
     centres in that room and is capped by height as well as width, so nothing
     is cropped and a portrait image no longer towers over a landscape one. */
  .coins-band .visual-frame{
    display:flex; align-items:center; justify-content:center;
    min-height:var(--band-visual-h);
  }
  .coins-band .visual-frame.frameless img{
    width:auto; height:auto;
    max-width:100%; max-height:var(--band-visual-h);
    margin:0 auto;
  }

  /* ---------- CLOSING CTA ----------
     The glow is a very large circle, wider than the viewport, positioned so
     only its lower arc crosses the section. That is what makes it read as a
     light source rather than as a shape: at this radius the curve across the
     block is almost flat, so no edge is visible. It is clipped by overflow on
     the section, not by a smaller radius - shrinking it would bring the
     curvature back and it would read as a circle sitting behind the type.

     Monochrome, deliberately. The reference runs a blue-to-navy glow here, but
     this sheet is one value ladder from --paper to true black with no hue in
     it, so a coloured glow would be the only colour on the page. Everything
     except the three stops is structural: put hues on --cta-orb-a/b/c and the
     section takes them with nothing else changed. */
  :root{
    --cta-orb-a:rgba(238,241,245,0.30);
    --cta-orb-b:rgba(255,255,255,0.07);
    --cta-orb-c:rgba(255,255,255,0);
    --cta-orb-size:1600px;
  }
  .cta{
    position:relative; overflow:hidden; isolation:isolate;
    /* No padding at the foot. The art is meant to stand ON the hairline the
       footer draws along its top edge rather than float above it, so the
       section has to end exactly where the picture does - any bottom padding
       here becomes a gap between the phone and the line it should be resting
       on. */
    padding:var(--sp-10) var(--sp-6) 0;
  }
  .cta-orb{
    position:absolute; z-index:-1;
    width:var(--cta-orb-size); height:var(--cta-orb-size);
    left:50%; top:0; transform:translate(-50%, -72%);
    border-radius:50%;
    background:linear-gradient(180deg, var(--cta-orb-a) 0%, var(--cta-orb-b) 51%, var(--cta-orb-c) 100%);
    pointer-events:none;
  }
  .cta-inner{
    display:flex; flex-direction:column; align-items:center; text-align:center;
    max-width:1180px; margin:0 auto;
  }
  /* 32px on a narrow measure, so it breaks to three lines the way a spoken
     sentence does. Bold rather than the regular weight the reference sets its
     closing line in: this is the last thing on the page and the only prompt
     left, so it takes the same 700 the section headings above it carry. */
  .cta-title{
    font-size:clamp(26px, 2.6vw, 32px); font-weight:var(--wt-h2);
    line-height:1.25; letter-spacing:-0.012em;
    max-width:18ch; margin-bottom:var(--sp-6);
  }
  /* The store badges, not a pill. This is the foot of the page, where the
     next step is the download itself rather than a scroll back up to find it -
     and the badges are the mark people look for. .store-badge is the hero's
     own class, so the height and the Play badge's transparent-margin
     correction come for free and the two pairs stay identical. */
  .cta-actions{
    display:flex; align-items:center; justify-content:center;
    gap:var(--sp-4); flex-wrap:wrap;
  }
  .cta-art{ width:100%; max-width:340px; margin-top:var(--sp-9); margin-bottom:0; font-size:0; }
  .cta-art img{ width:100%; height:auto; display:block; }

  @media (max-width:860px){
    .cta{ padding:var(--sp-9) 20px 0; }
    :root{ --cta-orb-size:900px; }
    .cta-art{ margin-top:var(--sp-7); }
  }

  /* ---------- GLOBAL PAYMENTS BAND ----------
     The 480px floor above was set when this panel held a portrait render and
     three bands had to agree on one height. Neither is true now: #crypto is a
     half panel in the row below and already zeroes the floor, so the rule
     serves this band alone - and the art here is landscape, 1100x673, which
     needs 324px at this column width. The floor was holding the panel 156px
     taller than its own contents, all of it empty fill under the globe.

     Zeroed, so the band is as tall as the taller of its two columns and
     nothing else. */
  #cards .visual-frame{ min-height:0; }

  /* A landscape image in an even split reads small: 530px of art inside an
     1180px panel left the globe looking like a thumbnail beside its own
     heading. The art takes the larger share instead.

     1.2, not more, because the copy column is the binding constraint at the
     other end - .band-copy is capped at 46ch, which sets about 480px at 17px,
     and 485 is that measure with nothing to spare. Widening the art past this
     starts breaking the paragraph into a narrower column than it was written
     for.

     Scoped to min-width, not left open: #cards .section-box is an id plus a
     class, which outranks the .coins-band single-column rule in the
     max-width:860px block further down the sheet. Unscoped, this would keep
     two columns on a phone and wedge a 250px globe beside 250px of type. */
  @media (min-width:861px){
    #cards .section-box{
      grid-template-columns:1fr 1.2fr;
      gap:48px;
      /* Copy anchored to the top edge, the way a bleap card reads: title and
         description first, art under them. .coins-band centres both columns,
         which floated the wording in the middle of the panel because the art
         is the taller of the two. start puts both on the top edge and lets the
         art run down from there. */
      align-items:start;
    }
    /* The globe was drawing at the full width of its column, which made it
       exactly as tall as the panel is deep - it defines the panel height, so
       it met the top and bottom padding with nothing to spare and read as
       crowded. Capped, it sits back from its column and the panel closes to
       match. The id is needed to outrank the .coins-band max-width:100%. */
    #cards .visual-frame.frameless img{ max-width:440px; }
    /* A little more room top and bottom. Vertical only - the horizontal pad
       stays tied to --box-pad so this panel's heading keeps landing on the
       same left rail as the two below it. */
    #cards .section-box{ padding:48px var(--box-pad); }
  }
  @media (max-width:860px){
    .coins-band{grid-template-columns:1fr;}
    /* The art no longer jumps above the copy when the band stacks. Both bands
       now lead with the heading in source order - the wide one because its
       heading belongs on the same left rail as every other heading on the
       page, the half one because that is the card order it was built in - and
       a phone should read them in that same order rather than opening on a
       picture. Source order is the order now; there is no rule here. */
    /* One column, so the visual has the full width and needs less height. */
    :root{ --band-visual-h:340px; }
  }

  /* ---------- TESTIMONIALS ---------- */
  .avatar{
    width:34px; height:34px; border-radius:50%; background:var(--avatar-bg);
    display:flex; align-items:center; justify-content:center;
    font-family:var(--body); font-size:13px; font-weight:600; color:var(--avatar-text);
  }

  /* ---------- LANGUAGE ----------
     A flag-and-code pill in the header, with a listbox under it. It used to be
     a styled face over a real <select>, down in the footer, which bought
     keyboard handling and the platform's picker sheet for no script at all.
     Two things ended that trade. A menu row here carries a round flag beside
     the language name, and a native <option> cannot draw one - the platform
     renders it as plain text, so the flags would have appeared on the closed
     pill and nowhere else. And a control in the header has to open downward
     over the page, which a native picker on desktop does not do on our terms.
     What replaces it is a listbox with the roles and the arrow keys written
     out; the script is at the foot of the page beside the translator.

     The state still lives on <html lang>, so the flag on the pill is a pure
     CSS swap and there is one source of truth that screen readers and the
     browser's own translation prompt already read.

     Every language names itself - English, Français, Español - which is the
     convention every language menu follows. The rows sit inside .lang-select,
     which the translator skips, so they cannot be swapped by the thing they
     control. */
  .lang-select{ position:relative; display:inline-flex; }
  .fl-sprite{ position:absolute; width:0; height:0; overflow:hidden; }

  /* Padded to 5px on the flag side and 14px on the text side: the flag is a
     circle sitting inside a pill of nearly its own height, so an even inset
     would leave it looking wedged against the left edge while the code
     floated in open space. */
  .lang-btn{
    display:inline-flex; align-items:center; gap:9px;
    height:38px; padding:0 14px 0 5px; border-radius:999px;
    background:rgba(255,255,255,0.07); border:1px solid rgba(255,255,255,0.10);
    color:var(--paper); cursor:pointer;
    -webkit-backdrop-filter:blur(12px); backdrop-filter:blur(12px);
    transition:background .2s var(--ease), border-color .2s var(--ease);
  }
  .lang-btn:hover{ background:var(--eyebrow-bg); border-color:var(--eyebrow-border); }
  .lang-btn:focus-visible{ outline:2px solid var(--gold); outline-offset:3px; }
  /* Two letters standing alone need the tracking back. At the sheet's usual
     negative letter-spacing a pair of capitals reads as one collided mark. */
  .lang-code{
    font-family:var(--body); font-size:13px; font-weight:600;
    letter-spacing:0.07em; line-height:1;
  }

  /* Same round-flag treatment as the currency marks in the rate calculator
     and the Lagos mark in the footer, so the page reads as one family. The
     inset hairline is what keeps a white-edged flag - France, Spain - from
     bleeding into whatever sits behind it. */
  .lang-flag{
    width:28px; height:28px; flex:none; display:block; position:relative;
    border-radius:50%; overflow:hidden;
  }
  .lang-flag svg{ width:100%; height:100%; display:block; }
  .lang-flag::after{
    content:""; position:absolute; inset:0; border-radius:50%;
    box-shadow:inset 0 0 0 1px rgba(255,255,255,0.22);
  }
  .flag-fr,.flag-es{ display:none; }
  [lang="fr"] .flag-gb,[lang="es"] .flag-gb{ display:none; }
  [lang="fr"] .flag-fr{ display:block; }
  [lang="es"] .flag-es{ display:block; }

  /* Right-aligned and scaled from its top-right corner, because the pill sits
     at the right end of the header: a panel growing from the left would open
     away from the thing that spawned it. */
  .lang-menu{
    position:absolute; top:calc(100% + 10px); right:0; z-index:60;
    min-width:186px; margin:0; padding:var(--sp-2); list-style:none;
    background:rgba(14,14,14,0.92);
    -webkit-backdrop-filter:blur(24px) saturate(140%);
    backdrop-filter:blur(24px) saturate(140%);
    border:1px solid var(--line); border-radius:18px;
    box-shadow:0 18px 46px rgba(0,0,0,0.55);
    opacity:0; visibility:hidden; transform:translateY(-8px) scale(0.97);
    transform-origin:top right;
    transition:opacity .18s var(--ease), transform .18s var(--ease), visibility .18s;
  }
  .lang-select.is-open .lang-menu{ opacity:1; visibility:visible; transform:none; }
  .lang-opt{
    display:flex; align-items:center; gap:var(--sp-3);
    padding:var(--sp-2) var(--sp-4) var(--sp-2) var(--sp-2); border-radius:12px;
    font-family:var(--body); font-size:14px; font-weight:500;
    color:var(--muted); cursor:pointer; white-space:nowrap;
    transition:background .15s var(--ease), color .15s var(--ease);
  }
  .lang-opt .lang-flag{ width:24px; height:24px; }
  .lang-opt:hover{ background:rgba(255,255,255,0.07); color:var(--paper); }
  .lang-opt:focus-visible{ outline:2px solid var(--gold); outline-offset:-2px; }
  .lang-opt[aria-selected="true"]{ background:rgba(255,255,255,0.11); color:var(--paper); font-weight:600; }
  @media (prefers-reduced-motion: reduce){
    .lang-menu{ transition:opacity .18s ease, visibility .18s; transform:none; }
  }
  /* The code drops on a narrow header and the pill closes to a ring around
     the flag, which is the one part that carries the meaning. */
  @media (max-width:420px){
    .lang-btn{ height:34px; padding:3px; gap:0; }
    .lang-code{ display:none; }
    .lang-flag{ width:26px; height:26px; }
  }

  /* ---------- FOOTER ----------
     A full-bleed band running the whole width of the viewport. It no longer
     takes a step down in value from the page - both are true black now - so
     the hairline along its top edge is doing all of the work of separating
     them. Remove it and the document simply runs on with no end.

     Everything above the columns is centred on the axis - wordmark, then the
     address, then the marks - so the footer opens the way a masthead does
     rather than repeating the header.

     Only the surface is edge to edge. Type stays inside .foot-inner at the
     page's own 1180px measure and on the page's own gutter, so the footer
     columns line up with every section above them instead of drifting out to
     the viewport edge on a wide screen. */
  footer{
    background:var(--footer-bg);
    border-top:1px solid var(--line);
  }
  .foot-panel{
    padding:clamp(56px,7vw,88px) var(--sp-6) clamp(48px,6vw,72px);
  }
  .foot-inner{max-width:calc(1180px - 2 * var(--sp-6)); margin:0 auto;}

  .foot-brand{
    display:flex; flex-direction:column; align-items:center; text-align:center;
    gap:var(--sp-4);
  }
  /* The address is the only line in the footer set at reading size in a
     display weight. It is also the one thing people scroll down here to find,
     so it is given the position that says so rather than being filed in the
     support column. The underline arrives on hover instead of sitting there,
     which keeps the block quiet at rest. */
  .foot-email{
    font-size:var(--t-lead); font-weight:600; color:var(--paper);
    letter-spacing:-0.02em;
    text-decoration:underline; text-decoration-color:transparent;
    text-underline-offset:5px; text-decoration-thickness:1.5px;
    transition:text-decoration-color .25s var(--ease);
  }
  .foot-email:hover{text-decoration-color:currentColor;}
  .foot-email:focus-visible{outline:2px solid var(--gold); outline-offset:3px; border-radius:6px;}

  /* ---------- SOCIAL MARKS ----------
     The marks stand on the page rather than sitting in discs. With no disc to
     give them presence they have to carry it themselves, so they are set at
     22px against the 17px they were - the disc was 42px, and the mark inside
     it now reads at about the size the whole button used to.

     The hit area does not shrink with the container: 11px of padding on each
     side keeps a 44px target under a 22px glyph. The row is centred under the
     wordmark now, and because that padding is symmetric the optical centre
     falls where the geometric one does - the old negative left margin, which
     cancelled the first mark's padding against a left-aligned wordmark, would
     pull the whole row off centre here and is gone.

     Hover moves colour rather than fill - up to the page's full ink from a
     resting 78% - with the same small lift the discs had. */
  .social-row{display:flex; gap:var(--sp-3); justify-content:center; margin:var(--sp-2) 0 0;}
  .social-icon{
    display:inline-flex; align-items:center; justify-content:center;
    padding:11px;
    color:var(--social-ink);
    -webkit-tap-highlight-color:transparent;
    transition:color .25s cubic-bezier(.22,.61,.36,1), transform .25s cubic-bezier(.22,.61,.36,1);
  }
  .social-icon svg{width:22px; height:22px; fill:currentColor; display:block;}
  /* The brand marks fill their 24x24 box very differently. X's artwork is only
     81% of the box tall and the in mark 78% tall, so a single
     size makes the row look ragged. These even out the optical weight. */
  .social-icon[aria-label="X"] svg{width:26px; height:26px;}
  .social-icon[aria-label="LinkedIn"] svg{width:24.5px; height:24.5px;}
  .social-icon:hover{ color:var(--paper); transform:translateY(-2px); }
  .social-icon:active{transform:translateY(0);}
  .social-icon:focus-visible{outline:2px solid var(--gold); outline-offset:2px; border-radius:8px;}
  @media (prefers-reduced-motion: reduce){
    .social-icon{ transition:color .25s ease; }
    .social-icon:hover{ transform:none; }
  }

  /* Five equal tracks spread the full width of the panel. minmax(0,1fr) and
     not 1fr: a 1fr track will not shrink below its longest unbreakable word,
     and "Withdrawals" is long enough to push its column wider than its
     neighbours as soon as the panel starts narrowing. */
  .foot-grid{
    display:grid; grid-template-columns:repeat(5,minmax(0,1fr));
    gap:var(--sp-8) var(--sp-5);
    margin-top:clamp(56px,7vw,96px);
  }
  /* 700 on full-strength ink. These ran 600 at --muted above links set
     15px/500 at --paper, so every column label was smaller, lighter AND
     dimmer than the items it was meant to head - the hierarchy read upside
     down. Weight and colour both step up; the size stays at --t-mono so the
     label is still distinguishable from a link by shape, not just weight. */
  .foot-col h5{font-family:var(--body); font-size:var(--t-mono); font-weight:700; letter-spacing:-0.008em; color:var(--paper); margin-bottom:var(--sp-4);}
  .foot-col a{display:block; font-size:var(--t-sm); font-weight:500; color:var(--paper); opacity:0.7; margin-bottom:var(--sp-3); transition:opacity .2s var(--ease);}
  .foot-col a:hover{opacity:1;}

  /* ---------- PLACE ----------
     One location, so this is a line rather than the column of addresses a
     multi-country footer needs.

     The flag is .fx-ng, the same gradient the rate calculator drops into the
     hero - three bands in one linear-gradient - so there is one Nigerian flag
     in this stylesheet rather than two that can drift apart. All this rule
     adds is the size and the ring, and the ring is not decoration: the centre
     band of the flag is white and the light-theme surface behind it is very
     nearly white, so without it the mark reads as two disconnected green
     blobs. An inset shadow is enough here because the span has no children -
     it paints over a background, which is all .fx-ng gives it. */
  /* Two groups on one line: the language control, then the address. They get a
     wider gap between them than the flag gets from its own label, so the row
     reads as two things rather than four. Wraps rather than overflows on a
     narrow phone, and centres either way. */
  .foot-place{
    display:flex; align-items:center; justify-content:center;
    gap:var(--sp-3) var(--sp-6); flex-wrap:wrap;
    margin-top:clamp(40px,5vw,64px);
    font-size:var(--t-sm); font-weight:500; color:var(--muted);
  }
  .foot-loc{ display:inline-flex; align-items:center; gap:var(--sp-3); }
  .foot-flag{
    flex:none; display:block; width:22px; height:22px;
    border-radius:50%; overflow:hidden;
    box-shadow:inset 0 0 0 1px var(--line);
  }

  /* ---------- FINE PRINT ----------
     Two registers, not one. The sentence that has to be there - Bitmoni is
     not a bank - is set at reading size on its own line, because dropping it
     into a grey 12px paragraph is how a site gets to say it disclosed
     something without anybody having read it. What follows is genuine small
     print and is set as such. */
  .foot-legal{
    margin-top:clamp(48px,6vw,80px);
    border-top:1px solid var(--line);
    padding-top:var(--sp-7);
    display:flex; flex-direction:column; align-items:center;
    gap:var(--sp-5); text-align:center;
  }
  /* No rule of its own any more. It had one to separate the copyright from
     the two disclaimer paragraphs that sat above it inside .foot-legal; with
     those gone it is the only child of that block, so its border landed just
     under .foot-legal's and read as a doubled line. The padding and margin
     went with it - they were spacing the text off that rule. */
  .foot-bottom{
    width:100%;
    font-size:var(--t-fine); color:var(--muted);
  }

  @media (max-width:1000px){
    .foot-grid{grid-template-columns:repeat(3,minmax(0,1fr));}
  }
  @media (max-width:800px){
    .foot-grid{grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--sp-7) var(--sp-5);}
    .hero-grid{grid-template-columns:1fr;}
  }
  /* The page gutter drops from 28 to 20 at 860. The band matches it rather
     than running its own scale, which is the whole point of putting the type
     on .foot-inner: the footer columns start on the same line as the sections
     above them at every width. */
  @media (max-width:860px){
    .foot-panel{padding-left:20px; padding-right:20px;}
  }
  @media (max-width:560px){
    .foot-email{font-size:var(--t-body);}
    .foot-legal{text-align:left; align-items:flex-start;}
    .foot-place{justify-content:flex-start;}
  }

  /* ---------- MOTION ---------- */
  @media (prefers-reduced-motion: no-preference){
    /* scroll reveal (classes added by JS) */
    /* 18px rather than 26px: a shorter travel on a longer, softer curve reads
       as considered, where a big jump reads as a stock scroll-animation. */
    .reveal{ opacity:0; transform:translateY(18px); transition:opacity .9s var(--ease-soft), transform .9s var(--ease-soft); }
    .reveal.in{ opacity:1; transform:none; }

    /* hero entrance */
    .hero h1,.hero .lead,.hero-actions{ opacity:0; animation:heroIn .75s cubic-bezier(.22,.61,.36,1) both; }
    .hero h1{ animation-delay:.15s; }
    .hero .lead{ animation-delay:.26s; }
    .hero-actions{ animation-delay:.36s; }
    .hero-visual{ opacity:0; animation:heroVis .9s cubic-bezier(.22,.61,.36,1) both; animation-delay:.30s; }
    @keyframes heroIn{ from{opacity:0; transform:translateY(20px);} to{opacity:1; transform:none;} }
    @keyframes heroVis{ from{opacity:0; transform:translateY(28px) scale(.965);} to{opacity:1; transform:none;} }

    /* floating hero visual */
      }

  /* ---------- MICRO-INTERACTIONS ---------- */
  .btn{ transition:transform .2s ease, background .2s ease, box-shadow .2s ease; }
  .btn:hover{ transform:translateY(-2px); }
  /* ---------- STORE BADGES ----------
     Official artwork, shipped byte-for-byte as Apple and Google both require
     ("use only the badge artwork provided"; "don't alter"). They are NOT
     interchangeable in geometry, so the two need different rules:

     - Apple's SVG is 119.66x40 and its grey border is part of the artwork,
       so its box is exactly the visible badge.
     - Google's PNG is 646x250 with 41px of transparent padding baked in on
       every side, and that padding IS their mandated quarter-height clear space.
       Its visible badge is therefore only 168/250 of the file. Rendering both
       at the same CSS height would make Google's look ~33% smaller, so its
       box is scaled up by 250/168 and the padding pulled back off with a
       negative margin, leaving both with an equal 44px visible height and a
       true 12px gap between them.

     44px clears Apple's 40px onscreen minimum and Google's 28px. */
  :root{ --badge-h:44px; }
  .store-badge{ display:inline-flex; align-items:center; transition:transform .2s var(--ease); }
  .store-badge img{ display:block; width:auto; height:var(--badge-h); }
  .store-badge.badge-gplay img{
    height:calc(var(--badge-h) * 1.4881);
    margin:calc(var(--badge-h) * -0.2440);
  }
  .store-badge:hover{ transform:translateY(-2px); }
  @media (prefers-reduced-motion: reduce){ .store-badge:hover{ transform:none; } }
  .btn:active{ transform:translateY(0); }
  .coins-band .visual-frame{ transition:transform .6s var(--ease-soft); }
  .coins-band:hover .visual-frame{ transform:translateY(-6px); }
  /* The wide panel lifts its art on hover; the half panels lift the whole
     card instead, so the two effects would otherwise stack in the row. */
  .box-row .coins-band:hover .visual-frame{ transform:none; }
  @media (prefers-reduced-motion: reduce){
    .btn:hover,.coins-band:hover .visual-frame{ transform:none; }
  }


  /* ---------- TRUST + FAQ ---------- */
  .trust-split{ display:grid; grid-template-columns:1fr 1fr; gap:64px; align-items:center; }
  .trust-copy h2{ margin-bottom:var(--sp-4); }
  .trust-copy p{ color:var(--muted); font-size:var(--t-body); line-height:1.6; letter-spacing:0; max-width:46ch; margin-bottom:0; }
  .trust-shield{ display:flex; justify-content:center; }
  .trust-shield img{ width:100%; max-width:260px; height:auto; display:block; }
  @media (max-width:860px){
    .trust-split{ grid-template-columns:1fr; gap:40px; }
    .trust-shield{ order:-1; }
    .trust-shield img{ max-width:200px; }
  }

  /* Heading holds the left column, questions the right. */
  .faq-grid{ display:grid; grid-template-columns:0.82fr 1.18fr; gap:var(--sp-8); align-items:start; }
  .faq-intro h2{ margin-bottom:var(--sp-5); }
  .faq-intro p{ font-size:var(--t-sm); line-height:1.55; color:var(--muted); max-width:32ch; }
  .faq-intro p a{ color:var(--paper); text-decoration:underline; text-underline-offset:2px; }
  .faq-list{ border-top:1px solid var(--line); }
  .faq-item{ border-bottom:1px solid var(--line); }
  .faq-item summary{
    list-style:none; cursor:pointer; padding:var(--sp-5) var(--sp-8) var(--sp-5) 0; position:relative;
    font-family:var(--body); font-size:var(--t-body); font-weight:600; letter-spacing:-0.015em; line-height:1.4;
    transition:opacity .2s var(--ease);
  }
  .faq-item summary::-webkit-details-marker{ display:none; }
  /* A plus whose vertical bar rotates onto the horizontal one, becoming a minus.
     ::before spans right 4-20px, so its centre is at 12px; the 1.5px vertical
     bar sits at 11.25px to share that centre. */
  .faq-item summary::before,
  .faq-item summary::after{
    content:''; position:absolute; top:50%; background:var(--paper);
    transition:transform .3s cubic-bezier(.22,.61,.36,1);
  }
  .faq-item summary::before{ right:4px; width:16px; height:1.5px; transform:translateY(-50%); }
  .faq-item summary::after{ right:11.25px; width:1.5px; height:16px; transform:translateY(-50%); }
  .faq-item[open] summary::after{ transform:translateY(-50%) rotate(90deg); }
  .faq-item summary:hover{ opacity:0.65; }
  .faq-item summary:focus-visible{ outline:2px solid var(--gold); outline-offset:4px; border-radius:6px; }
  .faq-item .faq-answer{ padding:0 var(--sp-8) var(--sp-6) 0; color:var(--muted); font-size:var(--t-base); line-height:1.6; }
  .faq-item .faq-answer a{ color:var(--gold); text-decoration:underline; text-underline-offset:2px; }
  @media (max-width:860px){
    .faq-grid{ grid-template-columns:1fr; gap:var(--sp-6); }
    .faq-intro p{ max-width:none; }
  }
  @media (prefers-reduced-motion: reduce){
    .faq-item summary::before,.faq-item summary::after{ transition:none; }
  }

  @media (max-width:560px){
    .faq-item summary{ font-size:16px; }
  }

  /* ---------- RATE CALCULATOR ----------
     Built to the reference box on bleap.finance, measured off the live DOM
     rather than off a screenshot. Every number below is theirs:

       card            flex column, #34C759, radius 32
       rows surface    #1A1A1A, radius 32, inset 0 0 0 2px #262626
       row             grid "label ." / "value selector", padding 24,
                       align-items center; a 2px #262626 bar on ::after of
                       every row but the last is the divider
       label           16/19.2, rgba(255,255,255,.4)
       figure          32/38.4, weight 400, rgba(255,255,255,.4)
       currency        flex, gap 8, code 20/24 #fff, flag 24 round, chev 16
       green bar       flex, space-between, gap 12, padding 8 16 12 24
       bar text        column, 14/16.8, #fff

     24 + 19.2 + 38.4 + 24 comes to the 105.594 their row measures, and two of
     those plus the 54px bar is the 265.188 of the card - so the proportions
     hold at any width, and this column stays 480 rather than their 342.

     Three things are deliberately not copied. The face is Albert Sans, not
     their licensed nbInternationalPro. The bar carries Bitmoni's live quote
     rather than "Save up to 6.59 EUR with Bleap", their logo and the two
     competitor avatars beside it. And the right-hand pill is not here: it was
     taken off this box earlier and nothing has asked for it back.

     The one place the copy is loosened is the figure size, and only
     downwards: see the note on the fit script below. */
  :root{
    /* The calculator column. 580 left the panel far wider than the figures
       inside it, so the rows read as mostly empty. One token, because the
       panel and the error line are the same column and were free to drift
       apart as two separate numbers. */
    --fx-width:min(480px, 100% - var(--fx-d) * 2.6);
    /* The diameter of a falling disc. It lives here rather than on the layer
       because the calculator is measured against it too. */
    --fx-d:46px;
    /* Their surface and the 2px line they draw on it. That one grey is both
       the ring around the panel and the divider between the rows - the same
       value in both places is what makes the divider read as the panel's own
       edge carried across the middle. */
    --fx-surface:#1A1A1A;
    --fx-line:#262626;
    --fx-ink:#FFFFFF;
    /* Label and figure are the same 40% white on their box. The figure is not
       dimmed because it is a placeholder - it is the resting state. */
    --fx-figure:rgba(255,255,255,0.4);
    --fx-label:rgba(255,255,255,0.4);
    --fx-accent:rgba(255,255,255,0.6);
    /* The native dropdown paints itself: a translucent fill would let the page
       show through the open menu, so the options get an opaque pair of their
       own rather than the panel's. */
    --fx-menu-bg:var(--paper);
    --fx-menu-ink:var(--brand);
    /* iOS system green, which is what they run. Its ink is near-black rather
       than the page's true black: on a saturated green, #000 reads as a hole
       punched through the bar. */
    --fx-promo-bg:#34C759;
    --fx-promo-ink:#FFFFFF;
  }

  .fx-head{ text-align:center; max-width:46ch; margin:0 auto var(--sp-7); }
  .fx-head .eyebrow{ justify-content:center; }
  .fx-head p{ color:var(--muted); font-size:var(--t-body); line-height:1.6; }

  /* The card is the green layer, and the surface is laid on top of it at full
     width. Neither clips, so the surface's 32px corners sit inside the card's
     and the green shows as a band under the rows and a curl around their two
     bottom corners. That curl is the shape - the bar is not a separate strip
     below the box, it is the box seen from behind. */
  .fx-calc{
    position:relative; max-width:var(--fx-width); margin:0 auto;
    display:flex; flex-direction:column;
    background:var(--fx-promo-bg); border-radius:32px;
    transition:opacity .3s var(--ease);
  }
  .fx-fields{
    display:flex; flex-direction:column;
    background:var(--fx-surface); border-radius:32px;
    box-shadow:inset 0 0 0 2px var(--fx-line);
  }

  /* Two rows of a two-by-two grid: the label over the figure in the first
     column, the currency parked in the second on the figure's line. The empty
     cell beside the label is what keeps the currency down there rather than
     letting it stretch up the full height of the row. */
  .fx-field{
    position:relative;
    display:grid; align-items:center;
    grid-template-columns:1fr auto;
    grid-template-areas:"label ." "value selector";
    /* Their grid has no column gap - the two columns meet, because four
       digits never come close to the currency. Eleven digits of naira arrive
       at it exactly, and the fit script would happily shrink the figure until
       it was touching the flag. The gap is the stop: invisible at their
       content, load-bearing at ours. */
    column-gap:16px;
    padding:24px;
  }
  /* The divider is drawn by the row above it rather than as a border on the
     row below, which is how they do it: a 2px bar in the ring's own grey,
     laid across the full width with no inset at either end. */
  .fx-field:not(:last-child)::after{
    content:""; position:absolute; left:0; right:0; bottom:0;
    height:2px; background:var(--fx-line);
  }

  .fx-label{
    grid-area:label;
    font-family:var(--body); font-size:16px; font-weight:400;
    line-height:1.2; color:var(--fx-label);
  }

  /* The figure runs at 32px and is pulled down by script when the number is
     too long for its column. Theirs never has to be: a thousand reais is four
     digits. One bitcoin is eleven digits of naira, which at 32px is twice the
     width of the cell it has to sit in, so the ceiling is copied and the
     floor is ours. */
  .fx-amount{
    grid-area:value; min-width:0; width:100%;
    font-family:var(--body); font-size:32px; font-weight:400;
    line-height:1.2; color:var(--fx-figure);
    font-variant-numeric:tabular-nums;
    background:none; border:0; padding:0;
  }
  .fx-amount::placeholder{ color:var(--fx-figure); opacity:.5; }
  .fx-amount:focus{ outline:none; }

  /* The currency, and the invisible select stretched over it. Only this block
     opens the picker - when the whole row was the target, a tap anywhere near
     the figure raised a dropdown instead of the keyboard. */
  .fx-cur{
    grid-area:selector; justify-self:end;
    position:relative; display:flex; align-items:center; gap:8px;
  }
  .fx-mark{
    flex:none; width:24px; height:24px; border-radius:50%;
    display:grid; place-items:center; overflow:hidden;
    /* XRP and Cosmos are branded near-black, which on an ink panel is an
       invisible badge with a floating glyph. A neutral hairline reads against
       both a dark and a light badge, so it does not need a per-theme value. */
    box-shadow:inset 0 0 0 1px rgba(128,128,128,0.38);
  }
  /* The badge carries the coin's own logo where the set has one, and the
     lettered fallback where it does not. Both take their colour from the
     badge, which the script sets per coin: white on nearly all of them, ink
     on BNB, whose yellow will not hold a white mark. */
  .fx-mark{ color:#fff; }
  .fx-mark b{
    font-family:var(--body); font-weight:700; font-size:11px; line-height:1;
    letter-spacing:-0.03em; color:inherit;
  }
  .fx-mark svg{ width:66%; height:66%; display:block; fill:currentColor; }
  .fx-code{
    font-family:var(--body); font-size:20px; font-weight:400;
    line-height:1.2; color:var(--fx-ink); white-space:nowrap;
  }
  .fx-chev{ flex:none; color:var(--fx-accent); }
  /* The native select is stretched invisibly over the currency block: it keeps
     the keyboard behaviour, the mobile wheel picker and the accessible name
     that a div-and-listbox reimplementation would have to rebuild from
     scratch. */
  .fx-pick{
    position:absolute; inset:-10px -8px;
    opacity:0; cursor:pointer; font:inherit; border:0;
    background:var(--fx-menu-bg); color:var(--fx-menu-ink);
  }
  .fx-pick option{ background:var(--fx-menu-bg); color:var(--fx-menu-ink); }
  .fx-cur:has(.fx-pick:focus-visible){
    outline:2px solid var(--fx-accent); outline-offset:6px; border-radius:8px;
  }

  /* ---------- THE GREEN BAR ----------
     Their bar is two lines of 14px on the left and a pill on the right. The
     quote takes the two lines: the rate on the first, its move and the time it
     was taken on the second. That lands the bar at the 54px theirs measures
     without having to set a height on it. */
  .fx-promo{
    display:flex; align-items:center; justify-content:space-between;
    gap:12px; padding:8px 16px 12px 24px;
  }
  .fx-meta{
    margin:0; display:flex; flex-direction:column;
    font-family:var(--body); font-size:14px; line-height:1.2;
    color:var(--fx-promo-ink);
  }
  .fx-quote{ font-weight:500; font-variant-numeric:tabular-nums; }
  .fx-sub{ display:flex; align-items:center; gap:4px; opacity:.85; }
  .fx-dot{ opacity:.6; }
  .fx-change{ font-variant-numeric:tabular-nums; }
  .fx-change[data-dir="up"]::before{ content:"\25B2\A0"; font-size:8px; vertical-align:1px; }
  .fx-change[data-dir="down"]::before{ content:"\25BC\A0"; font-size:8px; vertical-align:1px; }

  /* Where the product actually is today, sitting directly under the picker
     that raises the question. It is deliberately a step louder than the fine
     print beneath it - the first sentence takes the page's full ink - because
     it is a statement of position rather than a disclaimer. */
  .fx-scope{
    max-width:62ch; margin:var(--sp-5) auto 0; text-align:center;
    font-size:var(--t-sm); color:var(--muted); line-height:1.6;
  }
  .fx-scope strong{ color:var(--paper); font-weight:600; }
  .fx-fine{
    max-width:56ch; margin:var(--sp-4) auto 0; text-align:center;
    font-size:var(--t-fine); color:var(--muted); line-height:1.6;
  }
  /* While a refresh is in flight the figures on screen are last-known, not
     wrong, so they dim rather than disappearing. */
  .fx-panel.is-loading .fx-calc{ opacity:.55; }
  /* The quote is all the bar carries, so with no rate to print it goes rather
     than sitting there as a bare green strip. The card's own green would then
     be a rim around the rows with nothing under it, so that goes too and the
     panel closes up to the alert underneath. */
  .fx-panel.has-error .fx-promo{ display:none; }
  .fx-panel.has-error .fx-calc{ background:none; }
  .fx-alert{ display:none; }
  .fx-panel.has-error .fx-alert{
    display:block; max-width:var(--fx-width); margin:var(--sp-5) auto 0; text-align:center;
    font-size:var(--t-sm); color:var(--muted);
  }

  /* ---------- FALLING FLAGS ----------
     Twenty-five flags - fifteen African, six European, four from the Americas
     - drop into the section like coins into a tray, knock against the
     calculator and against each other, and settle in a heap along the floor.
     The ellipse they used to walk read as machinery: every flag at one speed,
     on one track, forever. Falling gives the section a beginning, and leaves a
     pile that is never quite the same twice.

     The set is decoration, not a claim about where money can go. The currency
     list in the calculator is the part that says what Bitmoni quotes.

     This layer is the play area; the solver that moves the flags is at the
     foot of the page. Three things it needs from this sheet. The layer clips,
     so a flag still waiting overhead never reaches the heading above. It sits
     under the calculator, so a flag that lands on a card shows only the sliver
     standing above the card's edge. And every flag is positioned from the
     layer's top-left corner, because a transform is all the solver writes per
     frame.

     Flags are CSS gradients and coins are inline SVG, neither of them images -
     forty-five more requests for decoration is not a trade worth making, and
     both stay sharp at any pixel density. Forty-five elements is also short of
     the count where a canvas would start to pay for itself. */
  .fx-stage{ position:relative; padding:clamp(96px,11.5vw,160px) 0 clamp(76px,10.5vw,140px); }
  .fx-calc{ z-index:1; }
  .fx-drop{
    position:absolute; inset:0; z-index:0; overflow:hidden;
    pointer-events:none;
  }
  /* Picking a flag up is a pointer affordance only: on a touch screen this
     layer would swallow the swipe that scrolls the page. */
  .fx-drop.is-grabbable{ pointer-events:auto; cursor:grab; }
  .fx-drop.is-holding{ cursor:grabbing; }

  .fx-flag{
    position:absolute; top:0; left:0;
    width:var(--fx-d); height:var(--fx-d);
    border-radius:50%; overflow:hidden;
    box-shadow:0 0 0 2px var(--brand), 0 6px 18px rgba(0,0,0,0.16);
    will-change:transform;
    /* Held back until the solver has placed them, so a script that never runs
       leaves nothing behind rather than a heap of flags piled in the corner. */
    visibility:hidden;
  }
  .fx-drop.is-live .fx-flag{ visibility:visible; }
  /* The three emblems the set needs. Anything more detailed than these - a
     maple leaf, a coat of arms, the twelve stars of the union - would be a
     handful of bytes of clip-path each to land as a smudge at 46px, so the
     flags that carry one are stylised down to its silhouette and its colour.
     Morocco has been a plain red field with a green star here from the start;
     Canada and Brazil join it on the same terms. */
  .fx-flag i{
    position:absolute; top:50%; left:50%;
    width:36%; height:36%; transform:translate(-50%,-50%);
  }
  .fx-flag i.star{
    clip-path:polygon(50% 0%,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%);
  }
  .fx-flag i.dot{ width:30%; height:30%; border-radius:50%; }
  .fx-flag i.gem{ width:66%; height:66%; clip-path:polygon(50% 6%,94% 50%,50% 94%,6% 50%); }

  /* A coin disc is a flag disc in every respect but its face: the same
     circle, the same ring, the same shadow, so the set reads as one pile and
     not as two. Its brand colour and its mark colour are set inline, because
     twenty one-line rules for twenty backgrounds is a sheet nobody can read.
     The logo sits at 58% rather than filling the disc - a flag fills its
     circle edge to edge, and a mark that did the same would look larger than
     the flags beside it at the same diameter. */
  .fx-coin{ display:grid; place-items:center; color:#fff; }
  .fx-coin svg{ width:58%; height:58%; display:block; fill:currentColor; }
  /* The sprite is a definitions block, not a picture: it is in the flow of
     the document and must take no room in it. */
  .ci-sprite{ position:absolute; width:0; height:0; overflow:hidden; }

  .fx-ng{ background:linear-gradient(90deg,#008751 0 33.33%,#fff 0 66.66%,#008751 0); }
  .fx-gh{ background:linear-gradient(180deg,#CE1126 0 33.33%,#FCD116 0 66.66%,#006B3F 0); }
  .fx-ke{ background:linear-gradient(180deg,#000 0 30%,#fff 0 36%,#BB0000 0 64%,#fff 0 70%,#006600 0); }
  .fx-sn{ background:linear-gradient(90deg,#00853F 0 33.33%,#FDEF42 0 66.66%,#E31B23 0); }
  .fx-ci{ background:linear-gradient(90deg,#F77F00 0 33.33%,#fff 0 66.66%,#009E60 0); }
  .fx-cm{ background:linear-gradient(90deg,#007A5E 0 33.33%,#CE1126 0 66.66%,#FCD116 0); }
  .fx-ml{ background:linear-gradient(90deg,#14B53A 0 33.33%,#FCD116 0 66.66%,#CE1126 0); }
  .fx-gn{ background:linear-gradient(90deg,#CE1126 0 33.33%,#FCD116 0 66.66%,#009460 0); }
  .fx-et{ background:linear-gradient(180deg,#078930 0 33.33%,#FCDD09 0 66.66%,#DA121A 0); }
  .fx-eg{ background:linear-gradient(180deg,#CE1126 0 33.33%,#fff 0 66.66%,#000 0); }
  .fx-ma{ background:#C1272D; }
  .fx-tz{ background:linear-gradient(45deg,#1EB53A 0 38%,#FCD116 0 42%,#000 0 58%,#FCD116 0 62%,#00A3DD 0); }
  .fx-rw{ background:linear-gradient(180deg,#00A1DE 0 50%,#FAD201 0 75%,#20603D 0); }
  .fx-ga{ background:linear-gradient(180deg,#009E60 0 33.33%,#FCD116 0 66.66%,#3A75C4 0); }
  /* South Africa's Y, built as nested wedges pointing in from the hoist,
     each a conic gradient a step further right so their edges run parallel:
     the black triangle, its gold edge, the green arm and its white edge. */
  .fx-za{
    background:
      conic-gradient(at 30% 50%,transparent 0 215deg,#000 0 325deg,transparent 0),
      conic-gradient(at 38% 50%,transparent 0 215deg,#FFB81C 0 325deg,transparent 0),
      conic-gradient(at 50% 50%,transparent 0 215deg,#007749 0 325deg,transparent 0),
      linear-gradient(180deg,transparent 40%,#007749 0 60%,transparent 0),
      conic-gradient(at 60% 50%,transparent 0 215deg,#fff 0 325deg,transparent 0),
      linear-gradient(180deg,transparent 32%,#fff 0 68%,transparent 0),
      linear-gradient(180deg,#E03C31 0 50%,#001489 0);
  }

  /* Europe and the Americas. */
  .fx-fr{ background:linear-gradient(90deg,#002395 0 33.33%,#fff 0 66.66%,#ED2939 0); }
  .fx-de{ background:linear-gradient(180deg,#000 0 33.33%,#DD0000 0 66.66%,#FFCE00 0); }
  .fx-it{ background:linear-gradient(90deg,#008C45 0 33.33%,#F4F5F0 0 66.66%,#CD212A 0); }
  .fx-es{ background:linear-gradient(180deg,#AA151B 0 25%,#F1BF00 0 75%,#AA151B 0); }
  .fx-ch{
    background:
      linear-gradient(90deg,transparent 38%,#fff 0 62%,transparent 0),
      linear-gradient(180deg,transparent 38%,#fff 0 62%,transparent 0),
      #D52B1E;
  }
  /* The Union Jack in layers, nearest the eye first: the red cross, the white
     cross under it, then the red and white diagonals, on navy. */
  .fx-gb{
    background:
      linear-gradient(90deg,transparent 41%,#C8102E 0 59%,transparent 0),
      linear-gradient(180deg,transparent 41%,#C8102E 0 59%,transparent 0),
      linear-gradient(90deg,transparent 33%,#fff 0 67%,transparent 0),
      linear-gradient(180deg,transparent 33%,#fff 0 67%,transparent 0),
      linear-gradient(45deg,transparent 47%,#C8102E 0 53%,transparent 0),
      linear-gradient(-45deg,transparent 47%,#C8102E 0 53%,transparent 0),
      linear-gradient(45deg,transparent 43%,#fff 0 57%,transparent 0),
      linear-gradient(-45deg,transparent 43%,#fff 0 57%,transparent 0),
      #012169;
  }
  .fx-us{
    background:
      linear-gradient(90deg,#3C3B6E 0 42%,transparent 0),
      repeating-linear-gradient(180deg,#B22234 0 15.4%,#fff 0 30.8%);
  }
  .fx-ca{ background:linear-gradient(90deg,#D80621 0 25%,#fff 0 75%,#D80621 0); }
  .fx-br{ background:#009C3B; }
  .fx-ar{ background:linear-gradient(180deg,#74ACDF 0 33.33%,#fff 0 66.66%,#74ACDF 0); }

  /* Forty-five discs need a smaller coin on a phone, and the calculator
     narrows with them: --fx-width holds a channel of 1.3 diameters open on
     each side of the cards at every width, so a disc can always fall past
     them to the floor. Below about 620px the cards used to meet the walls,
     and the whole set piled on their top edge - the same section behaving
     like a different one on a phone. */
  @media (max-width:760px){
    :root{ --fx-d:36px; }
  }
  @media (max-width:560px){
    :root{ --fx-d:30px; }
  }

  /* The reference box is drawn at fixed pixel values and is served the same
     ones on a phone - it only ever has to hold four digits. The two that have
     to give here are the padding, which at 24 leaves a 375px screen barely
     240px of figure, and the radius that follows it down. Everything the eye
     reads as the box - the 2px ring, the divider, the type scale, the green
     bar's own padding - is left at their values. */
  @media (max-width:560px){
    .fx-calc,.fx-fields{ border-radius:24px; }
    .fx-field{ padding:var(--sp-4); }
    .fx-promo{ padding:var(--sp-2) var(--sp-3) var(--sp-3) var(--sp-4); }
  }
  @media (prefers-reduced-motion: reduce){
    .fx-calc{ transition:none; }
  }

  /* Responsive spacing. Last in the sheet so it overrides the base rules. */
  @media (max-width:860px){
    section{padding:var(--sp-7) 0;}
    .wrap{padding:0 20px;}
    .coins-band{gap:var(--sp-7);}
  }
  @media (max-width:560px){
    /* --badge-h drops to 40px here, which is exactly Apple's documented
       onscreen minimum. The derivation used to be tighter than a preference:
       the closing band's centred pair needed height*6.3487 + gap (Apple 2.9916
       + Google 3.3571 aspect), overflowed 375px at 44, and wrapped onto two
       visibly offset rows. That band is gone and the hero column has room for
       44 at this width, so 40 is now a judgement rather than a fix - the
       badges should read as a footnote to the headline, not a second call to
       action. */
    :root{ --t-lead:1.125rem; --t-body:1rem; --badge-h:40px; }
  }
  /* Below ~340px even minimum-size badges cannot share a line. Stack them
     deliberately rather than letting them wrap into a pair that looks
     accidentally misaligned. */
  @media (max-width:340px){
    .hero-actions{ flex-direction:column; align-items:flex-start; }
  }

