/* Desktop layer — ≥861px only.
 *
 * Linked from index.html as:
 *   <link rel="stylesheet" href="desktop.css" media="(min-width: 861px)">
 *
 * The media attribute is the guarantee: the browser never applies this file
 * below 861px, so nothing written here can reach the approved mobile layout.
 * That only holds while desktop work stays IN this file — a desktop tweak made
 * by editing a base rule in index.html breaks the guarantee.
 *
 * Contract while the desktop pass is in progress:
 *   - Desktop CSS goes here. Never edit base rules in index.html for desktop.
 *   - `git diff -- index.html` should stay empty. If it isn't, mobile is at risk.
 *   - Desktop-only JS goes behind matchMedia('(min-width: 861px)').
 *   - Desktop-only markup: base rule hides it, this file shows it.
 *
 * Loads after index.html's inline <style>, so equal-specificity rules here win.
 * Sections below follow index.html's source order.
 */

/* ---- hero ----
 * Two columns: copy left, the 3D phone + card right.
 * Scoped to .story (the animated path) because that's where the canvas is
 * absolute and can be moved to its own half. Without .story — no JS, blocked
 * CDN, reduced motion — the hero keeps the stacked fallback, just with the
 * extra air below. */
/* the 100px page margin: header, content column and scene all sit inside it */
.site-header {
  padding-inline: 100px;
}

.hero-copy {
  padding-top: 21vh;
}
/* 86px is the design size; below ~1150 the copy column is too narrow for it,
   so it tracks the viewport down instead of wrapping into four lines */
.hero-copy h1 {
  font-size: min(86px, 7.5vw);
}
/* hero body line — its own class so it can carry a desktop size without
   touching the shared .tagline */
.hero-body {
  font-size: 23px;
}

/* the canvas and .intro are both absolute under .story, so .hero-copy is the
   only flex item here — centering it can't disturb them.
   --gutter / --content define the shared content column: 1200px max, never
   closer than 100px to the edge. % resolves against the section width in both
   the padding and the canvas offsets, so the two stay locked together. */
.story #hero-story {
  --gutter: max(100px, calc((100% - 1200px) / 2));
  --content: min(1200px, calc(100% - 200px));
  display: flex;
  align-items: center;
  padding-inline: var(--gutter);
}
.story .hero-copy {
  width: 50%;
  padding: 0;
  text-align: left;
}
.story .hero-copy h1 {
  text-wrap: initial;
} /* balance is for centred copy */
/* scoped to the hero: the closing CTA's form stays centred on its own axis */
.story .hero-copy .form-group {
  margin-left: 0;
}
/* The canvas stays full-bleed (inset:0 from index.html) on desktop too.
   It used to be clipped to the right column, but a canvas is a hard crop —
   with a 400px-wide box the camera's horizontal FOV collapses (fov is
   VERTICAL, horizontal follows from aspect) and the phone and card were cut
   off at both edges. Full-bleed costs nothing: the canvas is
   pointer-events:none and draws only where the objects are. Placing the
   composition in the right column is now the camera's job — see reframe() in
   index.html, which offsets the view to the space beside .hero-copy. */

/* the mobile lockup is a different Red Dot variant — desktop runs the plate */
.reddot-m {
  display: none;
}

/* award badge: flush to the hero's right edge, on the phone's midline. Above
 * the canvas (z3) so the card can't fly over it; pointer-events off so it never
 * eats a poke-drag aimed at the phone. knobs: top, width. */
.reddot {
  display: block;
  position: absolute;
  right: 0;
  top: 62%;
  z-index: 4;
  width: 80px;
  height: auto;
  pointer-events: none;
}

/* ---- intro (second screen) ---- */
/* 33px = mobile's 23 + 10. max-width tracks it so the line length stays put —
   at 480px this size would stack into a narrow eight-line column. */
.intro p {
  font-size: 33px;
  max-width: 690px;
}
/* circles +25% — icon and the overlap scale with them so the pair keeps its
   proportions. They cross in on xPercent, so size doesn't affect the entrance. */
.intro-icons .tile {
  width: 150px;
  height: 150px;
}
.intro-icons img {
  width: 70px;
  height: 70px;
}
.intro-icons .tile.card {
  margin-left: -25px;
}

/* ---- reveal blocks (#hold / #spend) ---- */
.hold-title {
  font-size: min(96px, 11vw);
}
.copy-lines p {
  max-width: 480px;
  margin-left: auto;
  margin-right: auto;
}

/* Benefit journey (.story only — no-JS / reduced motion keep the stacked
 * mobile-style column above). Everything must fit one pinned viewport: the
 * pin holds the section with its top 15% above the fold, so the visible band
 * is [15vh…115vh] of the mask — padding clears the dead zone, the phone caps
 * at ~58vh, and the benefit lines become side texts the timeline swaps. */
/* the pin holds the section 15vh ABOVE the fold, so a 100svh mask leaves a
 * 15vh white band under it — the colour has to run 115svh to fill the screen.
 * The benefit stage begins 200px below the visible top (clear of kicker/name)
 * and ends 4vh above the visible bottom. Its midpoint is 63vh + 100px in mask
 * coordinates; both the phone and copy use that one axis so tall viewports do
 * not leave the capped phone floating above its related text. */
.story .hold-mask {
  min-height: 115svh;
  --benefit-center-y: calc(63svh + 100px);
  /* Fallback inner edge of the copy column, from the centre line — used only
   * until syncCopyLanes() publishes its first measurement, and on a page where
   * the journey never builds. Not a floor under the lane: see the note on the
   * .copy-lines rules for why competing with the lane is what made the gap
   * inconsistent between sides and viewports in the first place. */
  --copy-inset: calc(50% + 56px);
}
/* 15vh clears that same dead zone; +90px puts the title clear of the header */
.story .mask-content {
  padding-top: calc(15vh + 90px);
  padding-bottom: 4vh;
}
/* the block subtitle is redundant here — each benefit now carries its own body
 * copy beside the phone, so the header stays kicker + name only */
.story .mask-sub {
  display: none;
}
/* large hero-scale phone: 32vh wide ≈ 66vh tall, the block's dominant object.
 * Take the travelling phone out of the title's flow and centre it in the
 * below-title stage. The negative margin is half the phone's reserved height.
 * It cannot live in translateY because GSAP owns y during the landing tween. */
.story .mask-content > .mask-phone {
  position: absolute;
  top: var(--benefit-center-y);
  left: 50%;
  /* the 26vw term is the mid-width guard: the copy sits at 50% + 30px while the
   * phone only travels min(19vw, 300px) — on a narrow-but-tall window the
   * 32vh-sized phone (plus #spend's fanned card) reached into that copy. Width
   * tracks the viewport below ~1310px so phone + card always clear the text. */
  --phone-w: min(340px, 32vh, 26vw);
  width: var(--phone-w);
  /* half the reserved phone height: width × (1115 / 539) ÷ 2 */
  margin: calc(var(--phone-w) * -1.0344) 0 0;
  translate: -50% 0;
}
/* the live phone: bleed past the phone box so nothing renders off the canvas —
 * a canvas is a hard crop, so anything outside this box is simply not drawn.
 * At 220% the fanned card's corner sat 4px inside the right edge and clipped
 * flat on the float. 250% leaves ~65px of margin and still stops short of the
 * copy. The camera z in index.html is tuned against the HEIGHT ratio, so
 * retune that together with 124%; the width is free. */
.story .phone3d-canvas {
  display: block;
  position: absolute;
  z-index: 2;
  /* explicit box, never left/right+auto: a canvas is a replaced element, so
   * auto width resolves to the drawing buffer, not the insets */
  top: -12%;
  left: -65%;
  width: 250%;
  height: 124%;
  pointer-events: none;
}
/* benefit lines: absolute side texts over the mask, vertically on the phone's
 * midline. Odd lines sit right (phone travels left), line 2 sits left. Staged
 * at opacity 0 — the journey timeline fades them; opacity keeps them in the
 * AX tree like the rest of the staged mask copy. */
/* above the canvas (z2): the wide canvas box now reaches toward the copy, and
 * the text must win that overlap even though the canvas paints transparent */
.story .copy-lines {
  position: absolute;
  inset: 0;
  margin: 0;
  pointer-events: none;
  z-index: 4;
}
.story .copy-lines p {
  position: absolute;
  top: var(--benefit-center-y); /* exact travelling-phone midline */
  /* independent property, not transform: the journey tweens x via GSAP, which
   * owns transform — translate composes with it instead of being clobbered */
  translate: 0 -50%;
  /* The box spans the whole band left over beside the phone — both offsets are
   * set by the rules below — and `auto` margins then centre the column inside
   * that band. Hugging the phone with only one offset set was what pushed the
   * pair off-axis: the gap was right, but every pixel of slack piled up on the
   * far side, so at 1470 the copy sat 580px from the page edge and 125px from
   * the device. Centred in the band, the two halves balance at any width.
   *
   * width:auto (not the old fixed 420) is what lets both offsets apply; the cap
   * moves to max-width, and the over-constrained abspos rules re-resolve the
   * auto margins as equal. 26vw was 333px at 1280 — one glyph short of "Apple
   * Pay, Google Pay", which then broke to a third line and undid the authored
   * two-line break, hence 30vw.
   *
   * min-width is for the OTHER line: both lanes are republished from the same
   * phone box every frame, so while the phone sits on one side the far side's
   * band computes negative. That line is at opacity 0, but a 0-width box still
   * reflows the copy one character per line on every scrub frame. */
  width: auto;
  min-width: 160px;
  max-width: min(30vw, 420px);
  margin: 0 auto;
  font-size: 30px;
  line-height: 1.3;
  /* centred in its own band, so the two sides are mirror images — a flush edge
   * only reads as deliberate when the block it is flush against is fixed, and
   * this one travels */
  text-align: center;
  opacity: 0;
}
/* nth-of-TYPE, not nth-child: the mobile stack interleaves a .mask-phone div
 * between the benefit paragraphs, which would shift every child index here. */
/* --lane-left / --lane-right are published by syncCopyLanes() in index.html
 * from the phone's measured box: the device's edge plus one gap. They are used
 * ALONE, not max()'d against the authored inset, and that is the whole point.
 *
 * An inset from the centre line makes the gap whatever happens to be left over
 * after the phone: D() + inset − half the phone's width, where D() tracks vw
 * and the phone's width tracks vh. Two windows, or the same window with the
 * phone parked left vs right on #spend (the fanned card widens one side only),
 * then read as different layouts — ~126px of air in one and ~48px in the
 * other. Anchoring to the measured edge instead makes the gap a value we set:
 * identical on both sides, at every viewport, at every frame of the travel.
 *
 * --copy-inset is the fallback for before the first measurement and for a page
 * where the journey never builds — never a competing floor.
 *
 * The far offset is the page's own 100px margin — the same one the header,
 * the how-scroll row and the footer use — so the band is exactly "everything
 * between the page edge and the device". */
.story .copy-lines p:nth-of-type(odd) {
  left: var(--lane-left, var(--copy-inset));
  right: 100px;
}
.story .copy-lines p:nth-of-type(2) {
  left: 100px;
  right: var(--lane-right, var(--copy-inset));
}
/* the journey travels one live phone — the mobile stack's extra phones are off */
.story .copy-lines .mask-phone {
  display: none;
}
/* the benefit title breaks where the copy wants it to, not where the column
 * width happens to land. Inline spans on mobile, so that column is untouched. */
.story .copy-lines .t {
  display: block;
}
/* supporting sentence under each benefit — same face and colour as the block
 * subtitle it replaces */
.story .line-note {
  display: block;
  /* both resets undo the mobile rule, which centres the note in a 340px box —
   * inside this 420px column that pushed the body 40px off the title's edge */
  margin: 14px 0 0;
  max-width: none;
  font-family: "Herokid", sans-serif;
  font-weight: 400;
  font-size: 17px;
  line-height: 1.5;
  color: #313131;
}

/* ---- why / how ---- */
.why-title {
  font-size: min(72px, 8vw);
}

/* how: cards +30% (325x390), with the padding scaled to match so the growth
   lands as breathing room — icon, title and body keep their mobile sizes.
   Row gutters follow the page's 100px margin; scroll-padding matches so a
   snap doesn't eat the leading inset. */
.how-scroll {
  gap: 24px; /* +8 */
  padding-inline: 100px;
  scroll-padding-inline: 100px;
  cursor: grab;
  overscroll-behavior-inline: contain;
}
.how-scroll.is-dragging {
  cursor: grabbing;
  scroll-snap-type: none;
  user-select: none;
}
.how-scroll:focus-visible {
  outline: 2px solid var(--color-black);
  outline-offset: -4px;
}
.how-card {
  width: 325px;
  min-height: 390px;
  padding: 50px 49px; /* +20px each side; vertical evened out for the centring */
  /* the row is min-height driven, so top-aligned content dumped all its slack
     after the body. Centring splits that slack above and below instead — and
     it stays balanced across cards with different copy lengths. */
  justify-content: center;
}
.how-card h3 {
  margin-bottom: 20px;
} /* +8 title -> body */
.how-card p {
  font-size: 14px;
} /* +1 */
/* icon circles 25% lighter: a 25% white wash over whatever colour the card
   carries, instead of restating each one. It sits under the glyph, so the
   glyph keeps full strength (opacity: .75 on the circle would fade it too).
   !important is load-bearing — each card sets `style="background: <colour>"`,
   and that shorthand resets background-image at inline specificity. */
.how-icon {
  background-image: linear-gradient(
    rgba(255, 255, 255, 0.25),
    rgba(255, 255, 255, 0.25)
  ) !important;
}

/* ---- partners ----
 * One height for every logo balances the boxes, not the marks: at 34px tall a
 * 5.7:1 wordmark (Rhino) carries ~3x the ink of a 2:1 mark (M0), and at 195px
 * it outgrows its own 108px cell — so `max-width: 100%` starts shrinking it on
 * some widths and not others, which is why it looked different per device.
 * These heights equalise AREA instead (h = sqrt(target / aspect)), and every
 * logo then fits its track at any desktop width, so the rendered size stops
 * depending on the viewport.
 *
 * Area target raised 2900px² -> 6000px² (logos ~45% taller). The section also
 * widens below so the bigger marks keep their air: the widest of them (Rhino
 * at 184px) still clears its 295px track, which is what keeps max-width from
 * kicking in and reintroducing the per-device sizing. */
.partners {
  max-width: 980px;
}
.partners-title {
  font-size: 24px;
  margin-bottom: 56px;
}
.partners-grid {
  gap: 64px 48px;
}
.partner img.logo-dfns {
  height: 39px;
} /* 3.90:1 */
.partner img[src*="m0"] {
  height: 55px;
} /* 2.00:1 */
.partner img[src*="rhino"] {
  height: 32px;
} /* 5.74:1 */
.partner img.logo-biconomy {
  height: 34px;
} /* 5.13:1 */
/* rain is deliberately OFF the area formula (which gives 43px): its letterforms
   are solid and heavy, so equal box area still reads ~20% too big next to the
   thin marks. Same 20% correction the mobile rule already applies. */
.partner img.logo-rain {
  height: 34px;
} /* 3.21:1 */
.partner img[src*="fuze"] {
  height: 47px;
} /* 2.76:1 */

/* ---- footer ----
 * Same 100px side margin as every other block. The living gradient lives on
 * <footer>'s ::before (index.html, shared with mobile), so padding the children
 * leaves the band edge to edge. */
.footer-cols {
  padding-inline: 100px;
  /* no cap: the row spans exactly the wordmark's span, so the first and last
     columns line up with the two ends of the mark */
  grid-template-columns: repeat(4, auto); /* + the socials column */
  font-size: 16px; /* +4 on the links */
}
.footer-cols h4 {
  font-size: 16px;
} /* +4 on the column titles */
/* the columns are hidden for now (index.html), so desktop runs the same single
 * socials line as mobile — aligned to the 100px margin, at the desktop link size */
.footer-social {
  padding-inline: 100px;
  font-size: 16px;
}
/* wordmark comes inside the margin instead of bleeding. The bottom tuck crops
   a fixed fraction of the logo's height, so it has to scale with it — a %
   margin (resolved against the footer width) tracks the smaller mark, where
   the mobile -57px would over-crop. The white mark itself is shared with
   mobile now (index.html). */
.footer-word {
  width: calc(100% - 200px);
  margin: 98px 100px -3.4%; /* +50px lower than mobile's 48px */
}
