  /* Local asset URLs below are ROOT-ABSOLUTE (/assets/…), not relative.
     A relative url() resolves against the STYLESHEET, not the page: while these
     rules were inline in index.html, `assets/x` meant `/assets/x`, but from
     /assets/site.css the same string means `/assets/assets/x` and 404s. That
     silently broke the paper texture and the yacht band when this file was
     extracted. Root-absolute makes the stylesheet's own location irrelevant. */

  /* ============ Fonts ============
     The Figma file sets the serif as "Aime Trial"; this is the same family from
     the brand's own host. Both italics are declared — without them font-style:
     italic only gets a sheared roman, which is not the drawn italic. */
  @font-face {
    font-family: 'Aime'; font-style: normal; font-weight: 400; font-display: swap;
    src: url('https://images.gvnr.xyz/fonts/Aime/Aime-Regular.otf') format('opentype');
  }
  @font-face {
    font-family: 'Aime'; font-style: normal; font-weight: 700; font-display: swap;
    src: url('https://images.gvnr.xyz/fonts/Aime/Aime-Bold.otf') format('opentype');
  }
  @font-face {
    font-family: 'Aime'; font-style: italic; font-weight: 400; font-display: swap;
    src: url('https://images.gvnr.xyz/fonts/Aime/Aime-Italic.otf') format('opentype');
  }
  @font-face {
    font-family: 'Aime'; font-style: italic; font-weight: 700; font-display: swap;
    src: url('https://images.gvnr.xyz/fonts/Aime/Aime-BoldItalic.otf') format('opentype');
  }
  @font-face {
    font-family: 'PPPlayground'; font-style: normal; font-weight: 300; font-display: swap;
    src: url('https://images.gvnr.xyz/fonts/PPPlayground/PPPlayground-Light.otf') format('opentype');
  }

  /* ============ Tokens ============ */
  :root {
    --cream: #E5E5D5;
    --lime: #D3FE8A;
    --ink: #131313;
    /* The design frame is 1920x990, so every measurement below is the Figma
       number written as calc(N * var(--u)) and the whole thing scales as one.
       Tracks BOTH axes and takes the tighter: the hero fills the screen, so a
       short window starves it exactly like a narrow one does. */
    --u: clamp(0.5px, min(calc(100vw / 1920), calc(100vh / 990)), 1px);
    /* The sheet's side margin. On the desktop frame it is the hero's own 80;
       the tablet and phone tiers below reset it to a standard device margin. */
    --gutter: calc(80 * var(--u));
  }

  /* ============ Reset ============ */
  * { margin: 0; padding: 0; box-sizing: border-box; }
  html { scroll-behavior: smooth; font-size: calc(16 * var(--u)); }
  /* The bar is fixed, so an anchor would otherwise land its target underneath it.
     Each destination keeps the bar's height clear, plus a little air. #top is
     left out: the hero is meant to arrive flush against the top. */
  /* #gvnr belongs here too now that the bar aims at it: without the inset the
     section lands under the sticky bar and the eyebrow is the part it eats. */
  #borrow, #earn, #butler, #ucd, #gvnr, #security, #faq { scroll-margin-top: calc(120 * var(--u)); }
  body {
    background: #000006; color: var(--cream);
    font-family: 'Manrope', sans-serif; -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
  }
  img, svg { display: block; max-width: 100%; }
  /* The browser's own [hidden] rule is a bare attribute selector, so any class
     that sets display beats it. Anything hidden here should stay hidden. */
  [hidden] { display: none !important; }
  a { color: inherit; text-decoration: none; }

  /* ============ Hero — Figma 3380:4015 ============
     1920x990, column, gap 100, padding 20 / 80 / 80. */
  .hero {
    position: relative; overflow: hidden;
    min-height: 100svh;
    display: flex; flex-direction: column; align-items: center;
    gap: calc(100 * var(--u));
    /* 144 = the bar twice over: it clears the 72 the fixed bar occupies and
       leaves the same 72 again as air, so the eyebrow starts one nav-height
       below it rather than the 20 it had. The room comes out of the slack in
       the middle of the hero, which was running 402 empty. */
    padding: calc(168 * var(--u)) var(--gutter) calc(80 * var(--u));
  }
  /* The photograph is 1920x1117 against a 990-tall frame — it overruns the foot
     by design and the frame clips it. A flat 60% black over it, not a gradient:
     that is what the file specifies. */
  .hero-bg { position: absolute; inset: 0; z-index: 0; }
  .hero-bg img { width: 100%; height: 100%; object-fit: cover; object-position: center top; }
  .hero-bg::after { content: ''; position: absolute; inset: 0; background: rgba(0, 0, 0, 0); }

  /* ============ Nav ============ */
  /* Fixed, so it is reachable from anywhere on the page. It keeps the hero's own
     side padding so the logo and the button stay on the same margins they had
     when the bar sat in the flow. */
  .nav {
    position: fixed; top: 0; left: 0; right: 0; z-index: 50;
    /* 96, not 72. The mark is 47 tall, so the old bar left it 12 of air top and
       bottom and it read as pinned to the edge of the screen. 96 doubles that
       to 24 either side. Padding could not do this: box-sizing is border-box
       page-wide, so it would have eaten the same 72 and pushed the mark out the
       bottom instead of away from the top. */
    height: calc(96 * var(--u));
    padding: 0 var(--gutter);
    display: flex; align-items: center; justify-content: space-between;
    /* The ground rides a 0..1 the script keeps in step with the scroll, so it
       arrives gradually instead of switching on. No transition here on purpose:
       the value is already continuous, and easing it would only add lag. */
    background: rgba(19, 19, 19, calc(var(--nav-ground, 0) * 0.92));
    box-shadow: 0 1px 0 rgba(229, 229, 213, calc(var(--nav-ground, 0) * 0.12));
  }

  /* Dead centre of the bar, not the leftover between logo and button — those two
     weigh differently, so space-between alone leaves the links off-axis. */
  .nav-links {
    position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  }
  /* One asset, not a composed group: the file carries the diamond, the wordmark
     and the GVNR mark already set against one another, so the alignment between
     them belongs to the artwork rather than to this sheet.
     It used to take scale(1 - ground * 0.18) and settle down to 82% as the bar
     took its ground. Vero's call to drop it: the mark holds one size the whole
     way down the page. --nav-ground stays — it is what the bar's own background
     and hairline still ride on, and only the logo has stopped listening to it. */
  .nav-logo { display: block; }
  /* 51 is derived, not picked. "Diamond Hands" fills 35 of the file's 38, and it
     used to render at 47 — so 47/35 x 38 = 51 holds the name at exactly the size
     it has always had, and the GVNR follows at the size it was drawn beside it. */
  .nav-lockup { height: calc(51 * var(--u)); width: auto; display: block; }
  .nav-links { display: flex; gap: calc(28 * var(--u)); }
  .nav-links a {
    font-size: calc(14 * var(--u)); line-height: calc(22.4 * var(--u));
    /* Rests below full and brightens on hover, the way every other text link on
       the page behaves — the footer already did this and the bar did not. It
       also fixes a contrast failure: sampled against the photograph behind the
       bar, the old hover took the link from 6.93:1 down to 4.34:1, under the
       4.5 floor, so it got harder to read at the moment you aimed at it. */
    color: rgba(229, 229, 213, 0.8); transition: color .15s ease;
  }
  .nav-links a:hover { color: var(--cream); }
  .btn {
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--lime); color: #000; border-radius: calc(2 * var(--u));
    padding: calc(13 * var(--u)) calc(26 * var(--u));
    font-weight: 600; font-size: calc(13 * var(--u)); line-height: calc(20.8 * var(--u));
    letter-spacing: calc(1.04 * var(--u)); text-transform: uppercase; white-space: nowrap;
    transition: background-color .15s ease;
  }
  .btn:hover { background: #c5f470; }

  /* ============ Hero body ============
     justify-between, so the stats sit on the foot of the frame whatever the type
     above them does. */
  .hero-body {
    position: relative; z-index: 2;
    flex: 1 0 0; width: 100%;
    display: flex; flex-direction: column; align-items: center; justify-content: space-between;
  }
  .hero-head { display: flex; flex-direction: column; align-items: center; gap: calc(46.677 * var(--u)); }
  .hero-eyebrow {
    font-weight: 700; font-size: calc(9.976 * var(--u)); line-height: calc(15.961 * var(--u));
    letter-spacing: calc(3.9903 * var(--u)); text-transform: uppercase; text-align: center;
  }
  .hero-title {
    display: flex; flex-direction: column; align-items: center; gap: calc(12.447 * var(--u));
    --h1: min(calc(93.354 * var(--u)), calc((100vw - 2 * var(--gutter)) / 8.2));
  }
  .hero-title h1 {
    font-family: 'Aime', serif; font-weight: 400;
    /* .682 is 63.657/93.354 — the drawn leading, written as a ratio so it
       follows the size down instead of staying at a fixed 63. */
    font-size: var(--h1); line-height: .682;
    white-space: nowrap;
  }
  /* Live text again: the old line was an outlined vector from Figma, but the copy
     changed, which killed the export — and the face it was drawn in is this same
     PPPlayground. Sized against the h1 at the 6.2:5.4 ratio the brand's earlier
     hero used for the pair. */
  .hero-script {
    font-family: 'PPPlayground', cursive; font-weight: 300;
    font-size: calc(var(--h1) * 1.1462); line-height: 1.25;
    color: var(--lime); white-space: nowrap;
  }
  .hero-sub {
    font-family: 'Bebas Neue', sans-serif;
    font-size: calc(19.062 * var(--u)); line-height: calc(19.795 * var(--u));
    letter-spacing: calc(1.9062 * var(--u)); text-align: center;
  }

  /* ---- Entrance — on load, not on scroll ----
     The eyebrow and the sub fade; the headline flips in word by word, the same
     move every section heading further down takes and the one its own figures
     below it already used.

     .9s, not the 1.6 this ran at before: at 1.6 the hero was going at less than
     half the tempo of the rest of the page, and the sub was landing at 2.30
     while the figures landed at 2.26 — two beats arriving as one. At .9 the
     chain reads eyebrow 1.05, headline 1.48, sub 1.60, figures 2.26. */
  @keyframes heroFade {
    from { opacity: 0; }
    to { opacity: 1; }
  }
  /* The perspective lives on the PAIR, not on each line: one vanishing point for
     both means the two lines flip as a single composition rather than as two
     unrelated pieces of type.

     And it is a multiple of the headline's own size, not a fixed number. What a
     reader actually sees is the word's height over the perspective, so a fixed
     figure would make the flip half as deep on a phone, where the line drops
     from 93 to 43. 11.78x reproduces the 1100 the desktop wants and holds the
     same depth at every size. */
  .hero-title { perspective: calc(var(--h1) * 11.78); }
  .hero-title .w {
    display: inline-block; opacity: 0;
    animation: wordFlip .9s cubic-bezier(0.22, 1, 0.36, 1) forwards;
    animation-delay: calc(.3s + var(--i, 0) * 70ms);
  }
  .hero-eyebrow, .hero-sub {
    opacity: 0;
    animation-duration: .9s;
    animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
    animation-fill-mode: forwards;
  }
  .hero-eyebrow { animation-name: heroFade; animation-delay: .15s; }
  .hero-sub { animation-name: heroFade; animation-delay: .7s; }
  @media (prefers-reduced-motion: reduce) {
    .hero-eyebrow, .hero-sub { opacity: 1; animation: none; }
    .hero-title .w { opacity: 1; transform: none; animation: none; }
  }

  .hero-stats {
    display: flex; align-items: center; gap: calc(60 * var(--u));
    width: calc(952.122 * var(--u));
  }
  .stat {
    display: flex; flex-direction: column; gap: calc(6 * var(--u));
    padding-bottom: calc(8 * var(--u));
    border-bottom: calc(1.801 * var(--u)) solid rgba(255, 255, 255, 0.2);
  }
  .stat .v {
    font-family: 'Aime', serif; font-weight: 400;
    font-size: calc(30 * var(--u)); line-height: 1; color: var(--lime); white-space: nowrap;
  }
  .stat .l {
    font-family: 'Bebas Neue', sans-serif;
    font-size: calc(19.812 * var(--u)); line-height: calc(31.7 * var(--u));
    letter-spacing: calc(3.6023 * var(--u)); text-transform: uppercase;
    color: rgba(255, 255, 255, 0.5); white-space: nowrap;
  }

  /* ============ Paper ============
     Everything below the hero sits on the same sheet.
     The sheet is a fixed layer the page scrolls over, not a background on the
     container. Painted on the container it had to cover 1905 x 6469 from a
     1600 x 1200 file — a 5.7x vertical stretch, which is what made it blurry.
     Fixed, it only ever covers one screen and the texture stays at its own scale.
     A layer rather than background-attachment: fixed, which iOS Safari does not
     honour and which forces a full repaint on every scroll frame. */
  .paper-bg { position: fixed; inset: 0; z-index: -1; background-color: #E5E5D5; }
  /* 80%. The file has it at 50%; this is Vero's call for the build.
     Multiplied, not laid over. The texture file is opaque and averages #EAE9E4 —
     near white — so stacking it at 80% painted over the cream and the sheet came
     out #E9E8E1. Multiplying makes its white transparent and lets only the grain
     darken, which is what ink on paper actually does. */
  .paper-bg::after {
    /* Was .8 — Vero's earlier call, revised on 2026-08-25 for being too loud.
       At .8 the grain read 2.03 and pulled the sheet 16.7 luma below the cream
       it is painted on; at .6 it reads 1.53 and 12.6, so the texture stays and
       the paper comes back up. */
    content: ''; position: absolute; inset: 0; opacity: .6;
    mix-blend-mode: multiply;
    background-image: url('/assets/paper-texture-hi.webp');
    background-size: cover; background-position: center;
  }
  /* Transparent on purpose: a fill here would hide the sheet behind it */
  .paper { position: relative; }
  /* The design's own measure: a 1320 column centred in the 1920 frame. */
  .wrap { position: relative; width: calc(1320 * var(--u)); margin-inline: auto; }

  /* ============ Problem — Figma 3380:4076 ============ */
  /* clip, not hidden — the same reason as .ucd: hidden would make this section a
     scroll container and kill position: sticky on the option cards inside it. It
     paints identically, and what it guards (the band's chevrons) is already
     cropped by the band's own overflow. */
  .problem {
    position: relative; overflow: clip;
    margin-top: calc(100 * var(--u)); padding: 0 0 calc(60 * var(--u));
  }
  .prob-eyebrow {
    font-weight: 600; font-size: calc(11 * var(--u)); line-height: calc(17.6 * var(--u));
    letter-spacing: calc(4.4 * var(--u)); text-transform: uppercase;
    color: #737373; text-align: center;
  }
  .prob-h {
    font-family: 'Aime', serif; font-weight: 400;
    font-size: calc(40 * var(--u)); line-height: 1.2;
    color: var(--ink); text-align: center; margin-top: calc(30 * var(--u));
  }
  .prob-sub {
    font-size: calc(14 * var(--u)); line-height: calc(25.6 * var(--u));
    color: #222; text-align: center; margin-top: calc(30 * var(--u));
    max-width: calc(760 * var(--u)); margin-inline: auto;
  }
  /* Narrower than the wrap: every box on the page holds to 1206 inside the 1320
     column, so the header breathes wider than the furniture under it. The 1206
     is set by the product blocks — see .prod-block for where it comes from. */
  .prob-cards, .fourth-band { width: calc(1206 * var(--u)); margin-inline: auto; }
  .prob-cards {
    display: flex; gap: calc(20 * var(--u)); align-items: stretch;
    margin-top: calc(40 * var(--u));
  }
  .prob-card {
    position: relative; overflow: hidden;
    flex: 1 0 0; min-width: 0;
    background: #CBC5AD; border-radius: calc(4 * var(--u));
    /* 60 vertical, 40 horizontal. The content is 160 tall, so at a flat 40 the
       card sat at 1.62 — the same flatness the security cards had before their
       own fix. 60 brings it to 1.39, matching them, and the horizontal stays at
       40 so the copy keeps the measure and the line breaks it has now. */
    padding: calc(60 * var(--u)) calc(40 * var(--u));
    transition: transform .35s cubic-bezier(.22, 1, .36, 1), box-shadow .35s ease;
  }
  /* The same grain the dark cards carry, but not at the same strength. The file
     is dark ink on transparency — mean alpha .17, luma 50 — which on the olive
     lands within a point of the ground and reads as pure texture, no tint. This
     sand is luma 196, so every grain pixel is a step down: at the dark cards' .6
     it would pull the card 14 luma darker, a visibly muddier sand. At .35 the
     texture is about 60% of theirs and the dulling is 8 luma, which reads as
     tooth in the paper rather than dirt on it. */
  .prob-card::after {
    content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
    background-image: url('https://images.gvnr.xyz/diamonds/bg-noise.svg');
    background-size: cover; background-position: center; opacity: .23;
  }
  /* the card content rides over the grain */
  .prob-card > * { position: relative; z-index: 2; }
  /* It lifts off the sheet rather than changing colour: a small rise and the
     shadow that implies. Transform and shadow only, so nothing around it moves. */
  .prob-card:hover {
    transform: translateY(calc(-6 * var(--u)));
    box-shadow: 0 0 0 1px rgba(19, 19, 19, 0.18);
  }
  @media (prefers-reduced-motion: reduce) {
    .prob-card { transition: none; }
    .prob-card:hover { transform: none; }
  }
  .prob-card-in {
    display: flex; flex-direction: column; gap: calc(20 * var(--u));
    padding: calc(20 * var(--u)) 0 calc(21 * var(--u));
  }
  .prob-n {
    font-family: 'Bebas Neue', sans-serif; font-size: calc(14 * var(--u));
    letter-spacing: calc(0.7 * var(--u));
    line-height: 1; color: var(--ink); opacity: .9;
  }
  .prob-card h3 {
    font-family: 'Aime', serif; font-weight: 400;
    font-size: calc(20 * var(--u)); line-height: 1; color: var(--ink);
  }
  .prob-card p {
    font-size: calc(14 * var(--u)); line-height: calc(24.32 * var(--u));
    color: rgba(19, 19, 19, 0.5); margin-top: calc(16 * var(--u));
    transition: color .35s ease;
  }
  /* The copy sits back at rest and comes forward with the card, on the same beat */
  .prob-card:hover p { color: rgba(19, 19, 19, 0.8); }

  /* ============ The fourth option band — Figma 3380:4251 ============
     Sampled off the file's own render rather than guessed. The seals bleed past
     both edges, which is why the band clips. */
  .fourth-band {
    position: relative; overflow: hidden;
    background: #131313; border-radius: calc(4 * var(--u));
    isolation: isolate;
    margin-top: calc(20 * var(--u));
    padding: calc(60 * var(--u)) 0;
    display: flex; flex-direction: column; align-items: center;
    gap: calc(30 * var(--u));
    transition: transform .35s cubic-bezier(.22, 1, .36, 1), box-shadow .35s ease;
  }
  /* The same lift the cards above it take, so the section shares one gesture */
  .fourth-band:hover {
    transform: translateY(calc(-6 * var(--u)));
    box-shadow: 0 0 0 1px rgba(229, 229, 213, 0.22);
  }
  .fourth-band:hover .fb-eyebrow { color: var(--cream); }
  @media (prefers-reduced-motion: reduce) {
    .fourth-band, .fb-deco { transition: none; }
    .fourth-band:hover { transform: none; }
    .fourth-band:hover .fb-deco.is-right { transform: none; }
    .fourth-band:hover .fb-deco.is-left { transform: scaleX(-1); }
    /* the watermark still arrives, it just stops moving to do it — held at full
       size in both states, so there is no scale to snap between */
    .fourth-band::before,
    .fourth-band:hover::before {
      transform: translate(-50%, -50%); transition: opacity .55s ease;
    }
  }
  /* The chevron's point sits at 40.31% of the artwork, not its middle — measured
     off the pixels. 124% is the one height at which the point lands on the band's
     centreline while the artwork still reaches the top edge (0.5 / 0.4031); the
     surplus runs past the foot and the band's overflow crops it. */
  /* The olive ground. There was an ink version beside it for a while; Vero
     chose this one on 2026-08-27 and the other is gone. */
  .fourth-band.boxv2 { background: #34440E; }
  .fourth-band + .fourth-band { margin-top: calc(20 * var(--u)); }

  /* The mark from the heading, blown up as a watermark and revealed on hover.
     It sits at z 0 — above the ground, under the grain — so the noise falls over
     it and it reads as pressed into the material rather than laid on top. The
     chevrons are later siblings at the same level, so they keep the edges.

     .07 is measured, not picked: the artwork averages luma 187 against the
     olive's 57, so at that opacity it lands on 66 — nine units off the ground.
     Enough to find, not enough to compete with the copy over it.

     The box carries the viewBox ratio explicitly because the file is saved with
     preserveAspectRatio="none": given a box of any other shape it would stretch
     to fill it rather than keep the cut of the stone. */
  .fourth-band::before {
    content: ''; position: absolute; z-index: 0; pointer-events: none;
    left: 50%; top: 50%;
    /* Sized off the band rather than off a fixed number, or the 349 it wants at
       full width would span a 350 phone card edge to edge — a shape, not a
       watermark. The cap only bites once the band is narrower than ~635. */
    width: min(calc(349.16 * var(--u)), 55%); aspect-ratio: 36.8336 / 31.6472;
    background: url('/assets/logo-diamond.svg') center / 100% 100% no-repeat;
    opacity: 0; transform: translate(-50%, -50%) scale(.9);
    transition: opacity .55s ease, transform .55s cubic-bezier(.22, 1, .36, 1);
  }
  .fourth-band:hover::before { opacity: .07; transform: translate(-50%, -50%) scale(1); }

  .fourth-band::after {
    content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
    background-image: url('https://images.gvnr.xyz/diamonds/bg-noise.svg');
    background-size: cover; background-position: center;
    opacity: .4;
  }
  .fb-deco {
    position: absolute; top: 0; height: 124.04%; width: auto;
    pointer-events: none; user-select: none;
    /* Grown from the point of the chevron, not from the middle of the artwork —
       any other origin would slide the point off the band's centreline. */
    transform-origin: center 40.31%;
    /* Two legs with their own timing: the hover zoom answers at once, the
       entrance slide is slower and waits for the band to land under it. */
    transition: transform .45s cubic-bezier(.22, 1, .36, 1),
                translate .9s cubic-bezier(.22, 1, .36, 1) .12s;
  }
  .fb-deco.is-left { left: 0; transform: scaleX(-1); }
  .fb-deco.is-right { right: 0; }
  .fourth-band:hover .fb-deco.is-right { transform: scale(1.14); }
  .fourth-band:hover .fb-deco.is-left { transform: scaleX(-1) scale(1.14); }
  .fb-h img { width: calc(24 * var(--u)); height: auto; margin-right: calc(12 * var(--u)); vertical-align: calc(-3 * var(--u)); display: inline-block; }
  .fb-eyebrow {
    position: relative; z-index: 2;
    font-family: 'Bebas Neue', sans-serif; font-size: calc(16 * var(--u));
    line-height: 1; letter-spacing: 0.1em;
    color: rgba(229, 229, 213, 0.8); text-align: center;
    transition: color .35s ease;
  }
  .fb-h {
    position: relative; z-index: 2;
    font-family: 'Aime', serif; font-weight: 400;
    font-size: calc(24 * var(--u)); line-height: 1;
    color: var(--cream); text-align: center;
  }
  .fb-copy {
    position: relative; z-index: 2;
    font-size: calc(15 * var(--u)); line-height: 1.9;
    color: var(--cream); text-align: center;
  }

  /* ============ The choice — Figma 3380:4384 ============
     The header sits on the paper; the products below it are dark panels running
     the full 1320. Same eyebrow / headline / sub scale as the problem section —
     the file uses one type ramp for both. */
  .choice { margin-top: calc(100 * var(--u)); }
  .choice-h {
    font-family: 'Aime', serif; font-weight: 400;
    font-size: calc(40 * var(--u)); line-height: 1;
    color: var(--ink); text-align: center; margin-top: calc(30 * var(--u));
  }
  .choice-sub {
    font-size: calc(14 * var(--u)); line-height: calc(25.6 * var(--u));
    color: #222; text-align: center; margin-top: calc(30 * var(--u));
  }

  /* ---- The dark product panel ---- */
  /* justify-between, so the button sits on the foot of the column whatever the
     list above it does — that is how the file holds the two halves level. */
  .prod-eyebrow {
    font-weight: 600; font-size: calc(11 * var(--u)); line-height: calc(17.6 * var(--u));
    letter-spacing: calc(4.4 * var(--u)); text-transform: uppercase;
    color: rgba(229, 229, 213, 0.55);
  }
  .prod-h {
    font-family: 'Aime', serif; font-weight: 400;
    font-size: calc(28 * var(--u)); line-height: 1.2;
    color: var(--cream); margin-top: calc(16 * var(--u));
  }
  /* Aime ships Regular and Bold only, so the name is set apart by colour
     rather than by weight — both lines sit at 400. */
  .prod-h .accent { display: block; color: var(--lime); }
  /* 34 was set when each step ran to two lines and the item was 51 tall. Now
     that they all fit on one, the item is 27 and that gap was wider than the
     thing it separated. 24 sits just under the 25.6 line height, so the list
     reads as a list rather than as four separate notes. */
  .prod-steps { list-style: none; display: flex; flex-direction: column; gap: calc(24 * var(--u)); }
  .prod-steps li { display: grid; grid-template-columns: calc(30 * var(--u)) auto; align-items: baseline; }
  .prod-steps .n {
    font-family: 'Aime', serif; font-size: calc(14 * var(--u));
    line-height: calc(25.6 * var(--u)); color: rgba(229, 229, 213, 0.5);
  }
  .prod-steps .t {
    font-size: calc(14 * var(--u)); line-height: calc(25.6 * var(--u)); color: var(--cream);
  }
  .prod-cta {
    align-self: flex-start;
    background: var(--lime); color: var(--ink);
    border-radius: calc(4 * var(--u));
    padding: calc(12 * var(--u)) calc(26 * var(--u));
    font-weight: 700; font-size: calc(12 * var(--u)); line-height: calc(20.8 * var(--u));
    letter-spacing: calc(1.04 * var(--u)); text-transform: uppercase; white-space: nowrap;
    transition: background-color .25s ease;
  }
  .prod-cta:hover { background: #c5f470; }

  /* The band that titles each half of the panel */
  /* The two product stories, on their own dark panel above the numbers */
  /* Two boxes now, not one panel with two columns, on the same 1206 every other
     section holds to. */
  /* Hover: a 10% white settles over the card and the footer deco rises from the
     bottom edge. Two background layers on one pseudo-element — the tint listed
     first so it sits over the artwork. */
  /* The card content rides over the grain */

  /* The control that belongs to a product rather than to the deposit — the LTV
     for Borrow, the scenario for Earn. */

  /* ---- The simulator card ---- */
  /* The travelled part of the track is marked by a gradient stop the script
     keeps in step with the value — the native pseudo-elements differ per engine. */
  .sim-slider input[type="range"] {
    -webkit-appearance: none; appearance: none; width: 100%; display: block;
    height: calc(4.243 * var(--u)); outline: none; cursor: pointer;
    background: linear-gradient(to right,
      rgba(229, 229, 213, 0.85) 0 var(--fill, 0%),
      rgba(229, 229, 213, 0.22) var(--fill, 0%) 100%);
  }
  .sim-slider input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none; appearance: none;
    width: calc(13.579 * var(--u)); height: calc(13.579 * var(--u));
    border-radius: 50%; background: var(--lime); cursor: pointer;
  }
  .sim-slider input[type="range"]::-moz-range-thumb {
    width: calc(13.579 * var(--u)); height: calc(13.579 * var(--u));
    border: none; border-radius: 50%; background: var(--lime); cursor: pointer;
  }
  .sim-slider input[type="range"]:focus-visible { outline: 2px solid var(--lime); outline-offset: 4px; }

  /* One block at 60%, which is how the file dims the whole footnote rather than
     each line of it */
  /* One state colour drives both halves of the reading: the ratio wears it and
     the badge is filled with it. Sized by its text, since the labels differ in
     length — a fixed box fitted SAFE and broke on MODERATE. */
  .sim-badge {
    display: inline-flex; align-items: center; justify-content: center;
    padding: calc(5 * var(--u)) calc(7 * var(--u));
    font-family: 'Manrope', sans-serif; font-weight: 700;
    font-size: calc(9 * var(--u)); line-height: 1; letter-spacing: calc(0.5 * var(--u));
    text-transform: uppercase; white-space: nowrap;
    background: var(--state, var(--lime)); color: var(--ink);
    border-radius: calc(4 * var(--u));
  }
  /* In the gap under the label. Its box is pinned to the height it would occupy
     anyway, so the figure below starts exactly where the figures in the
     neighbouring cells do — margins alone left it three quarters of a pixel out,
     since the pill's own height rounds differently at some scales. */
  .sg-cell .sim-badge {
    margin-top: calc(14 * var(--u));
    height: calc(19 * var(--u)); padding-block: 0;
  }
  .sg-cell .sim-badge + .sg-val { margin-top: calc(11 * var(--u)); }
  /* Declared on the cell, not on the figure: the pill sits beside the figure now,
     so a variable set on the figure would never reach it. */
  .sg-cell.is-safe { --state: var(--lime); }
  .sg-cell.is-moderate { --state: #EFC663; }
  .sg-cell.is-risk { --state: #E2705C; }
  .sg-val.is-health { color: var(--state, var(--lime)); }

  /* ---- Carry simulator — Figma 3380:4523 ----
     A different shape from Borrow's: one deposit rather than two sliders, and the
     result cells carry their own border instead of sharing dividers. */
  /* The figure IS the field. A real input keeps the keyboard, the caret and
     the screen-reader label; the styling just takes its chrome away. Width is
     set in ch by the script so it hugs the number and the unit stays close. */
  /* The figure is framed now, which is what makes it read as the one field on
     the panel. The frame lights up on focus instead of an underline. */

  /* ============ Butler — Figma 3389:28 ============
     One centred column now: eyebrow, title, paragraph, then the chat panel. The
     photograph that used to sit beside it is gone from the file. */
  .butler { margin-top: calc(100 * var(--u)); padding: 0 0 calc(60 * var(--u)); }
  .butler-h {
    font-family: 'Aime', serif; font-weight: 400; font-size: calc(40 * var(--u));
    line-height: 1.2; color: var(--ink); text-align: center;
    /* The script word's leading is pinned below its size, so it now overhangs its
       line box by 16 upward. The margin pays that back, landing the visible gap
       on the same 30 every other section shows. Measured, not guessed. */
    margin-top: calc(44 * var(--u));
  }
  /* The one word set in Playground, and twice the size of the line it sits in */
  .butler-h .script {
    font-family: 'PPPlayground', cursive; font-weight: 500;
    font-size: calc(80 * var(--u));
    /* Its own leading, so an 80 glyph does not stretch the 48 line box it sits in.
       Without this the two headline rows step 90 apart instead of 48. */
    line-height: 0.6;
  }
  .butler-lede {
    width: calc(650.891 * var(--u)); margin: calc(30 * var(--u)) auto 0;
    font-size: calc(14 * var(--u)); line-height: calc(25.6 * var(--u));
    color: #222; text-align: center;
  }
  /* The scene is wrapped in an anchor. `display: block` is load-bearing: an
     anchor is inline by default, which would leave .butler-panes' `margin: … auto`
     nothing to centre within. Colour and underline are reset so the link is
     invisible as a link — the scene already reads as something to click. */
  .butler-link { display: block; color: inherit; text-decoration: none; }

  .butler-panes {
    position: relative; overflow: hidden;
    width: calc(1206 * var(--u)); min-height: calc(736 * var(--u));
    margin: calc(40 * var(--u)) auto 0;
    border-radius: calc(4 * var(--u));
    display: flex; justify-content: flex-end; align-items: center;
    /* Was 47, which is what the vertical centring left when the block was 657:
       (657 - 563 column) / 2. The block is 736 now, so the same reasoning gives
       86 — and the panel keeps sitting the same distance from every edge. */
    padding: calc(86 * var(--u));
  }
  /* The photograph is the ground of the whole block */
  .butler-photo {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; display: block;
    pointer-events: none; user-select: none;
    /* Slower than the card it sits in — the frame answers, the scene drifts. */
    transition: transform .8s cubic-bezier(.22, 1, .36, 1);
  }
  /* The block is a photograph, so the move belongs to the picture: the frame
     takes the same rise as the cards above it and the scene pushes in behind
     the chat. The panes already clip, so the growth stays inside the corner
     radius. z-index is untouched — the chat is at 1 and the photograph at 0, and
     a transform does not lift it out of that order. */
  .butler-panes {
    transition: transform .45s cubic-bezier(.22, 1, .36, 1), box-shadow .45s ease;
  }
  .butler-panes:hover {
    transform: translateY(calc(-6 * var(--u)));
    box-shadow: 0 0 0 1px rgba(229, 229, 213, 0.22);
  }
  .butler-panes:hover .butler-photo { transform: scale(1.04); }

  @media (prefers-reduced-motion: reduce) {
    .butler-panes, .butler-photo { transition: none; }
    .butler-panes:hover { transform: none; }
    .butler-panes:hover .butler-photo { transform: none; }
  }

  /* The chat is a column over the photograph: the greeting stands on its own and
     the panel beneath it is frosted rather than filled. */
  .butler-chat {
    position: relative; z-index: 1;
    width: calc(540 * var(--u)); max-width: 100%;
    display: flex; flex-direction: column; gap: calc(40 * var(--u));
  }
  /* A curtain rather than a fade. The sheet is twice the column's height with
     its ramp fixed near the top, so sliding it up carries the opacity edge
     upward through the composition. Percentages are of the layer, hence half
     their value in the column: clear to 9.6, solid by 29.
     Moving a layer is composited; interpolating a gradient is not, which is why
     this reads smooth where a stop animation steps. */
  .butler-chat { overflow: hidden; border-radius: calc(4 * var(--u)); }
  .butler-chat::before {
    content: ''; position: absolute; left: 0; right: 0; top: 0; height: 200%;
    z-index: 0; pointer-events: none;
    background: linear-gradient(to bottom,
      rgba(229, 229, 213, 0) 0%,
      rgba(229, 229, 213, 0) 9.6%,
      rgba(229, 229, 213, 0.9) 29%);
    transform: translateY(0);
    transition: transform .9s cubic-bezier(.4, 0, .2, 1) .25s;
  }
  .butler-chat.in::before { transform: translateY(-29%); }
  /* Down by the gap, and right by the panel's own padding, so it lands on the
     same left edge as the chips and the composer below it. */
  .butler-chat.in .bc-bubble {
    transform: translate(calc(34 * var(--u)), calc(40 * var(--u)));
  }
  .butler-chat > * { position: relative; z-index: 1; }

  /* Straight from the file: cream falling from nothing at the top to 90% at the
     halfway mark, so the scene shows through the head of the panel and the type
     at the foot sits on solid ground. No border — it would draw a line across the
     part that is meant to be invisible. */
  .bc-foot > * { position: relative; z-index: 1; }
  .bc-foot {
    position: relative;
    border-radius: calc(4 * var(--u));
    padding: calc(34 * var(--u));
    /* The transparent half is not empty by accident: it is the window the scene
       shows through, so the panel is given the height to hold it and the content
       is pushed to the solid foot. */
    min-height: calc(455 * var(--u));
    display: flex; flex-direction: column; justify-content: flex-end;
    gap: calc(28 * var(--u));
  }
  /* The greeting stands alone over the photograph */
  /* A speech bubble: square only on the corner nearest the avatar */
  .bc-bubble {
    /* Narrower than the panel and pinned left, as a spoken line rather than a
       band: 468 of the column's 540. */
    width: calc(468 * var(--u)); align-self: flex-start;
    /* On hover it drops by the gap that held it apart, so it comes to rest
       against the panel — inside the box rather than above it. */
    transition: transform .7s cubic-bezier(.4, 0, .2, 1) .35s;
    background: #34440E; border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: calc(8 * var(--u)) calc(8 * var(--u)) calc(8 * var(--u)) 0;
    padding: calc(16 * var(--u));
    font-size: calc(14 * var(--u)); line-height: 1.2;
    color: var(--cream); text-align: center;
  }
  .bc-foot { display: flex; flex-direction: column; gap: calc(24 * var(--u)); }
  .bc-chips { display: flex; flex-wrap: wrap; gap: calc(8 * var(--u)); align-items: center; }
  .bc-chips span {
    height: calc(32 * var(--u)); display: inline-flex; align-items: center;
    padding: calc(4 * var(--u)) calc(13 * var(--u));
    background: rgba(52, 68, 14, 0.1); border-radius: calc(20 * var(--u));
    font-size: calc(12 * var(--u)); color: #34440E; white-space: nowrap;
  }
  .bc-box {
    height: calc(120 * var(--u)); margin: calc(10 * var(--u)) 0;
    background: rgba(255, 255, 255, 0);
    border: 1px solid rgba(65, 65, 65, 0.2); border-radius: calc(4 * var(--u));
    padding: calc(20 * var(--u));
    display: flex; flex-direction: column; align-items: flex-end; justify-content: space-between;
    cursor: text;
    transition: background-color .25s ease, border-color .25s ease;
  }
  .bc-box:hover {
    background: rgba(255, 255, 255, 0.5);
    border-color: rgba(52, 68, 14, 0.45);
  }
  .bc-box:hover p { color: var(--ink); }
  .bc-box p { transition: color .25s ease; }
  .bc-box p { width: 100%; font-size: calc(14 * var(--u)); line-height: 1.2; color: rgba(19, 19, 19, 0.8); }
  .bc-box img { width: calc(40 * var(--u)); height: calc(40 * var(--u)); }

  /* ============ UCD — Figma 3380:4644 ============
     A centred header with the ringed emblem bleeding off the left edge, then the
     comparison table. */
  .ucd {
    /* clip, not hidden. The two paint identically, but hidden makes this section
       a scroll container, and that silently kills position: sticky on anything
       inside it — which the table's header row needs on a handset. Nothing here
       is absolutely positioned, so the clip is guarding nothing either way. */
    position: relative; overflow: clip;
    margin-top: calc(100 * var(--u)); padding: 0 0 calc(60 * var(--u));
  }
  .ucd-inner { position: relative; }
  .ucd-icon { width: calc(26 * var(--u)); height: calc(26 * var(--u)); }
  .ucd-h {
    font-family: 'Aime', serif; font-weight: 400; font-size: calc(40 * var(--u));
    line-height: 1.2; color: var(--ink); text-align: center; margin-top: calc(30 * var(--u));
  }
  /* The word and its mark on one centred row */
  .ucd-h .mark {
    display: flex; align-items: center; justify-content: center;
    gap: calc(12 * var(--u)); font-weight: 700;
  }
  .ucd-sub {
    font-size: calc(14 * var(--u)); line-height: calc(25.6 * var(--u));
    color: #222; text-align: center; margin-top: calc(30 * var(--u));
    max-width: calc(660 * var(--u)); margin-inline: auto;
  }

  /* The table is 698 wide and centred in the 1320 — narrower than everything
     around it, which is what keeps it from reading as a spreadsheet. */
  .ucd-table { width: calc(698 * var(--u)); margin: calc(40 * var(--u)) auto 0; }
  .ucd-row { display: grid; grid-template-columns: calc(200 * var(--u)) calc(258 * var(--u)) calc(240 * var(--u)); }
  .ucd-row + .ucd-row { border-bottom: 1px solid #CACABD; }
  .ucd-row > * { padding: calc(20 * var(--u)) calc(16 * var(--u)); display: flex; align-items: center; }
  .ucd-lab {
    font-weight: 600; font-size: calc(11 * var(--u)); line-height: calc(17.6 * var(--u));
    letter-spacing: calc(2 * var(--u)); text-transform: uppercase; color: #737373;
  }
  .ucd-row.is-head .ucd-lab { color: var(--ink); }
  .ucd-row.is-head .ours { font-weight: 700; color: #34440E; }
  .ucd-row.is-head .theirs { font-weight: 600; color: rgba(19, 19, 19, 0.5); }
  .ucd-row.is-head .ours, .ucd-row.is-head .theirs {
    font-size: calc(11 * var(--u)); line-height: calc(17.6 * var(--u));
    letter-spacing: calc(2 * var(--u)); text-transform: uppercase;
  }
  /* Ours is set in the serif, theirs in the sans — the file uses the type itself
     to say which column is the argument. */
  .ucd-row .ours {
    font-family: 'Aime', serif; font-size: calc(16 * var(--u));
    line-height: calc(17.6 * var(--u)); color: var(--ink);
  }
  .ucd-row .theirs {
    font-size: calc(14 * var(--u)); line-height: calc(17.6 * var(--u));
    color: rgba(19, 19, 19, 0.6);
  }
  /* Hover. The head row is a legend, not a comparison, so it stays out of it.
     Only the label moves with the ground: "ours" is already set in full ink and
     has nowhere to go, and lifting "theirs" would put emphasis on the column the
     table is arguing against. The background-color leg lives in the reveal rule
     further down, which owns this element's `transition` — declared here it
     would be dropped, the same way the card lifts were.
     Note this is background-COLOR, not the shorthand: the rows sit on the paper
     and `background` would replace the sheet showing through them. */
  .ucd-row:not(.is-head):hover { background-color: rgba(79, 71, 24, 0.05); }
  .ucd-lab { transition: color .3s ease; }
  .ucd-row:not(.is-head):hover .ucd-lab { color: #3F3F3F; }

  /* --- The contract, on the record ---
     Of everything this section claims, the address is the one a reader can go
     and check for themselves, so it belongs under the table as its closing
     line rather than filed away in the footer with the housekeeping. Same 698
     measure and same hairline as the table above it, so it reads as that
     table's last row.

     The address is deliberately NOT inside the anchor. Wrapped in a link it
     cannot be selected on a handset without the OS opening a link preview
     instead, and copying it is the thing people come here to do; user-select:
     all turns one tap or click into the whole 42 characters, which is the copy
     button without the script. The link is a separate, smaller target. */
  /* Filled rather than outlined, and Vero's #C3BFA3 rather than the #CACABD the
     border used to draw: on a sheet this light an outline made the row read as a
     form field, and the address is a fact being handed over, not something to
     fill in. The fill carries the type it has to: the ink lands at 10:1 on it and
     the olive of the link at 5.7:1. */
  .ucd-contract {
    width: calc(698 * var(--u));
    margin: calc(24 * var(--u)) auto 0;
    display: flex; align-items: center; gap: calc(20 * var(--u));
    padding: calc(22 * var(--u)) calc(28 * var(--u));
    background: #C3BFA3;
  }
  /* The table's label voice, but at the ink rather than the #737373 it wore on
     the open sheet: against a filled ground that grey came down to 2.6:1. */
  .ucd-contract-lab {
    flex: 0 0 auto;
    font-weight: 600; font-size: calc(11 * var(--u)); line-height: calc(17.6 * var(--u));
    letter-spacing: calc(2 * var(--u)); text-transform: uppercase; color: var(--ink);
  }
  .ucd-contract-addr {
    font-size: calc(13 * var(--u)); line-height: 1.4;
    letter-spacing: calc(0.2 * var(--u)); color: var(--ink);
    user-select: all; -webkit-user-select: all;
    overflow-wrap: anywhere;
  }
  /* The glyph is the affordance for the one thing people come to this row to do,
     so it is a button and not an ornament. user-select: all on the address stays
     as the no-JS path: if the clipboard call is refused, a tap still selects all
     42 characters. The negative margin pulls it out of the 20 gap — it belongs to
     the address it sits beside, not to the space between fields. */
  .ucd-contract-copy {
    flex: 0 0 auto; margin-left: calc(-8 * var(--u));
    display: inline-flex; align-items: center; justify-content: center;
    width: calc(24 * var(--u)); height: calc(24 * var(--u));
    padding: 0; border: 0; background: none; cursor: pointer;
    color: var(--ink); opacity: .7;
    transition: opacity .2s ease;
  }
  .ucd-contract-copy:hover { opacity: 1; }
  .ucd-contract-copy svg {
    display: block; width: calc(16 * var(--u)); height: calc(16 * var(--u));
    fill: none; stroke: currentColor; stroke-width: 1.3;
    stroke-linecap: round; stroke-linejoin: round;
  }
  /* Two glyphs in the same box, one shown at a time, so confirming the copy costs
     no layout: the check is drawn on the same 16 grid the clipboard is. */
  .ucd-contract-copy .tick { display: none; }
  .ucd-contract-copy.is-copied { opacity: 1; color: #34440E; }
  .ucd-contract-copy.is-copied .clip { display: none; }
  .ucd-contract-copy.is-copied .tick { display: block; }
  /* Sentence case and the address's own size. In caps with 2 of tracking it read
     as a third label in a row that already has one; as a sentence it reads as the
     link it is. */
  .ucd-contract-go {
    margin-left: auto; flex: 0 0 auto;
    font-weight: 600; font-size: calc(13 * var(--u)); line-height: calc(17.6 * var(--u));
    color: #34440E; text-decoration: none; white-space: nowrap;
    border-bottom: 1px solid rgba(52, 68, 14, 0.35);
    transition: border-color .3s ease;
  }
  .ucd-contract-go:hover { border-bottom-color: #34440E; }
  /* The line under the contract row — where to go to read the rest. Centred on
     the table's own 698 rather than on the sheet, so it hangs off the row above
     it instead of floating in the middle of the section. */
  .ucd-docs {
    width: calc(698 * var(--u)); margin: calc(20 * var(--u)) auto 0;
    text-align: center;
    font-size: calc(13 * var(--u)); line-height: calc(17.6 * var(--u));
    color: rgba(19, 19, 19, 0.6);
  }
  .ucd-docs a {
    color: #34440E; text-decoration: none;
    border-bottom: 1px solid rgba(52, 68, 14, 0.35);
    transition: border-color .3s ease;
  }
  .ucd-docs a:hover { border-bottom-color: #34440E; }


  /* ============ Security — Figma 3380:4708 ============
     The Governor seal bleeds off the right here, mirroring UCD's on the left. */
  .security {
    position: relative; overflow: hidden;
    margin-top: calc(100 * var(--u)); padding: 0 0 calc(60 * var(--u));
  }
  .sec-inner { position: relative; }
  .sec-h {
    font-family: 'Aime', serif; font-weight: 400; font-size: calc(40 * var(--u));
    line-height: 1.2; color: var(--ink); text-align: center; margin-top: calc(30 * var(--u));
  }
  .sec-sub {
    font-size: calc(14 * var(--u)); line-height: calc(25.6 * var(--u));
    color: #222; text-align: center; margin-top: calc(30 * var(--u));
  }
  .sec-cards {
    width: calc(1206 * var(--u)); margin: calc(40 * var(--u)) auto 0;
    display: grid; grid-template-columns: repeat(3, 1fr); gap: calc(20 * var(--u));
  }
  .sec-card {
    position: relative; overflow: hidden; isolation: isolate;
    background: #34440E; border-radius: calc(4 * var(--u));
    /* 60 vertical, up from 40: the content is only 158 tall (72 icon + 36 gap +
       50 of copy), so at the old inset the card sat at a 1.63 ratio and read
       flat next to its neighbours. 60 is the same large inset the product
       blocks and the band already use, and it brings the card to 1.40. */
    padding: calc(60 * var(--u)) calc(30 * var(--u));
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: calc(36 * var(--u));
  }
  /* The same grain the dark bands carry, so the green reads as the same material */
  .sec-card::after {
    content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
    background-image: url('https://images.gvnr.xyz/diamonds/bg-noise.svg');
    background-size: cover; background-position: center;
    opacity: .4;
  }
  /* Hover: the footer deco rides up from below the card and fades in */
  .sec-card::before {
    content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
    opacity: 0;
    background-image: url('/assets/security-hover-deco.svg');
    background-repeat: no-repeat;
    background-size: 100% auto;
    background-position: center calc(100% + 60 * var(--u));
    transition: opacity .45s ease,
                background-position .6s cubic-bezier(.22, 1, .36, 1);
  }
  .sec-card:hover::before { opacity: 1; background-position: center bottom; }
  /* The icon and the line ride over both layers */
  .sec-card > * { position: relative; z-index: 2; }
  .sec-card img {
    height: calc(72 * var(--u)); width: auto;
    transition: transform .45s cubic-bezier(.22, 1, .36, 1);
  }
  /* Scale, not a size change: it costs no layout, so the line below never shifts */
  .sec-card:hover img { transform: scale(1.08); }
  /* The same rise and stroke the other cards take. The ground here is the same
     #34440E as the band and Earn, so it takes their alpha and lands on the same
     37.4 luma the rest of the dark cards do. The transition legs are already
     declared in the reveal rule that owns this element's `transition`. */
  .sec-card:hover {
    transform: translateY(calc(-6 * var(--u)));
    box-shadow: 0 0 0 1px rgba(229, 229, 213, 0.22);
  }
  @media (prefers-reduced-motion: reduce) {
    .sec-card:hover { transform: none; }
    .sec-card:hover img { transform: none; }
  }
  .sec-card h3 {
    font-family: 'Aime', serif; font-weight: 400;
    font-size: calc(18 * var(--u)); line-height: 1.4; text-align: center;
    /* Aime has no weight below Regular, and light type on a dark ground blooms.
       Pulling the cream back thins the strokes optically instead. */
    color: rgba(229, 229, 213, 0.82);
  }
  .sec-cta {
    display: block; width: max-content; margin: calc(40 * var(--u)) auto 0;
    /* Secondary: the outlined treatment the product CTAs wear at rest. */
    background: transparent; color: var(--ink);
    box-shadow: inset 0 0 0 calc(1 * var(--u)) rgba(19, 19, 19, 0.35);
    border-radius: calc(4 * var(--u));
    padding: calc(13 * var(--u)) calc(26 * var(--u));
    font-weight: 600; font-size: calc(13 * var(--u)); line-height: calc(20.8 * var(--u));
    letter-spacing: calc(1.04 * var(--u)); text-transform: uppercase; white-space: nowrap;
    transition: background-color .3s ease, color .3s ease, box-shadow .3s ease;
  }
  .sec-cta:hover {
    background: var(--lime); color: var(--ink);
    box-shadow: inset 0 0 0 calc(1 * var(--u)) transparent;
  }

  /* ============ FAQ — Figma 3385:279 ============
     A narrow centred header over a wide list. The list is 856 in a 1320 column,
     so it is inset rather than full width. */
  .faq { margin-top: calc(100 * var(--u)); padding: 0 0 calc(80 * var(--u)); }
  .faq-head { width: calc(411 * var(--u)); margin: 0 auto; text-align: center; }
  .faq-h {
    font-family: 'Aime', serif; font-weight: 400; font-size: calc(40 * var(--u));
    line-height: 1; color: var(--ink); margin-top: calc(30 * var(--u));
  }
  .faq-sub {
    font-size: calc(14 * var(--u)); line-height: calc(25.6 * var(--u));
    color: #222; margin-top: calc(30 * var(--u));
  }
  .faq-list { width: calc(700 * var(--u)); margin: calc(40 * var(--u)) auto 0; }
  .faq-row {
    display: flex; align-items: center; justify-content: space-between;
    padding: calc(20 * var(--u)) 0;
    border-bottom: 1px solid #CACABD;
    width: 100%; background: none; border-left: 0; border-right: 0; border-top: 0;
    text-align: left; cursor: pointer; font: inherit; color: inherit;
  }
  .faq-q { display: flex; align-items: center; gap: calc(10 * var(--u)); width: calc(560 * var(--u)); }
  .faq-n {
    width: calc(40 * var(--u)); height: calc(40 * var(--u));
    display: flex; align-items: center; justify-content: center;
    font-family: 'Aime', serif; font-size: calc(16 * var(--u)); line-height: 1.2;
    color: rgba(79, 71, 24, 0.5);
  }
  .faq-t {
    font-family: 'Aime', serif; font-weight: 400;
    font-size: calc(16 * var(--u)); line-height: calc(17.6 * var(--u)); color: var(--ink);
  }
  /* .35, not the .45 the other zooms take: this transform is doing two jobs —
     the hover zoom and the open/close rotate — and .35 is what the answer panel
     below it runs at, so the chevron turns WITH the panel instead of trailing
     it. It is also the duration the card lifts use, so it is no outlier. */
  .faq-row img {
    width: calc(16 * var(--u)); height: calc(16 * var(--u));
    transition: transform .35s cubic-bezier(.22, 1, .36, 1);
  }
  .faq-row[aria-expanded="true"] img { transform: rotate(180deg); }

  /* ---- Hover ----
     The question is already set in full ink, so there is nothing to darken
     there. What has room to move is everything around it: the number, which
     sits at half strength; the rule, which is the row's only edge; and the
     chevron, which gets the same small zoom the band's chevrons take. The
     question itself steps right, so the row reads as picked up rather than
     merely tinted. */
  .faq-row { transition: border-color .3s ease; }
  .faq-q { transition: transform .35s cubic-bezier(.22, 1, .36, 1); }
  .faq-n { transition: color .3s ease; }

  .faq-row:hover { border-bottom-color: rgba(79, 71, 24, 0.4); }
  .faq-row:hover .faq-q { transform: translateX(calc(6 * var(--u))); }
  .faq-row:hover .faq-n { color: rgba(79, 71, 24, 0.9); }
  /* Written after the rotate rule, which it ties with on specificity, and the
     open row restates the rotate so the two compose instead of cancelling. */
  .faq-row:hover img { transform: scale(1.12); }
  .faq-row[aria-expanded="true"]:hover img { transform: rotate(180deg) scale(1.12); }
  /* an open row keeps its emphasis without being hovered */
  .faq-row[aria-expanded="true"] .faq-n { color: rgba(79, 71, 24, 0.9); }

  @media (prefers-reduced-motion: reduce) {
    /* .faq-a carries the max-height transition that the script drives when a row
       opens, so leaving it out meant the panel still slid open under reduced
       motion — the one movement a reader actually triggers on this section. The
       row still opens, it just arrives instead of animating. */
    .faq-q, .faq-n, .faq-row, .faq-a { transition: none; }
    .faq-row:hover .faq-q { transform: none; }
    .faq-row:hover img { transform: none; }
    .faq-row[aria-expanded="true"]:hover img { transform: rotate(180deg); }
  }
  /* Collapsed by height rather than display, so the row can animate open and the
     answer stays in the document for search and for the keyboard. */
  .faq-a {
    overflow: hidden; max-height: 0;
    transition: max-height .35s cubic-bezier(.4, 0, .2, 1);
  }
  .faq-a > p {
    width: calc(560 * var(--u)); margin-left: calc(50 * var(--u));
    padding: calc(16 * var(--u)) 0 calc(24 * var(--u));
    font-size: calc(14 * var(--u)); line-height: calc(25.6 * var(--u)); color: #222;
  }
  .faq-still {
    width: calc(700 * var(--u)); margin: calc(40 * var(--u)) auto 0;
    text-align: center;
  }
  .faq-still h3 {
    font-family: 'Aime', serif; font-weight: 400; font-size: calc(20 * var(--u));
    line-height: 1.24; color: var(--ink);
  }
  .faq-still p {
    font-size: calc(14 * var(--u)); line-height: calc(25 * var(--u));
    color: #222; margin-top: calc(16 * var(--u));
  }
  /* The concierge line. A sentence with a link in it rather than a third button:
     the pair above is one decision with two answers — ask the Butler or contact
     us — and a large-loan enquiry is a different kind of thing, addressed to the
     few people it applies to. As a button it would have argued with the two that
     were just set to one measure; as a line under them it qualifies its own
     reader and lets everyone else pass.
     The selector carries .faq-still because .faq-still p already sets a size, a
     colour and a margin for the lede above, and one class alone would lose to it.
     "Book an appointment" is the link rather than the whole sentence — it is the
     part that says what happens next. */
  .faq-still .faq-concierge {
    margin-top: calc(36 * var(--u));
    font-size: calc(13 * var(--u)); line-height: calc(22 * var(--u));
    color: rgba(19, 19, 19, 0.7);
  }
  .faq-still .faq-concierge a {
    color: #34440E; text-decoration: none;
    border-bottom: 1px solid rgba(52, 68, 14, 0.35);
    transition: border-color .3s ease;
  }
  .faq-still .faq-concierge a:hover { border-bottom-color: #34440E; }

  /* Same row the closing section uses for its own pair of buttons. */
  .faq-ctas {
    display: flex; gap: calc(14 * var(--u)); justify-content: center; flex-wrap: wrap;
    margin-top: calc(36 * var(--u));
  }
  /* The outlined button is normally a centred block of its own; inside a row it
     just takes its place. */
  .faq-ctas .sec-cta { margin: 0; }
  /* --- The page's two CTA pairs are one component, declared once ---
     Four buttons across two sections, and every measure they can share is set
     here: the corner, the padding, the type and the tracking. The corner is the
     reason the rule started existing — .btn carries the 2 of the older button,
     and beside the outlined 4 that read as a slip rather than a choice.
     The padding and the type are pinned for a second reason. Below 640 the bare
     .btn steps down to 11/14, and that step belongs to the NAV — the one place a
     button has to fit beside the lockup on a 375 screen. Neither of these pairs
     is in the bar, and inheriting it split them apart: the FAQ pair mixes a .btn
     with a .sec-cta, which has no such step, so "Ask the Butler" came out a size
     under the "Contact Us" beside it; and the two pairs then spoke in different
     sizes from one another. Specificity carries it — a two-class selector outranks
     a bare .btn at any width — so no second media query has to undo the first. */
  .faq-ctas .btn, .closure-ctas .btn {
    border-radius: calc(4 * var(--u));
    padding: calc(13 * var(--u)) calc(26 * var(--u));
    font-size: calc(13 * var(--u)); letter-spacing: calc(1.04 * var(--u));
  }
  /* The FAQ's primary goes to the ink at every width — the selector names only
     this pair's .btn, so the closing band's lime one is untouched. It sits on the
     cream sheet rather than on a dark band, where a lime slab was the loudest
     thing in a section whose job is to answer questions quietly.
     The label has to move with the ground: .btn carries #000, which on #131313 is
     1.1:1 — invisible. The cream lands at 14.6:1.
     And the hover has to be restated here. .btn:hover is a class plus a
     pseudo-class, exactly the weight of .faq-ctas .btn, and this rule comes later
     in the sheet — so the lime hover would lose to the background above and the
     button would sit inert under the cursor. #262626 is the same size of step the
     lime one takes, in the direction this ground can go. */
  .faq-ctas .btn { background: var(--ink); color: var(--cream); }
  .faq-ctas .btn:hover { background: #262626; }

  /* ============ CLOSING ============
     A full-height photographic band that closes the paper. It sits outside the
     sheet, so it is the one place the texture stops. */
  .closure {
    position: relative; min-height: 100vh; box-sizing: border-box;
    background-color: #1a1712;
    background-image: url('/assets/bg-closure-yacht.webp');
    background-size: cover; background-position: center;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    padding: calc(120 * var(--u)) calc(40 * var(--u));
    text-align: center;
  }
  .closure-diamond { width: calc(48 * var(--u)); height: auto; display: block; }
  .closure h2 {
    font-family: 'Aime', serif; font-weight: 400;
    font-size: calc(56 * var(--u)); line-height: 1.1;
    color: var(--cream); margin-top: calc(30 * var(--u));
  }
  .closure-sub {
    font-family: 'Bebas Neue', sans-serif; font-size: calc(19 * var(--u));
    letter-spacing: calc(3 * var(--u)); text-transform: uppercase;
    color: #D9D9CF; margin-top: calc(22 * var(--u));
  }
  .closure-ctas {
    display: flex; gap: calc(14 * var(--u)); justify-content: center; flex-wrap: wrap;
    margin-top: calc(36 * var(--u));
  }
  /* Outlined with an inset shadow rather than a border — the same way the FAQ's
     own outlined button draws its ring. A border is a box: it put the ghost at
     48.8 against the lime one's 46.8, and a shadow costs no layout at all, so the
     two are the same size without either one being padded to match. It is also
     what lets all four buttons on the page share one height. */
  .closure-ctas .btn.is-ghost {
    background: transparent; color: var(--cream);
    box-shadow: inset 0 0 0 calc(1 * var(--u)) rgba(236, 236, 229, 0.4);
  }
  .closure-ctas .btn.is-ghost:hover { background: rgba(255, 255, 255, 0.08); }
  .signoff { position: relative; margin-top: calc(64 * var(--u)); display: flex; justify-content: center; }
  .signoff-gif { width: min(calc(420 * var(--u)), 70vw); height: auto; pointer-events: none; user-select: none; }
  /* The seal drops onto the signature once it is written */
  .signoff-stamp {
    position: absolute; right: calc(-34 * var(--u)); top: 50%;
    width: calc(112 * var(--u)); height: calc(112 * var(--u));
    opacity: 0; transform: translateY(-50%) rotate(10deg) scale(1.6);
    pointer-events: none; user-select: none;
  }
  .signoff-stamp.is-stamped {
    opacity: 1; transform: translateY(-50%) rotate(10deg) scale(1);
    transition: opacity .18s ease-out, transform .28s cubic-bezier(.34, 1.56, .64, 1);
  }

  /* ============ FOOTER ============ */
  /* The page's own ink, not a photograph. This was the one dark block wearing a
     file of its own — a near-flat #1a1a1a with the grain baked into the JPG — and
     `cover` on a 1920-wide image is what undid it: on a handset the crop lands
     inside a homogeneous patch and the texture flattens to a plain field, so the
     footer stopped matching the bands it sits under. Ground and grain are now the
     same two things every other dark block uses, which hold at any width and cost
     44KB less. (The file went with the cleanup; it is not in assets/ any more.) */
  .site-footer {
    position: relative;
    border-top: 1px solid rgba(229, 229, 213, 0.12);
    background: #131313;
    color: var(--cream);
  }
  /* The same grain the dark bands carry, at the same .4 */
  .site-footer::after {
    content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
    background-image: url('https://images.gvnr.xyz/diamonds/bg-noise.svg');
    background-size: cover; background-position: center;
    opacity: .4;
  }
  /* the footer content rides over the grain */
  .footer-inner, .footer-legal { position: relative; z-index: 2; }
  .footer-inner {
    padding: calc(40 * var(--u)) calc(80 * var(--u)) calc(28 * var(--u));
    display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: calc(40 * var(--u));
  }
  .footer-brand { display: flex; flex-direction: column; gap: calc(14 * var(--u)); }
  /* Driven by width, not height — the same reason as the handset rule below: a
     fixed height plus max-width is what squeezes the lockup out of proportion
     when the column is narrower than the height asks for.
     Worth knowing about this file: it declares 272 wide but its drawing stops at
     227.7, so roughly 16% of the box is empty on the right. A 220 element shows
     about 184 of actual mark. */
  .footer-logo { width: calc(220 * var(--u)); height: auto; display: block; align-self: flex-start; }
  /* The <picture> is not a box: display: contents keeps the img itself as the
     flex item of .footer-brand, so every rule here and in the handset tier goes
     on addressing .footer-logo directly. */
  .footer-brand picture { display: contents; }
  /* Part of the same deal, and it is silent: <source> has no UA display: none of
     its own — nothing renders it only because <picture> normally owns it. Hand
     the flex container its children directly and the source becomes a flex item
     like any other: a zero-sized one, which still collected a full 14 of gap
     above the mark. */
  .footer-brand picture source { display: none; }
  .footer-powered { display: flex; align-items: center; gap: calc(10 * var(--u)); margin-top: calc(16 * var(--u)); }
  .footer-powered span { font-size: calc(11 * var(--u)); color: rgba(229, 229, 213, 0.5); }
  .footer-powered img { height: calc(24 * var(--u)); width: auto; }
  .footer-col h4 {
    font-size: calc(12 * var(--u)); letter-spacing: calc(2.4 * var(--u));
    text-transform: uppercase; color: rgba(229, 229, 213, 0.4);
    margin-bottom: calc(16 * var(--u));
  }
  .footer-col a {
    display: block; color: rgba(229, 229, 213, 0.7); font-size: calc(12 * var(--u));
    line-height: 2; text-decoration: none; transition: color .15s ease;
  }
  .footer-col a:hover { color: var(--cream); }
  /* One row: the disclaimer runs from the left, the copyright sits against the
     right. They were two stacked blocks, so the copyright fell onto its own line
     at the left margin. The sentence measures 1212 unbroken against 1745 of
     room, so the pair fits on a single line with plenty to spare.
     Baseline, not centre: the two are different lengths and it is the type that
     has to line up, not the boxes. */
  .footer-legal {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: calc(40 * var(--u));
    padding: 0 calc(80 * var(--u)) calc(36 * var(--u));
    color: rgba(229, 229, 213, 0.4); font-size: calc(12 * var(--u)); line-height: 1.7;
  }
  /* a date and a company name — it never breaks */
  .footer-legal .copyright { white-space: nowrap; }

  /* ============ PRODUCT BLOCKS ============
     One green panel per product: the story on the left, its own simulator on the
     right. Both blocks share every rule — only their contents differ. */
  /* The ground is the only thing the two blocks do not share */
  #block-borrow { background: #131313; }

  .prod-block {
    position: relative; overflow: hidden; isolation: isolate;
    /* 1206 is the page's shared measure, and this block is what set it. The
       longest step — "Mints at 50% LTV — 5% Carry fee: 3% mint, 2% commitment" —
       measures 380 set on one line, and with the number's 30 the story column
       needs 410. It had 300, which is why all eight ran to two lines. The column
       went to 430, every one of them now sets on a single line with room to
       spare (20 at the tightest), and the simulator keeps the 608 it was
       calibrated at: 1206 - 120 padding - 430 - 48 gap. The rest of the page
       followed this width so the sections keep a common edge. */
    width: calc(1206 * var(--u)); margin: calc(40 * var(--u)) auto 0;
    background: #34440E; border-radius: calc(4 * var(--u));
    padding: calc(60 * var(--u));
    display: grid; grid-template-columns: calc(430 * var(--u)) 1fr;
    column-gap: calc(48 * var(--u)); align-items: stretch;
    transition: transform .35s cubic-bezier(.22, 1, .36, 1), box-shadow .35s ease;
  }
  /* The same rise the option cards and the olive band take, at the band's weight
     rather than the small cards' — this is furniture of the same size. */
  /* The alpha is a token because the two blocks sit on different grounds: at a
     flat .22 the cream line stands 45.8 luma off borrow's near-black and only
     37.4 off earn's olive, so the same stroke would read heavier on one card
     than the other. .18 on the dark one brings both to the same 37.4. */
  .prod-block:hover {
    transform: translateY(calc(-6 * var(--u)));
    box-shadow: 0 0 0 1px rgba(229, 229, 213, var(--stroke-a, 0.22));
  }
  .prod-block::after {
    content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
    background-image: url('https://images.gvnr.xyz/diamonds/bg-noise.svg');
    background-size: cover; background-position: center; opacity: .4;
  }
  /* At the size it was drawn (528 wide), anchored in the foot corner. Stretched
     to the block width the chevrons read as a repeating pattern, not a mark. */
  .pb-deco {
    position: absolute; left: 0; bottom: 0;
    width: calc(528 * var(--u)); height: auto;
    z-index: 0; pointer-events: none; user-select: none;
    /* Grown from the corner it is anchored in, not from its middle: any other
       origin would pull it off the card's edge and open a strip of bare ground
       behind it, which the card's overflow would then show. */
    transform-origin: left bottom;
    transition: transform .45s cubic-bezier(.22, 1, .36, 1);
  }
  .prod-block:hover .pb-deco { transform: scale(1.05); }

  @media (prefers-reduced-motion: reduce) {
    .prod-block, .pb-deco { transition: none; }
    .prod-block:hover { transform: none; }
    .prod-block:hover .pb-deco { transform: none; }
  }
  .pb-story, .pb-sim { position: relative; z-index: 2; }
  /* Stacked from the top with a fixed 60 between the three groups, not spread
     across the column. The simulator beside it sets the row height, and
     space-between was handing all that surplus to two gaps — they were running
     212 each, which is what left the middle of the card empty. */
  .pb-story {
    display: flex; flex-direction: column;
    justify-content: flex-start; gap: calc(60 * var(--u));
  }

  /* ---- the simulator ---- */
  .pb-sim {
    border: 1px solid rgba(229, 229, 213, 0.18);
    border-radius: calc(4 * var(--u));
    background: rgba(0, 0, 0, 0.12);
  }
  .sim-head {
    font-family: 'Aime', serif; font-size: calc(15 * var(--u)); line-height: 1.2;
    color: var(--cream); text-align: center;
    padding: calc(22 * var(--u));
    border-bottom: 1px solid rgba(229, 229, 213, 0.18);
  }
  .sim-ctrls {
    /* Stacked, not side by side: each control gets the full measure, so its
       track is long enough to set a value with any precision. */
    display: flex; flex-direction: column; gap: calc(40 * var(--u));
    padding: calc(34 * var(--u)) calc(32 * var(--u)) calc(40 * var(--u));
    border-bottom: 1px solid rgba(229, 229, 213, 0.18);
  }
  .sc-top {
    display: flex; align-items: center; justify-content: space-between;
    gap: calc(10 * var(--u)); margin-bottom: calc(22 * var(--u));
  }
  .sc-name { font-size: calc(12 * var(--u)); color: rgba(229, 229, 213, 0.75); }
  .sc-chip {
    display: inline-flex; align-items: baseline; gap: calc(4 * var(--u));
    border: 1px solid rgba(229, 229, 213, 0.25); border-radius: calc(4 * var(--u));
    padding: calc(5 * var(--u)) calc(10 * var(--u));
  }
  .sc-chip .val {
    font-family: 'Manrope', sans-serif; font-weight: 700; font-size: calc(13 * var(--u));
    color: var(--cream);
    background: none; border: none; outline: none; padding: 0; margin: 0;
    text-align: right; cursor: text; min-width: 1ch;
  }
  .sc-chip:focus-within { border-color: var(--lime); }
  .sc-chip .u { font-size: calc(9 * var(--u)); color: rgba(229, 229, 213, 0.6); }
  .sc-scale {
    display: flex; justify-content: space-between; margin-top: calc(8 * var(--u));
    font-size: calc(10 * var(--u)); color: rgba(229, 229, 213, 0.5);
  }
  /* A caption on the control, not a reading of it: it says what the number the
     slider sets actually is. Sits a step above the scale it follows — the scale
     is furniture, this is the sentence that stops the deposit being mistaken for
     something else. */
  .sc-hint {
    margin-top: calc(14 * var(--u));
    font-size: calc(11 * var(--u)); line-height: 1.45;
    color: rgba(229, 229, 213, 0.6);
  }

  /* ---- the results: three across, twice ---- */
  /* ---- Sectors ----
     The panel reads as one long table, so the eye has no way to tell where the
     controls end and the results begin. Hovering a sector washes its ground and
     draws the group. The wash sits UNDER the content rather than over it: laid
     on top it would dim the figures too, which reads as disabled rather than as
     grouped. Under them, the ground darkens and the cream type actually gains
     contrast.

     The colour is a per-card token because black only works on one of the two
     grounds. Measured: the olive panel renders #2E3C0C, and 12% black takes it
     to #28350B — a step you can see. The borrow panel renders #111111, where 18%
     black moves it two points, to #0E0E0E. Nothing to see. So that one takes a
     little white instead, which is the same gesture in the only direction its
     ground has left. */
  /* Its own stacking context, so the wash and the content settle their order
     INSIDE the sector. Without it the lifted children would also out-rank the
     card's corner deco, which sits at z 0 and overlaps the panel — the sector
     would have quietly reordered artwork it has nothing to do with. */
  .sim-sector { position: relative; isolation: isolate; }
  .sim-sector::after {
    content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
    background: var(--sector-wash, #000);
    opacity: 0; transition: opacity .28s ease;
  }
  .sim-sector:hover::after { opacity: var(--sector-wash-o, 0.12); }
  /* lifted over the wash, so only the ground takes it */
  .sim-sector > * { position: relative; z-index: 1; }
  #block-borrow { --sector-wash: #fff; --sector-wash-o: 0.05; --stroke-a: 0.18; }

  .sim-grid { display: grid; grid-template-columns: repeat(3, 1fr); }
  .sg-cell {
    padding: calc(30 * var(--u)) calc(26 * var(--u)) calc(34 * var(--u));
    border-left: 1px solid rgba(229, 229, 213, 0.18);
  }
  .sg-cell:nth-child(3n + 1) { border-left: 0; }
  .sg-cell.is-small { padding-block: calc(26 * var(--u)); }
  .sg-lab {
    font-size: calc(11 * var(--u)); line-height: 1.3;
    color: rgba(229, 229, 213, 0.55);
  }
  .sg-cell.is-small .sg-lab {
    font-weight: 600; font-size: calc(9 * var(--u));
    letter-spacing: calc(0.9 * var(--u)); text-transform: uppercase;
  }
  .sg-val {
    font-family: 'Aime', serif; font-size: calc(24 * var(--u)); line-height: 1.1;
    color: var(--cream); margin-top: calc(44 * var(--u));
    display: flex; align-items: baseline; gap: calc(7 * var(--u)); flex-wrap: wrap;
  }
  .sg-val .unit { font-size: calc(11 * var(--u)); color: rgba(229, 229, 213, 0.6); }
  .sg-note {
    font-size: calc(11 * var(--u)); line-height: 1.35;
    color: rgba(229, 229, 213, 0.55); margin-top: calc(10 * var(--u));
  }
  .case-tag {
    font-size: calc(11 * var(--u)); color: rgba(229, 229, 213, 0.55); white-space: nowrap;
  }
  .sg-sub {
    font-weight: 600; font-size: calc(14 * var(--u));
    color: var(--cream); margin-top: calc(12 * var(--u));
  }

  /* ---- Earn's simulator: controls split in two, then results, then the
     protocol's own row under its own band ---- */
  /* The two choosers share a row; the deposit takes the full measure beneath
     them, so its track is as long as the panel allows. */
  .sim-ctrls-e {
    padding: calc(32 * var(--u)) calc(30 * var(--u)) calc(36 * var(--u));
    border-bottom: 1px solid rgba(229, 229, 213, 0.18);
  }
  .ce-row { display: grid; grid-template-columns: 1fr 1fr; gap: calc(30 * var(--u)); }
  .ce-deposit { margin-top: calc(36 * var(--u)); }
  .ss-lab {
    font-size: calc(12 * var(--u)); color: rgba(229, 229, 213, 0.75);
    margin-bottom: calc(12 * var(--u));
  }
  .ce-group .case-tag { display: block; margin-top: calc(12 * var(--u)); }

  /* the two-button choosers: the live one filled, the other outlined */
  .asset-pick { display: flex; gap: calc(10 * var(--u)); }
  .asset-pick button {
    flex: 1 0 0;
    font-family: 'Manrope', sans-serif; font-weight: 700; font-size: calc(11 * var(--u));
    letter-spacing: calc(0.6 * var(--u)); text-transform: uppercase;
    padding: calc(10 * var(--u)) calc(8 * var(--u));
    border-radius: calc(4 * var(--u)); cursor: pointer;
    background: transparent; color: rgba(229, 229, 213, 0.7);
    border: 1px solid rgba(229, 229, 213, 0.3);
    transition: background-color .2s ease, color .2s ease, border-color .2s ease;
  }
  .asset-pick button[aria-pressed="true"] {
    background: var(--lime); color: var(--ink); border-color: var(--lime);
  }

  /* Which of the two sides of the carry you are reading. It changes with the
     asset, because holding BTC and providing USDC are not the same position. */
  .sim-party {
    font-family: 'Aime', serif; font-size: calc(15 * var(--u)); line-height: 1.2;
    color: var(--cream); text-align: center;
    padding: calc(20 * var(--u));
    border-bottom: 1px solid rgba(229, 229, 213, 0.18);
  }
  /* Two across, twice. The lead row carries the figure; the row beneath it turns
     the pair round — caption first, then a smaller number — so the second row
     reads as a footnote to the first rather than competing with it. Only the
     vertical rule divides; it runs unbroken down both rows. */
  .sim-grid.is-flat { grid-template-columns: 1fr 1fr; }
  .sim-grid.is-flat .sg-cell { border-left: 1px solid rgba(229, 229, 213, 0.18); }
  .sim-grid.is-flat .sg-cell:nth-child(odd) { border-left: 0; }
  .sim-grid.is-flat .sg-cell.is-small { padding-top: calc(6 * var(--u)); }
  /* value first, its name underneath */
  .sg-cell.is-lead .sg-val { margin-top: 0; }
  .sg-cell.is-lead .sg-note { margin-top: calc(10 * var(--u)); }

  .sim-band {
    font-family: 'Aime', serif; font-size: calc(15 * var(--u)); line-height: 1.2;
    color: var(--cream); text-align: center;
    padding: calc(20 * var(--u));
    border-top: 1px solid rgba(229, 229, 213, 0.18);
    border-bottom: 1px solid rgba(229, 229, 213, 0.18);
  }
  .proto-row { display: grid; grid-template-columns: repeat(4, 1fr); }
  .pr-cell {
    padding: calc(24 * var(--u)) calc(12 * var(--u)) calc(30 * var(--u));
    border-left: 1px solid rgba(229, 229, 213, 0.18);
  }
  .pr-cell:first-child { border-left: 0; }
  /* The four cells are 136 wide; at 9 with 0.9 of tracking the longest line
     (FURNACE BUYS & BURNS) needed 123 of the 100 on offer and broke into three
     and four lines. Smaller and tighter it sets in two, which is what makes the
     box read as calm rather than crowded. */
  .pr-cell .sg-lab {
    font-weight: 600; font-size: calc(10 * var(--u));
    letter-spacing: calc(0.4 * var(--u)); text-transform: uppercase;
    line-height: 1.5;
  }
  .pr-cell .sg-val { font-size: calc(20 * var(--u)); margin-top: calc(22 * var(--u)); }

  /* ==================================================================
     SCROLL REVEALS
     Read off squidrouter.com: short travel (24 to 32, never more), only
     opacity and a move, and a stagger that reads as one thing settling
     rather than a queue of things flying in.

     Written with `translate`, the standalone property — NOT `transform`.
     Nearly every element here already has a hover, and every one of those
     hovers is a `transform`. The two properties compose instead of
     overriding, so a card can be lifting under the cursor while it is
     still arriving and neither has to win a specificity fight.

     The curve stays ours: cubic-bezier(.22, 1, .36, 1) is a harder
     ease-out than the one Squid uses, and it is already the page's.
     ================================================================== */

  /* Section headers: the eyebrow and the line under it rise 32. The heading
     itself does not — it flips in word by word, below. */
  .prob-eyebrow, .closure-diamond,
  .prob-sub, .choice-sub, .butler-lede, .ucd-sub, .sec-sub, .faq-sub,
  .closure-sub, .closure-ctas {
    opacity: 0; translate: 0 calc(32 * var(--u));
    transition: opacity .7s ease, translate .7s cubic-bezier(.22, 1, .36, 1);
  }
  section.head-in :is(.prob-eyebrow, .closure-diamond),
  section.head-in :is(.prob-sub, .choice-sub, .butler-lede, .ucd-sub, .sec-sub,
                      .faq-sub, .closure-sub, .closure-ctas) {
    opacity: 1; translate: none;
  }
  section.head-in :is(.prob-sub, .choice-sub, .butler-lede, .ucd-sub, .sec-sub, .faq-sub, .closure-sub) { transition-delay: .24s; }
  /* the two buttons land last, which is the point of the whole section */
  section.head-in .closure-ctas { transition-delay: .34s; }

  /* ---- The word flip ----
     Squid's signature move, and the only thing on their page that is not just a
     rise: each word starts a full line below its place, tipped back 45 degrees,
     and comes up flat.

     `perspective` on the heading is what makes it a flip instead of a squash.
     Without a vanishing point rotateX has nothing to project against and the
     word simply gets shorter — which is exactly how this effect goes wrong when
     it is copied. The number is tuned to the type size: the foreshortening a
     reader sees is the word's own height over this figure, so the hero's smaller
     figures below need a tighter one to read at all. */
  .prob-h, .choice-h, .butler-h, .ucd-h, .sec-h, .faq-h, .closure h2 {
    perspective: calc(500 * var(--u));
  }
  /* `:where` and not `:is` for the display alone, on purpose. :is() carries the
     specificity of its heaviest argument, so `:is(...) .w` weighs the same as
     `.ucd-h .mark` and beat it on source order — which turned that lockup from a
     centred flex row into an inline-block and dropped the icon off the word.
     :where() weighs nothing, so a word that already has a layout of its own
     keeps it, and a plain one still gets the inline-block it needs to move. */
  :where(.prob-h, .choice-h, .butler-h, .ucd-h, .sec-h, .faq-h, .closure h2) .w {
    display: inline-block;
  }
  :is(.prob-h, .choice-h, .butler-h, .ucd-h, .sec-h, .faq-h, .closure h2) .w {
    opacity: 0; transform: translateY(100%) rotateX(45deg);
    transition: opacity .5s ease, transform .8s cubic-bezier(.22, 1, .36, 1);
    transition-delay: calc(.06s + var(--i, 0) * 55ms);
  }
  section.head-in :is(.prob-h, .choice-h, .butler-h, .ucd-h, .sec-h, .faq-h, .closure h2) .w {
    opacity: 1; transform: none;
  }

  /* The hero's three figures take the same flip, on load rather than on scroll,
     after the headline above them has settled. Two indices: --s steps the three
     columns, --i steps the words inside one of them. */
  .stat .v { perspective: calc(300 * var(--u)); }
  .stat .v .w {
    display: inline-block; opacity: 0;
    animation: wordFlip .9s cubic-bezier(.22, 1, .36, 1) forwards;
    animation-delay: calc(.95s + var(--s, 0) * .13s + var(--i, 0) * .05s);
  }
  @keyframes wordFlip {
    from { opacity: 0; transform: translateY(100%) rotateX(45deg); }
    to { opacity: 1; transform: none; }
  }
  /* each label follows its own figure */
  .stat .l {
    opacity: 0;
    animation: heroFade .9s cubic-bezier(.22, 1, .36, 1) forwards;
    animation-delay: calc(1.2s + var(--s, 0) * .13s);
  }

  @media (prefers-reduced-motion: reduce) {
    :is(.prob-h, .choice-h, .butler-h, .ucd-h, .sec-h, .faq-h, .closure h2) .w,
    .stat .v .w, .stat .l {
      opacity: 1; transform: none; animation: none; transition: none;
    }
  }

  /* Groups whose children arrive one after another. --i is written by the
     script when it starts watching, so the stagger holds at any count. */
  /* Both legs in one declaration, and this is not optional. `transition` is a
     single property: written on its own here, this rule would silently drop the
     `transform, box-shadow` transition these cards already carried for their
     hover, and the lift would snap instead of easing. The entrance legs take
     the stagger; the hover legs are pinned to 0s, or the third card would wait
     240ms before it started rising under the cursor. */
  .prob-card, .sec-card, .faq-item, .ucd-row {
    opacity: 0;
    transition: opacity .6s ease, translate .6s cubic-bezier(.22, 1, .36, 1),
                transform .35s cubic-bezier(.22, 1, .36, 1), box-shadow .35s ease,
                background-color .3s ease;
    transition-delay: calc(var(--i, 0) * 80ms), calc(var(--i, 0) * 80ms), 0s, 0s, 0s;
  }
  .prob-card, .sec-card { translate: 0 calc(30 * var(--u)); }
  .faq-item, .ucd-row { translate: 0 calc(24 * var(--u)); }
  .prob-cards.in .prob-card, .sec-cards.in .sec-card,
  .faq-list.in .faq-item, .ucd-table.in .ucd-row { opacity: 1; translate: none; }

  /* The contract row arrives with the table it closes, one beat behind the last
     comparison. No observer of its own: it is the table's next sibling, so the
     class the table already gets carries it. */
  .ucd-contract {
    opacity: 0; translate: 0 calc(24 * var(--u));
    transition: opacity .6s ease, translate .6s cubic-bezier(.22, 1, .36, 1);
    transition-delay: .4s;
  }
  .ucd-table.in + .ucd-contract { opacity: 1; translate: none; }

  /* Blocks that arrive whole */
  .prod-block, .fourth-band {
    opacity: 0; translate: 0 calc(30 * var(--u));
    transition: opacity .7s ease, translate .7s cubic-bezier(.22, 1, .36, 1),
                transform .35s cubic-bezier(.22, 1, .36, 1), box-shadow .35s ease;
  }
  .prod-block.in, .fourth-band.in { opacity: 1; translate: none; }

  /* Squid's one sideways move, and the only place on our page that earns it:
     the chevrons close in from the edges after the band itself has landed —
     hence the delay written into the translate leg alone, so the hover zoom
     on the transform leg stays immediate. */
  .fb-deco.is-left { translate: calc(-64 * var(--u)) 0; }
  .fb-deco.is-right { translate: calc(64 * var(--u)) 0; }
  .fourth-band.in .fb-deco { translate: none; }

  /* ==================================================================
     RESPONSIVE — kept at the foot of the sheet on purpose. These are
     plain class selectors, so they only beat the desktop rules they
     override by coming after them. Anywhere earlier and every rule
     written below would quietly win. Tiers run widest first:
     1024 (tablet) -> 900 (stacking) -> 640 (phone).
     ================================================================== */
  /* ============ TABLET AND BELOW ============
     The fluid unit is a desktop device: it reads the 1920x990 frame and shrinks
     the whole design as one. Below about 1024 that turns against itself — at
     1024 the unit has already fallen to 0.53, which sets body copy at 7px and
     eyebrows at 6. So from here down the unit is pinned to a real device pixel:
     every Figma number in this file then lands at the size it was drawn, and it
     is the LAYOUT that gives instead of the type. The fixed measures go fluid,
     the display face comes down to a size a tablet line can hold, and the
     columns stack in the block below. */
  @media (max-width: 1194px) {
    :root { --u: 1px; --gutter: 32px; }

    /* --u is pinned from here down, so the lockup no longer scales with the
       viewport: it steps down once, here, to keep clear of the centred links. */
    .nav-lockup { height: calc(44 * var(--u)); }

    /* The sheet keeps its drawn 1320 until the screen is narrower than that, and
       then it is the screen that decides. Same for the 1206 blocks inside it:
       min() holds the drawn measure where it fits and gives it up where it does
       not, so there is no width at which either one overhangs the gutter. */
    .wrap { width: min(calc(1320 * var(--u)), 100%); padding-inline: var(--gutter); }
    .prob-cards, .fourth-band, .prod-block, .butler-panes, .sec-cards {
      width: min(calc(1206 * var(--u)), 100%);
    }
    .butler-lede, .ucd-table, .faq-head, .faq-list, .faq-still { max-width: 100%; }

    /* The gutter changes HERE, so everything that sits on it has to follow here
       too. The closing band and the footer carried their desktop insets — 40 and
       80 — while the page had already moved to 32, so between 1025 and 1194 the
       foot of the page stood on three different margins at once. */
    .closure, .footer-inner, .footer-legal { padding-inline: var(--gutter); }

    /* Touch targets. 44 is the floor both platforms publish; the controls were
       drawn for a cursor and land under it. */
    .btn, .prod-cta, .asset-pick button { min-height: calc(44 * var(--u)); display: inline-flex; align-items: center; justify-content: center; }
    .faq-row { min-height: calc(44 * var(--u)); }
    /* the links are 22 of type in a 72 bar; the padding claims the rest */
    .nav-links a { padding-block: calc(11 * var(--u)); }
    .sim-slider input[type="range"]::-webkit-slider-thumb { width: calc(20 * var(--u)); height: calc(20 * var(--u)); }
    .sim-slider input[type="range"]::-moz-range-thumb { width: calc(20 * var(--u)); height: calc(20 * var(--u)); }
    /* The track IS the input's own box, so a 4px bar is a 4px hit area — under a
       thumb that is nothing to aim at. The box grows to 44 and the bar is drawn
       into the middle of it, so the rail looks the same and the whole strip
       answers to a finger. */
    .sim-slider input[type="range"] {
      height: calc(44 * var(--u));
      background-size: 100% calc(4.243 * var(--u));
      background-position: center; background-repeat: no-repeat;
    }
    /* the row is 40 taller than it was, so most of that is taken back above —
       but not below, where the scale labels would ride up into the rail */
    .sim-slider { margin-block: calc(-12 * var(--u)) 0; }
    /* the footer's link columns are set on a 24 line; the rows open up to 44 */
    .footer-col a { display: block; padding-block: calc(10 * var(--u)); }

    /* the unit next to the figure — 9 was legible beside a cursor, not a thumb */
    .sc-chip .u { font-size: calc(11 * var(--u)); }

    /* the health pill is a status, not a caption; it does not go under 10 */
    .sim-badge { font-size: calc(10 * var(--u)); }
    /* 9, uppercase and tracked, is the smallest thing on the page. The GVNR
       breakdown's own 10 is Vero's spec and stays; this one is not. */
    .sg-cell.is-small .sg-lab { font-size: calc(11 * var(--u)); }
  }

  /* Stacking: the width at which the drawn columns stop paying for themselves. */
  @media (max-width: 1024px) {
    /* One more step down for the lockup. The tier above holds 44, which clears
       the centred links only to about a 975 window; this tier reaches 901, where
       44 landed 20 ON TOP of the first link. 38 clears it there with room. */
    .nav-lockup { height: calc(38 * var(--u)); }

    .hero { padding-block: calc(156 * var(--u)) calc(56 * var(--u)); }
    .hero-head { gap: calc(32 * var(--u)); }
    .hero-sub { font-size: calc(16 * var(--u)); line-height: 1.4; }
    .hero-stats { width: 100%; gap: calc(24 * var(--u)); align-items: stretch; }
    .stat { flex: 1 1 0; min-width: 0; }
    .stat .v { font-size: calc(22 * var(--u)); white-space: normal; }
    .stat .l {
      font-size: calc(12 * var(--u)); line-height: 1.35;
      letter-spacing: calc(2 * var(--u)); white-space: normal;
    }

    /* the blocks keep their proportions but not their desktop inset */
    /* The links sit centred, so the room that runs out first is between the
       logo and the first of them: vw/2 - linksWidth/2 - gutter - logo. At the
       wide gap that reaches zero around 944, so it steps back here. */
    /* The block has to stack HERE, not at 900. Side by side it hands the
       simulator (block - 80 padding - 430 story - 48 gap) and the simulator
       cannot compress below 372, so anywhere under about 994 the card's own
       overflow was quietly cutting the right edge off the calculator. */
    /* 60, matching the gap inside the story column: stacked, the story and the
       simulator are two separate blocks, and the space between them cannot read
       as tighter than the space between groups within one of them. */
    .prod-block { grid-template-columns: 1fr; row-gap: calc(60 * var(--u)); }

    .prod-block { padding: calc(40 * var(--u)); }
    .pb-deco { width: 70%; }
    .prob-card { padding: calc(40 * var(--u)) calc(28 * var(--u)); }
    .fourth-band { padding: calc(40 * var(--u)) 0; }
    .butler-panes { padding: calc(28 * var(--u)); min-height: 0; }
    .closure { padding: calc(80 * var(--u)) var(--gutter); }
    .footer-inner { padding: calc(48 * var(--u)) var(--gutter) calc(32 * var(--u)); }
    .footer-legal { padding-inline: var(--gutter); }
  }

  /* Stacking: the point where multi-column layouts stop paying. */
  @media (max-width: 900px) {
    .ce-row, .sim-grid { grid-template-columns: 1fr; }
    .sim-grid.is-flat { grid-template-columns: 1fr; }
    .sim-grid.is-flat .sg-cell { border-left: 0; }
    .sg-cell { border-left: 0; border-top: 1px solid rgba(229, 229, 213, 0.18); }
    .proto-row { grid-template-columns: 1fr 1fr; }
    .pr-cell:nth-child(n+3) { border-top: 1px solid rgba(229, 229, 213, 0.18); }
    .pr-cell:nth-child(odd) { border-left: 0; }
    .closure h2 { font-size: calc(40 * var(--u)); }
    /* The closing pair stacks with the FAQ's, under one shared rule — see the note
       there. */
    .footer-inner { grid-template-columns: 1fr 1fr; padding-inline: var(--gutter); }
    /* --- Footer on a handset ---
       Rebuilt. What was wrong with the version this replaces:

       - Two alignments in one block. The mark was centred while the link columns
         sat flush left, which reads as an accident rather than a choice.
       - A two-column grid holding three groups always leaves a hole; Community
         stood alone with an empty cell beside it.
       - Nine rows of type for six destinations. Three headings over three pairs
         is more chrome than content once the columns are stacked.
       - The mark ran 320 of the 350 available — 91% of the width, and the loudest
         thing in a block whose job is to close the page quietly.

       The pattern instead: each group becomes a labelled ROW with its two links
       side by side, rather than a column of stacked ones. That halves the link
       rows from six to three, spends the width that was going to waste, and
       cannot leave an empty cell because there is no longer a grid to leave one
       in. The labels stay — people hunt for "Legal" by that word — and every
       part of the block finally centres on the same axis. */
    .footer-inner {
      grid-template-columns: 1fr;
      justify-items: center;
      text-align: center;
      row-gap: calc(26 * var(--u));
    }
    /* Full width on purpose. Left to shrink-wrap it settles on the file's own
       declared width, and the percentage cap below then measures itself against
       that instead of against the column — the mark came out at 163 rather than
       the 200 asked for.
       The bottom margin rides on top of the 26 row-gap. The brand is a different
       kind of thing from the three labelled groups under it, and the drawing
       gives that seam about 48 where the seams between groups get 26. */
    .footer-brand {
      width: 100%; align-items: center; text-align: center;
      margin-bottom: calc(22 * var(--u));
    }
    /* --- The handset mark is its own drawing, not the desktop one reflowed ---
       logo-vertical.svg stacks the diamond over the script over HANDS, and it
       carries POWERED BY GVNR at its own foot — hence the row hidden below.

       Both numbers come off the file's dead space. It declares 303 x 146, but the
       ink runs x 50.3 -> 252.7 and y 0 -> 145.3: a third of the width is empty,
       50.3 a side, symmetric. So a 330 element shows 220 of actual mark, and 85%
       of the column is 57% of it in ink. Driven by width, so the stack can never
       be squeezed by a height it cannot meet. */
    .footer-logo { align-self: center; width: min(calc(330 * var(--u)), 85%); height: auto; }
    /* Hidden, not removed. The SVG above already says this, so on a handset the
       row would say it twice — but the image carries a single alt for the whole
       mark, and display: none here would take "Powered by GVNR" out of the
       reading order along with the duplicate. */
    .footer-powered {
      position: absolute; width: 1px; height: 1px; margin: -1px;
      padding: 0; border: 0; overflow: hidden; clip-path: inset(50%);
      white-space: nowrap;
    }

    /* Heading, then its links one under the other. Vero's call over the pair
       laid side by side.

       Note what had to go with the direction: h4 was carrying flex: 0 0 100%,
       which is what forced it onto its own line while the links flowed beside
       it. On a column axis that same shorthand sets the flex-basis against the
       HEIGHT — the heading would have been told to fill the whole group. It is
       the bug that collapsed the option cards, and it is silent. Down a column
       nothing needs the declaration at all: every child already gets its own
       line. */
    .footer-col {
      display: flex; flex-direction: column; align-items: center;
      width: 100%;
    }
    .footer-col h4 { margin-bottom: calc(4 * var(--u)); }
    /* The rows already stood 44 tall from the padding above; stretching them
       makes them 44 WIDE as well, which they were not. Shrink-wrapped to their
       text, "X" was an 8px target — a letter to aim a thumb at. Nothing moves:
       the label stays centred, the row has no ground of its own. */
    .footer-col a { align-self: stretch; text-align: center; }

    /* On a narrow line the disclaimer leaves the copyright nothing, so the two
       go back to sitting one above the other — and centred, on the same axis as
       everything above them. The base rule's baseline alignment is what has to
       go: down a column it packs both blocks against the left edge, which is the
       one thing left in the footer that was not centred. */
    .footer-legal {
      flex-direction: column; align-items: center; text-align: center;
      gap: calc(12 * var(--u)); padding-inline: var(--gutter);
    }
    .faq-head, .faq-list, .faq-still { width: 100%; }
    /* --- Both pairs stack, and the four become one control repeated ---
       Each button used to be sized by its own label, which side by side is just
       two buttons and stacked is a step — the eye reads the wider one as the more
       important of the two. Worse across the two sections: the FAQ pair settled on
       169 and the closing pair on 239, so the page showed two different buttons
       depending on where you had scrolled to.
       So the four share ONE measure, declared here for both grids. 240 is the
       widest of the four labels — "Join the Carry Waitlist" runs 238.6 at this
       size — rounded up, and min() against the column so a narrow screen takes it
       down rather than overflowing. Not a full-width bar: 240 of the 353 a 393
       gives is a button, and a lime band edge to edge would be the loudest thing
       on a page that is closing quietly.
       align-self: stretch is what makes that min() mean anything in the closing
       band. It centres its children, so the grid shrink-wrapped to its own widest
       item and the 100% then measured itself against that — the closing pair came
       out 236.6 while the FAQ's, a block in a plain parent, took the full 240. */
    .faq-ctas, .closure-ctas {
      display: grid;
      grid-template-columns: min(calc(240 * var(--u)), 100%);
      justify-content: center; align-self: stretch;
      gap: calc(12 * var(--u));
    }
    /* The outlined one carries width: max-content from its standalone use, which
       is precisely the stretch opting out: it would keep its own label's width
       and leave the lime one alone at the column's. */
    .faq-ctas .sec-cta { width: auto; }
    .faq-q { width: auto; }
    .faq-t { white-space: normal; }
    .faq-a > p { width: 100%; margin-left: 0; }
    .sec-cards { grid-template-columns: 1fr; gap: calc(20 * var(--u)); }
    .ucd-table, .ucd-contract, .ucd-docs { width: 100%; }
    /* The hair of tracking is a desktop luxury. Below 1194 the unit is pinned
       at 1px while the row is not, and those 8px across 42 characters are what
       tipped the address onto a second line between 641 and 645 — the sliver
       just above the phone tier, where the row is at its narrowest and still
       laid out as one line. Dropping it costs nothing to read and buys 32. */
    .ucd-contract-addr { letter-spacing: 0; }
    .ucd-row { grid-template-columns: 1fr; }
    .ucd-row > * { padding-block: calc(10 * var(--u)); }
    .ucd-row + .ucd-row { padding-block: calc(10 * var(--u)); }
    .butler-lede { width: 100%; }
    .butler-panes { justify-content: center; padding: calc(16 * var(--u)); min-height: 0; }
    .butler-chat { width: 100%; }
    .bc-bubble { border-radius: calc(8 * var(--u)); }
    /* --- The panel comes up to meet the greeting, and the chips go flush left ---
       The 32 of margin that used to be here was only a sixth of what actually
       stood between the bubble and the first chip. Measured at 393, that distance
       was 195: 40 of column gap, 32 of margin, 16 of the panel's padding — and
       107 of the panel's own surplus. min-height holds it at 455 against 348 of
       content, and justify-content: flex-end hands the whole difference to the
       top.
       On the wide layout that surplus is the window the scene shows through, and
       it earns its height there. On a handset it was 107 of empty cream. So the
       margin goes and the panel is handed back to its content: the gap comes down
       to the 40 the column gap holds, which the reveal then closes to 16 as the
       bubble drops into the panel. */
    .bc-foot {
      padding: calc(20 * var(--u));
      min-height: 0;
    }
    .bc-chips { justify-content: flex-start; }
    :root { --gutter: 24px; }
    .hero { padding-inline: var(--gutter); }
    /* The bar wants 666 of the 705 a 768 tablet leaves, and more than the 593 a
       641 one does. Rather than drop the links — the page is one scroll and they
       are its only map — the whole bar comes in a size: shorter mark, tighter
       link gap, smaller button. That reads 556, which clears 641. */
    /* Back to 26, and the 22 that was here is gone with its reason. The links are
       centred on the bar, so their width decides where the lockup has to stop: at
       641 the six of them start at 191.6, and the old single-row file — 6.447 wide
       for every 1 tall — put a 26 mark's right edge exactly on that, touching. 22
       was what bought the clearance back.
       The navbar lockup stacks instead, at 3.305, so 26 of height is 86 of width
       against the 168 the old one took. The collision the 22 solved cannot happen
       at this ratio: 26 leaves 82 of clearance where the fix left 25. */
    .nav-lockup { height: calc(26 * var(--u)); }
    .nav-links { gap: calc(14 * var(--u)); }
    .nav-links a { font-size: calc(12 * var(--u)); }
    /* Down from 11/16 — and the vertical half of that number was never doing
       anything. min-height: 44 from the tier above was setting the height and the
       padding just sat underneath it, so trimming the padding alone would have
       changed nothing at all: 11px of type in a 44 box is what made a small
       label read as a slab.
       So the painted box is released to its own type — 37 — and the 44 goes back
       as a transparent hit area centred on it. The tap target both platforms ask
       for stays exactly 44, without spending half the bar's height on lime to
       get there.
       The horizontal 12 also buys the row 8 of slack it needs: at 375 the gutter,
       the lockup, the gap and the button already came to within 10 of the width. */
    .nav .btn {
      position: relative;
      min-height: 0;
      padding: calc(8 * var(--u)) calc(12 * var(--u));
      font-size: calc(11 * var(--u));
    }
    /* No ground of its own — it exists only to be hit. Left/right at 0 so it
       never reaches past the button's own width into the lockup beside it. */
    .nav .btn::after {
      content: ''; position: absolute; left: 0; right: 0; top: 50%;
      height: calc(44 * var(--u)); transform: translateY(-50%);
    }
    .hero-title h1, .hero-sub, .stat .v, .stat .l { white-space: normal; }
    .wrap { width: auto; padding-inline: var(--gutter); }
    /* Turning the row into a column turns the meaning of flex-basis with it:
       .prob-card carries flex: 1 0 0, which sizes the WIDTH while the axis is
       horizontal and the HEIGHT once it is vertical. With no height to grow
       into, the cards collapsed onto their own padding and the overflow that
       crops their grain cropped the copy with it — 160px of text, invisible.
       Back to auto so each card is as tall as what it holds. */
    .prob-cards { flex-direction: column; }
    .prob-card { flex: 0 0 auto; }

    /* --- The cards stack as they scroll ---
       Each pins a little lower than the one before, so the card underneath keeps
       a visible edge and the pile reads as a pile. 92 parks the first one 20
       below the fixed bar; 16 a step leaves that edge without eating the copy.
       The last card has no room to travel — its foot IS the group's foot — so it
       simply rides up over the two that are pinned, which is what lands it on
       top of the stack. */
    .prob-card { position: sticky; }
    .prob-card:nth-child(1) { top: calc(92 * var(--u)); }
    .prob-card:nth-child(2) { top: calc(108 * var(--u)); }
    .prob-card:nth-child(3) { top: calc(124 * var(--u)); }
    /* The chevrons come down to a third. On the desktop frame the copy is
       sized to pass exactly BETWEEN them — 0% overlap — but as the band narrows
       and the copy wraps taller, the artwork grows with the band and closes
       over the text: 47% of the copy sits on a chevron here and 118% at 390,
       where the two overlap each other across the whole line. Cream reads 8.34
       on the plain olive and 2.07 over the brightest part of the artwork, well
       under the 4.5 floor. At .3 that worst case comes back to about 5.3. */
    .fb-deco { opacity: .3; }

    /* 14, down from the 15 the band was drawn at. The leading stays on its 1.9
       ratio, so the paragraph keeps the air it has — it is the type that comes
       down, not the setting. */
    .fb-copy { padding-inline: var(--gutter); font-size: calc(14 * var(--u)); }
    .fb-copy br { display: none; }
    /* The authored line breaks are set for the desktop measure, so in a narrow
       column they cut a sentence where the eye does not expect it — "...solution
       to / unlock liquidity in" and "appreciated in / Value." Off here, the text
       simply wraps where it runs out of room.
       Three sets of breaks stay on purpose: the security cards, where the break
       is the copy's own phrasing; the GVNR labels, which are two-part names; and
       the butler heading — its break falls after the script word, which is the
       subject of the sentence, so it is phrasing rather than measure. Suppressed
       it cost two things at once: the heading ran to three ragged lines, and
       "Butler" and "carries" came together as one word, since the <br> was the
       only whitespace between the span and the text after it. */
    .prob-h br, .prob-sub br,
    .choice-h br, .choice-sub br,
    .sec-h br, .sec-sub br { display: none; }
  }

  /* ============ PHONE ============
     A 20px margin, which is what iOS and Material both settle on for a handset,
     and the display sizes brought down to a 390pt line. Nothing here changes the
     body scale: at 14px it is already the standard reading size, which is the
     whole point of pinning the unit above. */
  @media (max-width: 640px) {
    /* --- The results read as a table on a handset ---
       Stacked, each metric was three lines tall — label, figure, caption — and
       six of them ran 818px. As rows it is one line each: the name on the left,
       the number against the right edge, the way a statement of figures is
       normally read.

       Which text becomes the row name differs by cell. The three tall ones carry
       BOTH a short label ("You Receive") and a descriptive caption ("Total UCD
       you receive"); it is the caption that reads as a row name, so it takes the
       left and the short label steps out. The compact cells only have the label,
       so that one stays. Both are pulled to the front with order rather than
       moved in the markup, which keeps one DOM for every width. */
    /* The 16 between rows is a real gap, not padding meeting padding: as padding
       each row owned half of it, so the figure inside a row and the figure in the
       next were separated by the same distance twice over. The box then takes its
       own 22 top and bottom, matching the 22 the rows already keep at the sides,
       so the inset reads the same on all four edges. */
    .sim-grid { row-gap: calc(16 * var(--u)); padding-block: calc(22 * var(--u)); }
    .sim-grid .sg-cell {
      display: flex; align-items: baseline; justify-content: space-between;
      gap: calc(16 * var(--u));
      padding: 0 calc(22 * var(--u));
      border-top: 0;
    }
    /* The pill leaves the baseline. Its box is 19 tall around a 10 line-height,
       and on a baseline the slack below that line pushed the row to 59 while
       every other row sat at 47. Centred, it rides inside the row instead of
       setting its height. */
    .sim-grid .sim-badge { align-self: center; margin: 0; }
    /* Two more insets that only make sense stacked, and that outrank the row
       rules by being written for a specific cell kind: the 6 of padding on a
       compact cell in the flat grid, and the 10 that lifts a caption off the
       figure above it. Side by side there is nothing above to clear, and they
       were leaving Earn's rows 4 to 10 taller than Borrow's. */
    .sim-grid.is-flat .sg-cell.is-small { padding-top: 0; }
    .sim-grid .sg-cell.is-lead .sg-note { margin-top: 0; }
    .sim-grid .sg-cell.is-small { padding-block: 0; }
    /* And the 11 of margin that lifts a figure off the pill when the two are
       stacked on the wide layout. Side by side it is not clearance, it is 11 of
       height on one row out of six. */
    .sim-grid .sim-badge + .sg-val { margin-top: 0; }
    /* One edge down the whole panel. It was running three: the head inset 22,
       the controls 32, and the table nothing at all — the rows sat flush against
       the border while everything above them was indented. */
    .sim-ctrls, .sim-ctrls-e { padding-inline: calc(22 * var(--u)); }
    .sim-grid .sg-cell:not(.is-small) .sg-lab { display: none; }
    .sim-grid .sg-note { order: -1; margin-top: 0; }
    /* the pill follows its figure instead of leading it */
    .sim-grid .sim-badge { order: 1; }

    /* row names: one voice for both kinds of cell, and no uppercase — these read
       as sentences, not as column headers. 12 against the figures' 16: the name
       is what you scan past, the number is what you stop on. */
    .sim-grid .sg-note,
    .sim-grid .sg-cell.is-small .sg-lab {
      font-size: calc(12 * var(--u)); line-height: 1.4;
      font-weight: 400; text-transform: none; letter-spacing: 0;
      color: rgba(229, 229, 213, 0.75);
    }
    /* One voice for every figure. Down the column they were alternating between
       two: the three tall cells set their value in Aime at 400, the three compact
       ones in Manrope at 600, so the table changed face on every other row. The
       serif wins — it is what the figures wear everywhere else on this page.
       The unit rides at the same size too; at 11 inside a 16 it read as a
       different measurement rather than the tail of the same number. */
    .sim-grid .sg-val,
    .sim-grid .sg-sub {
      font-family: 'Aime', serif; font-weight: 400;
      font-size: calc(16 * var(--u)); line-height: 1.3;
      margin-top: 0; white-space: nowrap;
    }
    /* Pushed right by its own margin rather than by space-between. On the one
       row that carries a pill there are three items, and space-between spread
       them evenly — the figure ended up floating mid-row, 40 from its badge,
       while every other row had its figure against the edge. The auto margin
       eats the slack in one place, so the figure and its pill travel together. */
    .sim-grid .sg-val { flex-wrap: nowrap; margin-left: auto; }
    .sim-grid .sg-val .unit {
      font-size: calc(16 * var(--u));
      color: rgba(229, 229, 213, 0.55);
    }

    /* --- The GVNR breakdown reads the same way ---
       Same table, same rules, one grid down. It was running four stacked cells
       at 129 each — 515 in total — with its names set in 10px uppercase over two
       hard-broken lines and its figures at 20. As rows it matches the table
       above it exactly: same 14px name, same 16px serif figure, same 22 inset,
       same 16 between rows.

       Every declaration here is written one level deeper than the desktop rule
       it has to beat — .proto-row .pr-cell .sg-lab against .pr-cell .sg-lab —
       because those were authored for the stacked cell and outrank a plain row
       rule otherwise. */
    .proto-row {
      row-gap: calc(16 * var(--u));
      padding-block: calc(22 * var(--u));
    }
    .proto-row .pr-cell {
      display: flex; align-items: baseline; justify-content: space-between;
      gap: calc(16 * var(--u));
      padding: 0 calc(22 * var(--u));
      border: 0;
    }
    /* the break is a two-part name on a stacked cell; on one row it only wraps */
    .proto-row .pr-cell .sg-lab br { display: none; }
    .proto-row .pr-cell .sg-lab {
      font-size: calc(12 * var(--u)); line-height: 1.4;
      font-weight: 400; text-transform: none; letter-spacing: 0;
      color: rgba(229, 229, 213, 0.75);
    }
    .proto-row .pr-cell .sg-val {
      font-family: 'Aime', serif; font-weight: 400;
      font-size: calc(16 * var(--u)); line-height: 1.3;
      margin-top: 0; white-space: nowrap;
    }

    /* Row order. Down the desktop grid the three tall cells come first and the
       three compact ones after, which is a fact about a 3-by-2 layout and not
       about the figures. Read as a list it should run: what you receive, what
       backs it, how healthy that is, where it liquidates, what it costs, what
       you end up owing. Reordered here rather than in the markup, so the wide
       layout keeps the arrangement it was drawn with. */
    .sim-grid:not(.is-flat) .sg-cell:nth-child(1) { order: 1; }
    .sim-grid:not(.is-flat) .sg-cell:nth-child(4) { order: 2; }
    .sim-grid:not(.is-flat) .sg-cell:nth-child(2) { order: 3; }
    .sim-grid:not(.is-flat) .sg-cell:nth-child(5) { order: 4; }
    .sim-grid:not(.is-flat) .sg-cell:nth-child(3) { order: 5; }
    .sim-grid:not(.is-flat) .sg-cell:nth-child(6) { order: 6; }

    :root { --gutter: 20px; }

    /* The bar is a mark, five links and a button drawn for a 1920 line. The
       links already leave at 900; the mark and the button still have to fit a
       375 one, so both come down to a handset scale. Sized rather than
       transformed: height is what the other tiers step, so the mark reads one
       way down the whole range. (This used to say the transform was spoken for
       by the scroll-driven shrink — that shrink is gone now.) */
    /* The links leave at this width, so the bar is just the lockup and the
       button and the mark can come back up. */
    .nav-lockup { height: calc(34 * var(--u)); }
    .btn {
      padding: calc(11 * var(--u)) calc(14 * var(--u));
      font-size: calc(11 * var(--u)); letter-spacing: calc(0.6 * var(--u));
    }

    .hero { padding-block: calc(116 * var(--u)) calc(40 * var(--u)); }
    .hero-head { gap: calc(24 * var(--u)); }
    .hero-eyebrow { font-size: calc(10 * var(--u)); letter-spacing: calc(2.4 * var(--u)); }
    .hero-sub { font-size: calc(15 * var(--u)); }
    /* A 96 bar is 11% of a handset screen. Here it stays at the 72 it was,
       and the hero keeps the 44 of air under it that goes with that. */
    .nav { height: calc(72 * var(--u)); }

    /* Three stats on a 335 line would be 98 each. They go under one another. */
    .nav-links { display: none; }
    .hero-stats { flex-direction: column; align-items: flex-start; gap: calc(20 * var(--u)); }
    .stat { width: 100%; }
    .stat .v { font-size: calc(20 * var(--u)); }

    /* Headings. 40 was drawn against the full-width measure; on a 350 line it
       reads as a banner rather than a heading. */
    .prob-h, .choice-h, .sec-h, .ucd-h, .faq-h, .butler-h { font-size: calc(30 * var(--u)); }
    /* The script word never got a step of its own, so it stayed at its desktop
       80 against a heading that is now 30 — a 2.67 ratio where the design draws
       2. 60 restores it, and the unitless .6 leading follows the size down on its
       own: 60 x .6 is 36, which is exactly the 30px line box it has to sit in. */
    .butler-h .script { font-size: calc(60 * var(--u)); }
    .closure h2 { font-size: calc(32 * var(--u)); }
    .prod-h { font-size: calc(24 * var(--u)); }
    .fb-h { font-size: calc(20 * var(--u)); }

    /* The steps go back to two lines here — the story column needs 410 to hold
       one, and it only has that above about a 498 viewport. At two lines the
       desktop's 24 would fall UNDER the 25.6 leading inside each item, and the
       four of them would read as one block of eight lines rather than as a list.
       32 puts the space between items back above the space within them. */
    /* --- Product cards on a handset ---
       Two different 60s come down here: the one inside the story column, between
       its three groups, and the one between the story and the simulator when the
       card stacks.
       They used to be set equal at 40, guarding against the space BETWEEN the two
       blocks reading tighter than the space WITHIN one. The story's own is now 30
       on Vero's number, which leaves that ordering intact — 30 within against 40
       between — so the guard still holds; it was the other way round that would
       have broken it. */
    .pb-story { gap: calc(30 * var(--u)); }
    .prod-block { row-gap: calc(40 * var(--u)); }

    /* Centred on a handset. The story column carries the alignment, and the CTA
       gives up the flex-start it wears on the wide layout. */
    .pb-story { align-items: center; text-align: center; }
    .prod-cta { align-self: center; }

    /* --- The steps are the one thing in this column that stays left ---
       Vero's call, and the two-column grid comes back with it. The grid was
       dropped here for a reason that only held while the list was centred: a
       fixed number column pinned the four figures to the left edge while the
       sentences floated free of them, which read as neither alignment. Left, that
       conflict is gone — and the grid is what makes this read as a list. The
       figures stand on one line, and a step long enough to wrap hangs its second
       line off the copy edge instead of sliding back under its own number.
       align-self: stretch because the column centres its children: left-aligned
       text in a shrink-wrapped box would still sit in the middle of the card.
       26 rather than the 30 of the wide layout — the type came down from 14 to
       12 here, and the number column comes down with it.
       4 for the gap, on Vero's number. It is the leading that separates the steps
       now: the line box stays at 25.6 against 12 of type, so each one already
       carries more than twice its own height in air. */
    .prod-steps {
      align-self: stretch; text-align: left;
      gap: calc(4 * var(--u));
    }
    .prod-steps li { grid-template-columns: calc(26 * var(--u)) auto; }
    .prod-steps .t, .prod-steps .n { font-size: calc(12 * var(--u)); }

    /* insets, all of them drawn for a full-width block */
    /* 40 at the head, 24 on the other three. The card opens on an eyebrow — eleven
       px of tracked caps — and that is the lightest thing it has: given the same
       24 the sides get, it sat closer to the edge than any line of type below it.
       The extra 16 is the head of the card reading as a head. */
    .prod-block { padding: calc(40 * var(--u)) calc(24 * var(--u)) calc(24 * var(--u)); }
    .prob-card { padding: calc(32 * var(--u)) calc(24 * var(--u)); }
    .fourth-band { padding: calc(32 * var(--u)) 0; }
    .butler-panes { padding: calc(12 * var(--u)); }
    .bc-foot { padding: calc(16 * var(--u)); }
    .closure { padding: calc(64 * var(--u)) var(--gutter); }
    /* --- The comparison table on a handset ---
       Two columns, not one. This table exists to set two claims against each
       other, and stacking them turns the argument into a list: the header row
       collapsed into two orphan labels 123px above the first value, and nothing
       downstream said which side any line belonged to. 350 minus a 12 gap gives
       169 a column, and at that measure the longest line on either side wraps to
       two — the widest single word is 87, so nothing can overflow.
       The label takes its own row above the pair. */
    .ucd-row {
      grid-template-columns: 1fr 1fr;
      grid-template-areas: 'lab lab' 'ours theirs';
      column-gap: calc(12 * var(--u));
      align-items: start;
    }
    /* The contract on a handset. 42 hex characters will not share a line with
       anything else at 350, so the three parts stack: name, address, link. The
       address keeps its own row at full width and drops a step in size, which
       is what lets it stay on ONE line — broken across two, a hex string reads
       as two different strings. */
    .ucd-contract {
      flex-wrap: wrap; row-gap: calc(8 * var(--u));
      padding: calc(14 * var(--u));
    }
    .ucd-contract-lab { flex: 0 0 100%; }
    /* The size is tied to the width, which is the only way this stays on one
       line across the range. At a flat 12 it measures 320 in the 322 a 390 has
       to give — it fit, and every handset narrower than 390 broke it in two.
       A hex string on two lines is the one wrap worth this much trouble: it is
       read character by character when it is checked at all, and split down the
       middle people misread which half is which.
       42 characters of Manrope run 24 times the font size, so the size is whatever
       the row has to give divided by 24, capped at 12.
       What the row has to give changed when the glyph moved up beside the address,
       which is where it belongs — it is the button for the string it sits next to,
       and a row below it read as a third action rather than as part of this one.
       The address no longer owns the full width: viewport less the 40 of gutter,
       the 28 of padding, the glyph's 24 and the 10 of gap between them — 102. The
       constant is 110 rather than 102, and the 8 of difference is the whole point:
       at 102 the string fitted its box with 2 to spare, and 2 is a rounding, not a
       margin. The 24 holds for Manrope at every size measured, but a fallback face
       would not measure the same, and this is the one string on the page where
       being wrong costs a wrap. The price is that the 12 ceiling now arrives at
       398 instead of 392, so a 393 screen sets it at 11.8 — 0.2 of type against
       8 of certainty.
       Tracking goes to 0 here — it does not scale with the type, so at 9px it was
       a fifth of the character width rather than a hair. */
    .ucd-contract-addr {
      flex: 1 1 auto;
      font-size: min(calc(12 * var(--u)), calc((100vw - 110px) / 24));
      letter-spacing: 0;
    }
    /* 10 rather than the 20 the wide row uses: the glyph has to fit on the line
       with the address at 320, and every unit of gap comes off the type. The pull-in
       it wears on the wide layout is what that 10 replaces. */
    .ucd-contract { column-gap: calc(10 * var(--u)); }
    .ucd-contract-copy { margin-left: 0; }
    .ucd-contract-go { margin-left: 0; }

    .ucd-row .ucd-lab { grid-area: lab; }
    .ucd-row .ours { grid-area: ours; }
    .ucd-row .theirs { grid-area: theirs; }
    .ucd-row > * { padding-inline: 0; }

    /* The head row is the key to the two columns, so it rides under the bar
       while the five rows scroll past it. Its own label cell is empty and would
       only open a gap, so it goes. */
    .ucd-row.is-head {
      position: sticky; top: calc(72 * var(--u)); z-index: 2;
      grid-template-areas: 'ours theirs';
      background: #D8D8C9;
      border-bottom: 1px solid #CACABD;
    }
    .ucd-row.is-head .ucd-lab { display: none; }

    /* nothing inside the chat may out-measure the panel that holds it */
    .butler-panes *, .prod-block img, .prob-card img { max-width: 100%; }
    /* The greeting is drawn 468 of the column's 540 and slid 34 right as it
       arrives. Clamped to the full width it would have nowhere to slide to and
       the panel's own overflow would cut it off, so it keeps its inset as a
       proportion and travels a shorter distance. */
    .bc-bubble { width: 82%; }
    .butler-chat.in .bc-bubble { transform: translate(calc(14 * var(--u)), calc(24 * var(--u))); }

    /* The seal is hung 34 outside the signature so it reads as dropped onto it
       rather than placed beside it. On a 375 line that 34 is the page's only
       remaining horizontal overflow, so it comes in and the seal comes down. */
    .signoff-stamp {
      right: calc(-6 * var(--u));
      width: calc(72 * var(--u)); height: calc(72 * var(--u));
    }

    /* One column, and no rules between the items. The dividers were drawn back
     when each cell was a stacked card and needed an edge to be told apart from
     the next; as a table the 16 of gap already does that, and a line every row
     turns a quiet list of figures into a ledger. */
    .proto-row { grid-template-columns: 1fr; }
  }
