@font-face {
  font-family: "Space Grotesk";
  src: url("/landing-assets/fonts/space-grotesk.woff2") format("woff2");
  font-weight: 300 700; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/landing-assets/fonts/inter.woff2") format("woff2");
  font-weight: 100 900; font-display: swap;
}

:root {
  --bg: #f5f5f4;            /* page background, matches app canvas gray */
  --surface: #ffffff;
  --ink: #111111;           /* near-black, matches logo/headlines */
  --ink-soft: #55595e;
  --ink-faint: #9c9fa1;     /* micro-labels that must recede from row text */
  --line: #e4e4e2;
  --line-tint: #c4dcd0;     /* hairline that still reads on --tea-tint */
  --accent: #2f7df6;        /* app primary-action blue */
  --green: #2e9e5b;         /* confirmation/tea green */
  --tea-tint: #e2f0e8;      /* pale green wash for section accents */
  --radius-card: 20px;
  --radius-sm: 14px;        /* icon badges, small chrome */
  --radius-pill: 999px;
  --shadow-card: 0 12px 32px rgba(17, 17, 17, 0.08);
  --shadow-lift: 0 20px 44px rgba(17, 17, 17, 0.13);  /* card hover */
  --shadow-float: 0 8px 22px rgba(17, 17, 17, 0.10);  /* floating hero chips */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --beat: 70ms;             /* stagger quantum — every entrance stagger is a multiple */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* overshoot; landings ONLY */
  --shadow-btn: 0 6px 16px rgba(17, 17, 17, 0.12);
  --focus-ring: 0 0 0 4px color-mix(in srgb, var(--accent) 22%, transparent);
  --font-display: "Space Grotesk", system-ui, sans-serif;
  --font-body: "Inter", system-ui, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }
/* white root so iOS Safari's status bar, rubber-band overscroll and the
   safe-area strip all blend with the glass header (pairs with theme-color) */
html { background: #ffffff; }
body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background: linear-gradient(to bottom, #ffffff 0, #ffffff 120px, var(--bg) 640px);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3 { font-family: var(--font-display); font-weight: 700; line-height: 1.1; margin: 0; }
img, svg { max-width: 100%; display: block; }
a { color: inherit; }

/* Ambient page wash. Fixed so it never adds scroll width, and painted behind
   all content — the large light areas were reading flat. */
body::before {
  content: "";
  /* vertical bleed only — horizontal would widen the page at 320px. The
     extra height is headroom for the scroll-linked counter-drift. */
  position: fixed; inset: -14% 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(46% 34% at 6% 16%, var(--tea-tint) 0%, transparent 68%),
    radial-gradient(52% 40% at 96% 78%, var(--tea-tint) 0%, transparent 70%);
  opacity: 0.6;
}

/* ============================================================
   Task 4 — header, hero, platform mock
   ============================================================ */

/* --- Header ------------------------------------------------ */
.site-header {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; justify-content: space-between;
  /* keep the header gutter locked to the hero's, which is centred inside a
     1280px max-width, so the brand and the headline share a left edge on
     wide displays. The bar itself stays full-bleed. */
  /* safe-area terms are for viewport-fit=cover on iOS: the top inset keeps
     the header content below the clock/battery while the glass itself paints
     the status-bar strip; side insets cover the landscape notch. Zero
     everywhere else. Static values — never animate this padding (CLS). */
  padding: calc(16px + env(safe-area-inset-top, 0px))
           max(clamp(20px, 5vw, 64px), calc((100% - 1280px) / 2 + 64px), env(safe-area-inset-right, 0px))
           16px
           max(clamp(20px, 5vw, 64px), calc((100% - 1280px) / 2 + 64px), env(safe-area-inset-left, 0px));
  /* frosted glass: near-white at the top edge so it fuses with Safari's
     white chrome (theme-color), melting into translucency below; the settle
     animation's background-color firms up the translucent zone on scroll */
  /* NOTE (measured on iOS 26 sim): the status-bar strip color is chosen by
     Safari from the page's overall rendered color — it cannot be forced
     white via theme-color, html/body backgrounds, viewport-fit, or painting
     solid white under it. Only a whiter page canvas moves it. */
  background: linear-gradient(to bottom,
      color-mix(in srgb, var(--surface) 96%, transparent),
      color-mix(in srgb, var(--surface) 62%, transparent));
  transition: background-color 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
  -webkit-backdrop-filter: blur(18px) saturate(1.6);
  backdrop-filter: blur(18px) saturate(1.6);
  border-bottom: 1px solid color-mix(in srgb, var(--line) 55%, transparent);
}
.brand { display: inline-flex; line-height: 0; }
.brand img { width: 36px; height: 36px; }
.header-actions { display: flex; gap: 12px; }

/* Log in is deliberately quieter than the account CTA: a text link, not a
   pill — the header carries at most one button-shaped action. Padding keeps
   the tap target ≥44px. */
.header-link {
  display: inline-flex; align-items: center;
  padding: 10px 12px;
  font: 600 15px/1.4 var(--font-body);
  color: var(--ink);
  text-decoration: none;
  border-radius: var(--radius-pill);
}
.header-link:hover { text-decoration: underline; text-underline-offset: 4px; }
.header-link:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* --- Buttons ----------------------------------------------- */
.btn {
  display: inline-block; padding: 10px 24px;
  border-radius: var(--radius-pill);
  font: 600 15px/1.4 var(--font-body);
  text-decoration: none; white-space: nowrap;
  transition: translate 0.18s var(--ease-out), scale 0.18s var(--ease-out), box-shadow 0.15s ease;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none; user-select: none;
}
.btn:hover  { translate: 0 -1px; box-shadow: var(--shadow-btn); }
/* asymmetric press: 90ms in (scale/shadow), sprung 180ms release */
.btn:active { scale: 0.97; box-shadow: none; transition-duration: 0.18s, 0.09s, 0.09s; }
/* after :hover so a focused+hovered button keeps its lift */
.btn:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 3px;
  box-shadow: var(--focus-ring), var(--shadow-btn);
}
.brand:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: var(--radius-sm); }
.btn--outline { border: 1.5px solid var(--line); background: var(--surface); }
.btn--solid { background: var(--ink); color: #fff; border: 1.5px solid var(--ink); }
.btn--lg { padding: 14px 32px; font-size: 16px; }

/* --- System chrome ----------------------------------------- */
::selection { background: var(--tea-tint); color: var(--ink); }
html { scrollbar-color: var(--ink-faint) transparent; }
/* the mock is a picture of a product, not the product — arrow, not I-beam */
.chip, .mock-row, .mock-tab, .mock-pill, .float, .how-num { cursor: default; }

/* --- Hero -------------------------------------------------- */
.hero {
  display: grid; grid-template-columns: 1fr 1fr; gap: 48px; align-items: center;
  padding: clamp(44px, 7vw, 84px) clamp(20px, 5vw, 64px) clamp(36px, 4.5vw, 60px);
  max-width: 1280px; margin: 0 auto;
}
.hero h1 {
  font-size: clamp(3rem, 7vw, 5.25rem);
  letter-spacing: -0.045em;
  line-height: 0.95;
  text-wrap: balance;
  animation: riseIn 0.75s var(--ease-out) 0.05s both;
}
/* Accent on the one word the whole product is about. */
.hl { position: relative; display: inline-block; }
.hl::after {
  content: "";
  position: absolute; left: 0.02em; right: 0.02em; bottom: 0.03em;
  height: 0.1em; border-radius: var(--radius-pill);
  background: var(--green);
  transform-origin: 0 50%;
  animation: drawLine 0.55s var(--ease-out) 0.6s both;
}
.hero-sub {
  font-size: clamp(1.05rem, 1.5vw, 1.25rem);
  color: var(--ink-soft);
  max-width: 46ch;
  margin: 26px 0 0;
  animation: riseIn 0.75s var(--ease-out) 0.18s both;
}
.hero-actions { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 28px; }
.hero .hero-actions { animation: riseIn 0.75s var(--ease-out) 0.28s both; }

.chip-strip {
  display: flex; flex-wrap: wrap; gap: 7px;
  list-style: none; margin: 26px 0 0; padding: 0;
}
.chip {
  padding: 7px 13px;
  border: none;
  border-radius: var(--radius-pill);
  background: var(--tea-tint);
  font: 500 13px/1.3 var(--font-body);
  color: var(--ink-soft);
  animation: riseIn 0.6s var(--ease-out) both;
}
.chip:nth-child(1) { animation-delay: 0.38s; }
.chip:nth-child(2) { animation-delay: calc(0.38s + var(--beat)); }
.chip:nth-child(3) { animation-delay: calc(0.38s + 2 * var(--beat)); }
.chip:nth-child(4) { animation-delay: calc(0.38s + 3 * var(--beat)); }

/* --- Platform mock (decorative) ---------------------------- */
.hero-mock {
  position: relative;
  padding: 46px 30px 92px;
  isolation: isolate;
  animation: fadeIn 0.5s ease 0.1s both;
}
/* soft tea-tint wash behind the cards; kept inside the box so it can
   never widen the page */
.hero-mock::before {
  content: "";
  /* vertical bleed only — a horizontal one widens the page at 320px, where
     the mock is only 20px from the viewport edge */
  position: absolute; inset: -14px 0; z-index: 0;
  /* Two soft tea-tint lobes. Centres sit behind the cards so only a faint
     wash escapes around them, and each stop reaches zero before the box
     edge, so there is no hard cut and nothing can widen the page. */
  background:
    radial-gradient(52% 50% at 68% 30%, var(--tea-tint) 0%, transparent 70%),
    radial-gradient(48% 46% at 30% 72%, var(--tea-tint) 0%, transparent 72%);
}

/* Origin pills and certification chips lifted off the board — the same
   vocabulary the exchange itself uses. Every one sits inside .hero-mock's
   padding box, so none of them can extend the page. */
.float {
  position: absolute; z-index: 3;
  padding: 7px 14px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--shadow-float), 0 0 0 1px rgba(17, 17, 17, 0.04);
  font: 600 12px/1.2 var(--font-body);
  color: var(--ink);
  white-space: nowrap;
  /* sprung landing, then an endless slow orbit. Entrance rides opacity+scale,
     the orbit rides transform — separate channels, they compose. */
  animation: settleIn 0.55s var(--ease-spring) both, driftA 8.5s ease-in-out infinite;
}
/* the pills sit *on* the board's top edge rather than beside it, so they read
   as lifted off the surface instead of drifting in empty space. Orbits are on
   co-prime-ish periods so the four never re-sync into a metronome; depth tiers
   by amplitude alone: driftA nearest/largest, driftC farthest/smallest. */
.float--in    { top: 26px;  left: 2px;   animation-delay: 0.7s, 1.3s;  animation-name: settleIn, driftA; animation-duration: 0.55s, 8.5s; }
.float--lk    { top: 28px;  right: 2px;  animation-delay: 0.85s, 2.6s; animation-name: settleIn, driftC; animation-duration: 0.55s, 13s; }
/* straddles the board's bottom edge inside its 18px inner padding, so it
   never sits over a price */
.float--ke    { bottom: 78px; right: 14px; animation-delay: 1.05s, 3.3s; animation-name: settleIn, driftB; animation-duration: 0.55s, 9.5s; }
.float--certs {
  top: 2px; left: 44%; animation-delay: 0.95s, 1.9s;
  animation-name: settleIn, driftB; animation-duration: 0.55s, 11s;
  display: inline-flex; gap: 6px; padding: 5px 7px;
}
.float--certs i {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--radius-pill);
  background: var(--tea-tint); color: var(--ink);
  font: 700 9.5px/1 var(--font-body); font-style: normal; letter-spacing: 0.03em;
}

.mock-board {
  position: relative; z-index: 1;
  background: var(--surface);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card), 0 0 0 1px rgba(17, 17, 17, 0.045);
  padding: 24px 24px 18px;
  animation: riseInT 0.7s var(--ease-out) 0.12s both;
}

.mock-head {
  display: flex; align-items: center; gap: 14px; margin-bottom: 20px;
  animation: riseInT 0.55s var(--ease-out) 0.3s both;
}
.mock-title {
  font-family: var(--font-display); font-weight: 700;
  font-size: 26px; line-height: 1; letter-spacing: -0.035em;
}
.mock-tabs {
  display: inline-flex; gap: 2px; padding: 3px;
  background: var(--line); border-radius: var(--radius-pill);
}
.mock-tab {
  padding: 6px 14px; border-radius: var(--radius-pill);
  font: 600 12px/1 var(--font-body); color: var(--ink-soft);
}
.mock-tab--on {
  background: var(--ink); color: #fff;
  display: inline-flex; align-items: center; gap: 6px;
}
.live-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--green);
  animation: livePulse 2.4s ease-in-out infinite;
}

.mock-row {
  display: grid;
  grid-template-columns: 1.05fr 0.6fr 0.95fr minmax(74px, auto) auto;
  align-items: center; gap: 12px;
  padding: 12px 2px;
  font: 500 13px/1.25 var(--font-body);
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
}
.mock-row--label {
  padding: 0 2px 9px;
  border-bottom: 1px solid var(--line);
  font: 600 10px/1 var(--font-body);
  letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--ink-faint);
  animation: fadeIn 0.5s ease 0.38s both;
}
.mock-row:not(.mock-row--label) + .mock-row { border-top: 1px solid var(--line); }
/* Rows populate one beat apart, then a highlight walks them the way a live
   board ticks over — the stagger is wider than the lit window, so only one
   row is ever tinted. --i: 0 on the base rule is load-bearing: an undefined
   --i would invalidate the calc() and drop the whole animation list. */
.mock-row:not(.mock-row--label) {
  --i: 0;
  animation:
    riseSm 0.55s var(--ease-out) calc(0.46s + var(--i) * var(--beat)) both,
    rowScan 12s ease-in-out calc(2.2s + var(--i) * 3s) infinite;
}
.mock-table .mock-row:nth-child(3) { --i: 1; }
.mock-table .mock-row:nth-child(4) { --i: 2; }
.mock-table .mock-row:nth-child(5) { --i: 3; }
.mock-cell--num { text-align: right; }
.mock-price {
  color: var(--ink); font-weight: 600;
  font-variant-numeric: tabular-nums;
  /* refresh tick as the row's scan passes — --i inherits from the parent row */
  animation: priceTick 12s ease-in-out calc(2.2s + var(--i) * 3s) infinite;
}
.mock-pill {
  display: inline-block; padding: 5px 11px;
  border-radius: var(--radius-pill);
  background: var(--green); color: #fff;
  font: 600 11px/1 var(--font-body);
  letter-spacing: 0.01em; white-space: nowrap;
  /* the entrance's destination: lands right after its row (--i:1) arrives,
     ring blooms once at 1.5s and never repeats */
  position: relative;
  animation: pillLand 0.62s var(--ease-out) 1.1s both;
}
.mock-pill::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  animation: ringBloom 0.9s ease 1.5s both;
}

.mock-chat {
  position: absolute; z-index: 2;
  left: 0; bottom: 0; width: min(310px, 82%);
  display: flex; flex-direction: column; gap: 8px; align-items: stretch;
}
.mock-msg {
  display: flex; align-items: flex-start; gap: 12px; padding: 14px 17px;
  background: var(--surface); border-radius: var(--radius-card);
  box-shadow: 0 18px 44px rgba(17, 17, 17, 0.15), 0 0 0 1px rgba(17, 17, 17, 0.04);
  animation: popIn 0.5s var(--ease-out) 1.35s both;
}
/* the reply: differentiated by side + surface, never white-on-accent */
.mock-msg--in {
  align-self: flex-end; max-width: 85%;
  background: var(--tea-tint);
  box-shadow: var(--shadow-float), 0 0 0 1px rgba(17, 17, 17, 0.04);
  animation-delay: 3.4s;
}
.mock-msg--in .mock-typing    { animation-delay: 3.5s; }
.mock-msg--in .mock-chat-text { animation-delay: 5s; }
.mock-leaf {
  flex: none; width: 21px; height: 21px; margin-top: 2px;
  background: var(--green);
  border-radius: 2px 100% 2px 100%;
  transform: rotate(-8deg);
}
/* dots and message occupy the same grid cell, so the bubble never resizes
   when the message lands */
.mock-chat-body { display: grid; }
.mock-chat-body > * { grid-area: 1 / 1; }
.mock-chat-text {
  font: 500 13px/1.45 var(--font-body); color: var(--ink);
  animation: fadeIn 0.45s ease 2.95s both;
}
.mock-typing {
  display: inline-flex; align-items: center; gap: 4px;
  align-self: start; height: 19px;
  opacity: 0;                                   /* finished state: gone */
  animation: typingShow 1.7s ease 1.45s both;
}
.mock-typing i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--ink-faint);
  /* finite: 6 cycles cover both visible typing windows, then the battery rests */
  animation: typingBounce 1s ease-in-out 6;
}
.mock-typing i:nth-child(2) { animation-delay: 0.15s; }
.mock-typing i:nth-child(3) { animation-delay: 0.3s; }

/* --- Keyframes --------------------------------------------- */
/* Every rule above declares its *finished* appearance and animates from an
   offset, so `animation: none` (reduced motion) renders the final page. */
@keyframes riseIn   { from { opacity: 0; transform: translateY(18px); } }
@keyframes riseInT  { from { opacity: 0; translate: 0 18px; } }
@keyframes riseSm   { from { opacity: 0; translate: 0 8px; } }
@keyframes fadeIn   { from { opacity: 0; } }
@keyframes drawLine { from { transform: scaleX(0); } }
@keyframes popIn    { from { opacity: 0; transform: translateY(10px) scale(0.96); } }
@keyframes settleIn { from { opacity: 0; scale: 0.94; } 70% { opacity: 1; scale: 1.02; } to { opacity: 1; scale: 1; } }
/* four-stop keyframe IS the spring — do not swap for --ease-spring */
@keyframes pillLand { 0% { opacity: 0; scale: 0.72; } 55% { opacity: 1; scale: 1.06; } 75% { scale: 0.98; } 100% { opacity: 1; scale: 1; } }
@keyframes ringBloom {
  from { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 50%, transparent); }
  to   { box-shadow: 0 0 0 10px color-mix(in srgb, var(--green) 0%, transparent); }
}
/* drift orbits: horizontal apex ≤3px (pills sit 2px from the mock's padding
   edge), vertical ≤8px, rotation ≤0.8deg */
@keyframes driftA { 0%, 100% { transform: none; } 34% { transform: translate3d(-3px, -8px, 0) rotate(-0.8deg); } 67% { transform: translate3d(2px, -4px, 0) rotate(0.5deg); } }
@keyframes driftB { 0%, 100% { transform: none; } 40% { transform: translate3d(2px, -6px, 0) rotate(0.6deg); } 72% { transform: translate3d(-2px, -3px, 0) rotate(-0.4deg); } }
@keyframes driftC { 0%, 100% { transform: none; } 30% { transform: translate3d(-2px, -4px, 0) rotate(-0.4deg); } 64% { transform: translate3d(1px, -2px, 0) rotate(0.3deg); } }
@keyframes livePulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 55%, transparent); }
  70%      { box-shadow: 0 0 0 6px color-mix(in srgb, var(--green) 0%, transparent); }
}
/* swell with a 2px green inset bar — the exchange's selected-row vocabulary:
   in over ~0.5s, hold ~2.2s, out over ~1s */
@keyframes rowScan {
  0%, 100% { background-color: transparent; box-shadow: inset 2px 0 0 transparent; }
  4%  { background-color: color-mix(in srgb, var(--tea-tint) 70%, var(--surface)); box-shadow: inset 2px 0 0 var(--green); }
  22% { background-color: color-mix(in srgb, var(--tea-tint) 70%, var(--surface)); box-shadow: inset 2px 0 0 var(--green); }
  30% { background-color: transparent; box-shadow: inset 2px 0 0 transparent; }
}
/* presentation tick only — the digits never change; they are platform data.
   The lit colour is --green DEEPENED INTO --ink, not --green itself: the tick
   fires while rowScan holds the row at its 70% tea-tint mix (≈rgb(235,244,239)),
   and plain --green on that ground measures 3.05:1 — under the 4.5:1 bar for
   13px/600 text (and 11.5px at ≤560px; neither is "large"). The 70/30 mix
   computes to rgb(37,116,69): measured 5.11:1 on the tint and 5.73:1 on white,
   and it still reads unmistakably green. Do not restore var(--green) here. */
@keyframes priceTick {
  0%, 4%, 100% { color: var(--ink); translate: 0 0; }
  6%  { color: color-mix(in srgb, var(--green) 70%, var(--ink)); translate: 0 -1px; }
  10% { color: color-mix(in srgb, var(--green) 70%, var(--ink)); }
  15% { color: var(--ink); translate: 0 0; }
}
@keyframes typingShow { 0% { opacity: 0; } 8% { opacity: 1; } 88% { opacity: 1; } 100% { opacity: 0; } }
@keyframes typingBounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }

/* --- Responsive -------------------------------------------- */
@media (max-width: 1040px) {
  .hero { gap: 32px; }
  .mock-title { font-size: 23px; }
  .mock-row { font-size: 12px; gap: 9px; padding: 11px 2px; }
  .mock-board { padding: 21px 19px 16px; }
  .mock-chat { width: min(280px, 88%); }
  .mock-msg { padding: 12px 15px; }
  .mock-chat-text { font-size: 12px; }
}
@media (max-width: 880px) {
  .hero { grid-template-columns: 1fr; gap: 40px; }
  .hero-mock { max-width: 560px; width: 100%; }
}
@media (max-width: 560px) {
  .hero-mock { padding: 42px 16px 50px; }
  .mock-board { padding: 18px 16px 14px; }
  /* title + tabs side by side is the widest thing on the page at 320px;
     letting them wrap is what keeps the layout off a horizontal scrollbar */
  .mock-head { gap: 10px; margin-bottom: 16px; flex-wrap: wrap; }
  .mock-title { font-size: 21px; }
  .mock-tab { padding: 5px 11px; font-size: 11px; }
  .mock-row { grid-template-columns: 1fr 0.62fr minmax(66px, auto) auto; font-size: 11.5px; gap: 8px; }
  .mock-cell--weight { display: none; }
  .mock-pill { padding: 4px 9px; font-size: 10px; }
  .mock-chat { width: 90%; }
  .mock-msg { gap: 10px; padding: 12px 14px; }
  .mock-leaf { width: 18px; height: 18px; }
  .mock-chat-text { font-size: 12px; line-height: 1.4; }
  /* only the two origin pills survive on phones — the rest would crowd */
  .float--certs, .float--ke { display: none; }
  .float { padding: 6px 12px; font-size: 11px; }
}

@media (max-width: 430px) {
  /* stop the pills from stacking ragged on narrow phones */
  .hero-actions { flex-direction: column; align-items: stretch; }
  .hero-actions .btn { text-align: center; }
}

/* ============================================================
   Task 5 — features, benefits, founders, CTA band, footer
   ============================================================ */

html { scroll-behavior: smooth; }

/* --- Shared section rhythm ---------------------------------- */
.features, .founders, .roles {
  max-width: 1280px; margin: 0 auto;
  padding: clamp(28px, 4vw, 48px) clamp(20px, 5vw, 64px);
}
.features h2, .benefits h2, .founders h2, .roles h2, .story h2, .cta-band h2 {
  font-size: clamp(1.9rem, 3.6vw, 3rem);
  letter-spacing: -0.035em;
  text-wrap: balance;
}
.section-intro {
  color: var(--ink-soft);
  font-size: clamp(1rem, 1.3vw, 1.125rem);
  max-width: 60ch;
  margin: 14px 0 0;
}
/* micro-label above a section title — same ledger vocabulary as the
   "How it works" label, reusable wherever a section needs an eyebrow */
.eyebrow {
  font: 600 12px/1.4 var(--font-body);
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 18px;
}
/* editorial header row: eyebrow + title left, intro bottom-aligned right */
.section-head--split {
  display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: 20px 56px; align-items: end;
}
.section-head--split .section-intro { margin: 0 0 5px; }

/* --- Icon badges (shared plumbing; each section family sets its
   own chip colour and stroke weight so the three groups read as
   three different rooms of the same building) ----------------- */
.icon-badge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px;
  border-radius: var(--radius-sm);
  background: var(--tea-tint); color: var(--ink);
  margin-bottom: 18px;
}
.icon-badge svg {
  fill: none; stroke: currentColor;
  stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
}
/* benefits family: green marks on white chips, on the tint band */
.icon-badge--solid {
  width: 52px; height: 52px;
  background: var(--surface); color: var(--green);
}
.icon-badge--solid svg { stroke-width: 2.3; }

/* --- How it works: the one place on the page where the order --
   actually carries meaning, so the numbering is earned. -------- */
.how {
  max-width: 1280px; margin: 0 auto;
  padding: clamp(8px, 2vw, 20px) clamp(20px, 5vw, 64px) clamp(24px, 4vw, 40px);
}
.how h2 {
  font-family: var(--font-body);
  font-size: 12px; font-weight: 600; line-height: 1.4;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 26px;
}
.how-steps {
  position: relative;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px;
  list-style: none; margin: 0; padding: 0;
  border-top: 1px solid var(--line);
}
/* the green rule that draws itself through the 1-2-3 badges (Step 7c).
   scaleX(0) at rest — JS-off / no-support / reduced-motion all render
   today's gray border, never a permanent green line. */
.how-steps::before {
  content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 2px;
  border-radius: var(--radius-pill); background: var(--green);
  transform: scaleX(0); transform-origin: 0 50%;
}
.how-step { position: relative; padding-top: 36px; }
.how-num {
  position: absolute; top: -14px; left: 0;
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--radius-pill);
  background: var(--ink); color: #fff;
  font: 600 12px/1 var(--font-body);
  box-shadow: 0 0 0 6px var(--bg);
}
.how-step h3 { font-size: clamp(1.15rem, 1.7vw, 1.45rem); letter-spacing: -0.02em; margin-bottom: 6px; }
.how-step p { color: var(--ink-soft); margin: 0; }

/* --- Features: bento grid, the heaviest visual weight. One dark
   hero-weight card + three supporting on a 7/5 → 5/7 pinwheel; the
   lead card closes with the platform's own cost arithmetic. ---- */
.feature-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 24px; margin-top: 44px; }
.feature-card {
  grid-column: span 5;
  display: flex; flex-direction: column; align-items: flex-start;
  background: var(--surface); border-radius: var(--radius-card);
  box-shadow: var(--shadow-card); padding: 30px 32px 32px;
  transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.feature-card--lead, .feature-card--wide { grid-column: span 7; }
.feature-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lift); }
.feature-card h3 { font-size: 1.3rem; letter-spacing: -0.02em; margin-bottom: 10px; }
.feature-card p { color: var(--ink-soft); margin: 0; }
.feature-top {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; align-self: stretch; margin-bottom: 20px;
}
.feature-top .icon-badge { margin-bottom: 0; }
.feature-tag {
  font: 600 11px/1 var(--font-body);
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink-soft);
}
/* features family: white marks on ink chips */
.feature-card .icon-badge { width: 52px; height: 52px; background: var(--ink); color: #fff; }
.feature-card .icon-badge svg { stroke-width: 2; }
/* the dark lead card — same ink-with-a-breath-of-green ground as the
   CTA band, so the page's two weight peaks rhyme */
.feature-card--lead {
  background-color: var(--ink);
  background-image: radial-gradient(85% 110% at 88% 0%, color-mix(in srgb, var(--green) 20%, var(--ink)) 0%, var(--ink) 62%);
  color: #fff;
}
.feature-card--lead h3 { color: #fff; }
.feature-card--lead p { color: rgba(255, 255, 255, 0.78); }
.feature-card--lead .feature-tag { color: rgba(255, 255, 255, 0.72); }
.feature-card--lead .icon-badge { background: var(--green); }
/* the cost receipt: the same premiums the copy names, added up the way the
   exchange itself does it. aria-hidden keeps a screen reader out of the
   arithmetic — the paragraph above already states it in prose — but it is a
   worked example, not ornament: sighted users READ these labels. aria-hidden
   removes a subtree from the accessibility tree; it does not exempt visible
   text from WCAG 1.4.3, and axe/Lighthouse simply skip the subtree, so a
   clean a11y score is not evidence here. So every colour pair below is held to
   the 4.5:1 text bar and measured off painted pixels: plain token 15.52:1 with
   its 6.45:1 label, sum pill 5.73:1 with its 5.13:1 label, and the + / =
   operators 4.52:1. The operators are the floor — do not lighten this card's
   ground or lower their 0.45 alpha without re-measuring. */
.calc-strip {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  align-self: stretch; margin-top: auto; padding-top: 26px;
}
.calc-token {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 12px; border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.08);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.10);
  font: 600 13px/1 var(--font-body); color: #fff;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.calc-token i {
  font: 500 9.5px/1 var(--font-body); font-style: normal;
  letter-spacing: 0.07em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}
/* the "=" may never wrap away from the result it introduces */
.calc-eq { display: inline-flex; align-items: center; gap: 8px; }
/* the sum carries the receipt's answer, so it gets the only solid fill — but
   NOT plain --green. White on #2e9e5b measures 3.41:1 and the sub-label at
   0.85 alpha 2.89:1; the amount is 13px/600 (12px at ≤560px) and the label
   9.5px, so neither is "large text" and both owe 4.5:1. Same deepening the
   priceTick keyframe uses: 70% --green into --ink = rgb(37,116,69), which
   measures 5.73:1 for the amount and 5.13:1 for the label, and still reads
   unmistakably green on the card's near-black ground (3.29:1 against it).
   Do not restore var(--green) here. */
.calc-token--sum { background: color-mix(in srgb, var(--green) 70%, var(--ink)); box-shadow: none; }
.calc-token--sum i { color: rgba(255, 255, 255, 0.92); }
.calc-op { font: 600 14px/1 var(--font-body); color: rgba(255, 255, 255, 0.45); }

/* --- Roles: compact bordered cards -------------------------- */
.role-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 32px; }
.role-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: 26px 26px 28px;
  transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.role-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-card); }
/* roles family: keeps the light tea-tint chip, but at full stroke weight */
.role-card .icon-badge { width: 46px; height: 46px; margin-bottom: 16px; }
.role-card h3 { font-size: 1.15rem; letter-spacing: -0.02em; margin-bottom: 6px; }
.role-card p { color: var(--ink-soft); margin: 0; font-size: 0.95rem; }

/* --- Benefits: the section itself is the tea-tint band, no --
   individual card treatment on .benefit — kept plain so features'
   shadowed cards keep the strongest visual weight on the page. The
   columns are separated by hairlines instead, which is the ledger
   vocabulary the exchange itself is built on. */
.benefits {
  /* Flush-column treatment, same box model as .features/.founders
     (max-width + margin auto + the standard horizontal padding), NOT
     the .cta-band inset formula — stacking an outer inset margin AND
     matching internal padding double-indented the heading relative to
     every other section's h2. Heading rhythm across sections wins over
     edge-parity with .cta-band; the tint still reads as a clear band
     because it paints the full padding-box, and still shows rounded
     corners inside the viewport gutter at 1280px+. */
  max-width: 1280px; margin: 0 auto;
  padding: clamp(40px, 6vw, 72px) clamp(20px, 5vw, 64px);
  background: var(--tea-tint);
  border-radius: var(--radius-card);
}
.benefit-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; margin-top: 36px; }
.benefit { padding-right: 28px; }
.benefit + .benefit { border-left: 1px solid var(--line-tint); padding-left: 28px; }
.benefit:last-child { padding-right: 0; }
.benefit h3 { font-size: 1.15rem; letter-spacing: -0.02em; margin-bottom: 8px; }
.benefit p { color: var(--ink-soft); margin: 0; }

/* --- Story: the about-us film, one click from playing. The facade
   is a real link (Vimeo in a new tab with JS off); reveal.js upgrades
   it to swap in the player, so no Vimeo request exists until then. -- */
.story {
  max-width: 1280px; margin: 0 auto;
  padding: clamp(32px, 5vw, 60px) clamp(20px, 5vw, 64px) clamp(16px, 2.5vw, 28px);
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(28px, 4vw, 56px); align-items: center;
}
.story .section-intro { max-width: 38ch; }
.video-frame {
  position: relative; aspect-ratio: 16 / 9;
  border-radius: var(--radius-card); overflow: hidden;
  background: var(--tea-tint);
  box-shadow: var(--shadow-card), 0 0 0 1px rgba(17, 17, 17, 0.045);
}
.video-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
/* centring is grid placement, not translate — the reduced-motion layer
   zeroes translate/scale globally and must not move this button */
.video-facade { position: absolute; inset: 0; display: grid; place-items: center; }
/* the ring must out-paint the absolutely-positioned poster, so it lives on
   an overlay above the children, not on the element's own outline. The
   transparent outline stays for forced-colors mode, which repaints it. */
.video-facade:focus-visible { outline: 2px solid transparent; outline-offset: -4px; }
.video-facade:focus-visible::after {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  border-radius: var(--radius-card);
  box-shadow: inset 0 0 0 3px var(--accent);
}
.video-poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.video-play {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center;
  width: 74px; height: 74px; border-radius: var(--radius-pill);
  background: var(--ink); color: #fff;
  box-shadow: 0 16px 36px rgba(17, 17, 17, 0.30);
  transition: scale 0.18s var(--ease-out), box-shadow 0.18s ease;
}
.video-play svg { margin-left: 4px; }  /* optical centre of the triangle */
.video-facade:hover .video-play,
.video-facade:focus-visible .video-play { scale: 1.06; box-shadow: 0 20px 44px rgba(17, 17, 17, 0.34); }
.video-chip {
  position: absolute; right: 16px; bottom: 16px; z-index: 1;
  padding: 7px 13px; border-radius: var(--radius-pill);
  background: rgba(17, 17, 17, 0.85); color: #fff;
  font: 600 12px/1 var(--font-body);
}
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* --- Founders: plain columns, the lightest treatment on the page.
   Weight ladder, heaviest first: shadowed feature cards → bordered role
   cards → hairline columns on the tint band → these. Four card grids in
   a row is what made the page read as templated. -------------- */
.founder-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; margin-top: 32px; }
.founder-card { padding-right: 24px; }
.founder-card h3 { font-size: 1.15rem; letter-spacing: -0.02em; margin-bottom: 8px; }
.founder-card p { color: var(--ink-soft); margin: 0; }
/* Founder photos — real portraits, client-approved. 84px circular crop via
   object-fit; grayscale at rest, colour on hover. The global reduced-motion
   layer (`*, *::before, *::after { transition: none !important }`) already
   zeroes this transition, so no reduced-motion override is needed here. */
.founder-photo {
  width: 84px; height: 84px;
  border-radius: var(--radius-pill);
  object-fit: cover;
  filter: grayscale(1);
  transition: filter 0.3s var(--ease-out);
  margin-bottom: 16px;
}
.founder-card:hover .founder-photo { filter: grayscale(0); }

/* --- CTA band -------------------------------------------------- */
.cta-band {
  /* a breath of tea green in the black, so the band has depth rather than
     reading as a flat rectangle. background-color and background-image are
     split (rather than one `background` shorthand) so that if color-mix()
     or a var() substitution is invalid at computed-value time, only
     background-image is affected — background-color still paints --ink
     instead of the whole shorthand resetting to transparent. */
  background-color: var(--ink);
  background-image: radial-gradient(74% 130% at 50% 0%, color-mix(in srgb, var(--green) 18%, var(--ink)) 0%, var(--ink) 62%);
  color: #fff; text-align: center;
  border-radius: var(--radius-card); padding: clamp(40px, 6vw, 72px);
  /* same inset gutter as the brief's margin spec below ~1408px, but capped
     at 1280px so the band lines up with every other section's column once
     the viewport outgrows it (visible drift at 1600px+ otherwise). */
  width: min(1280px, calc(100% - clamp(20px, 5vw, 64px) * 2));
  margin: 0 auto 64px;
  position: relative; isolation: isolate; overflow: hidden;
}
/* the warm glow that fades in as the band enters the viewport (Step 7d).
   z-index -1 inside the isolated band: above the band's gradient, below the
   h2 and buttons. reveal.js owns the band's own opacity/transform — the glow
   animates only this pseudo's opacity/translate, so there is no conflict. */
.cta-band::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: 0;
  background: radial-gradient(60% 90% at 50% 0%, color-mix(in srgb, var(--green) 30%, transparent) 0%, transparent 70%);
}
.cta-band .hero-actions { justify-content: center; }
.btn--inverse.btn--solid { background: var(--surface); color: var(--ink); }
.btn--inverse.btn--outline { border-color: rgba(255, 255, 255, 0.4); background: transparent; color: #fff; }

/* --- Footer ------------------------------------------------- */
.site-footer { text-align: center; color: var(--ink-soft); font-size: 14px; padding: 32px 20px calc(32px + env(safe-area-inset-bottom, 0px)); }

/* --- Tap targets: bring the header/nav pill buttons to the ---
   44px minimum alongside everything else in this pass. */
.btn { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
.btn--lg { min-height: 52px; }

/* --- Scroll reveal -------------------------------------------
   .reveal-hidden is applied by reveal.js, never by this file, so with
   JavaScript off there is no hidden state to recover from. */
.reveal-hidden { opacity: 0; transform: translateY(20px); }
.reveal-hidden.reveal-in {
  opacity: 1; transform: none;
  transition: opacity 0.6s var(--ease-out), transform 0.6s var(--ease-out);
}
.feature-grid > :nth-child(2).reveal-in,
.role-grid   > :nth-child(2).reveal-in,
.benefit-grid > :nth-child(2).reveal-in,
.founder-grid > :nth-child(2).reveal-in,
.story       > :nth-child(2).reveal-in,
.how-steps   > :nth-child(2).reveal-in { transition-delay: 0.08s; }
.feature-grid > :nth-child(3).reveal-in,
.role-grid   > :nth-child(3).reveal-in,
.benefit-grid > :nth-child(3).reveal-in,
.founder-grid > :nth-child(3).reveal-in,
.how-steps   > :nth-child(3).reveal-in { transition-delay: 0.16s; }
.feature-grid > :nth-child(4).reveal-in { transition-delay: 0.24s; }

/* --- Responsive ----------------------------------------------- */
@media (max-width: 1040px) {
  .role-grid { gap: 16px; }
  .benefit { padding-right: 22px; }
  .benefit + .benefit { padding-left: 22px; }
  .feature-grid { gap: 18px; }
  .feature-card { padding: 26px 26px 28px; }
}
@media (max-width: 880px) {
  .feature-grid, .role-grid, .founder-grid { grid-template-columns: 1fr; }
  /* spans from the 12-column bento would mint implicit columns here */
  .feature-card, .feature-card--lead, .feature-card--wide { grid-column: auto; }
  .section-head--split { grid-template-columns: 1fr; gap: 0; align-items: start; }
  .section-head--split .section-intro { margin: 14px 0 0; }
  .story { grid-template-columns: 1fr; gap: 26px; }
  .story .section-intro { max-width: 60ch; }
  .how-steps { grid-template-columns: 1fr; gap: 0; border-top: none; }
  .how-step { border-top: 1px solid var(--line); padding-top: 34px; padding-bottom: 22px; }
  .how-step:last-child { padding-bottom: 0; }
  .benefit-grid { grid-template-columns: 1fr; }
  .benefit { padding-right: 0; padding-bottom: 26px; }
  .benefit + .benefit {
    border-left: none; padding-left: 0;
    border-top: 1px solid var(--line-tint); padding-top: 26px;
  }
  .benefit:last-child { padding-bottom: 0; }
}
@media (max-width: 560px) {
  .calc-token { padding: 7px 10px; font-size: 12px; }
  .video-play { width: 62px; height: 62px; }
  .video-play svg { width: 24px; height: 24px; }
  .video-chip { right: 12px; bottom: 12px; }
}

/* ============================================================
   Scroll-linked layer — one reviewable region, one deletion
   away from v2. Non-supporting browsers get today's static
   design: every base state above equals the shipped appearance.
   PATTERN INVERSION (deliberate): these declare the AT-REST
   state and animate TO the offset — the opposite of the
   entrance convention — so `animation: none` yields zero
   displacement. Longhands only: the `animation` shorthand
   would reset animation-timeline/animation-range. `linear`
   throughout: scroll IS the easing.
   ============================================================ */
@supports (animation-timeline: view()) {
  /* 7a — atmosphere: the tint wash drifts against the scroll (~7% counter-travel) */
  body::before {
    animation-name: washDrift; animation-timing-function: linear; animation-fill-mode: both;
    animation-timeline: scroll(root block);
  }
  /* 7b — header settles once you leave the hero: opaque + lifted over first 120px.
     NEVER animate padding/height — that reflows the whole document (CLS). */
  .site-header {
    animation-name: headerSettle; animation-timing-function: linear; animation-fill-mode: both;
    animation-timeline: scroll(root block); animation-range: 0 120px;
  }
  /* 7c — the how-it-works rule draws itself, threading the 1-2-3 badges.
     Desktop only: at ≤880px the steps stack and drop the shared border-top. */
  @media (min-width: 881px) {
    .how-steps::before {
      animation-name: drawRule; animation-timing-function: linear; animation-fill-mode: both;
      animation-timeline: view(block); animation-range: entry 25% cover 40%;
    }
  }
  /* 7d — the CTA band warms as you arrive.
     The timeline is NAMED on .cta-band rather than declared as `view(block)`
     on the pseudo, and that is load-bearing: `.cta-band` carries
     `overflow: hidden`, which makes it a scroll container — so for its own
     ::after it IS the nearest ancestor scroll container. An anonymous
     `view(block)` there resolves against a box that never scrolls and the
     progress freezes (measured: opacity pinned at 0.800045 at every scroll
     position, including far off-screen). Naming the timeline on the band
     resolves it against the BAND's nearest ancestor scroll container — the
     root — which is what actually scrolls. Keep the name here if the
     `overflow: hidden` stays.
     Note: `.cta-band` is the last element on the page, so `cover 60%` is not
     reachable at any tested viewport — the glow tops out near 0.61. That is
     the reviewed behaviour; do not "fix" it by retuning the range without
     asking. */
  .cta-band { view-timeline-name: --cta-view; }
  .cta-band::after {
    animation-name: ctaGlow; animation-timing-function: linear; animation-fill-mode: both;
    animation-timeline: --cta-view; animation-range: entry 20% cover 60%;
  }
}
@keyframes washDrift    { to { translate: 0 -7%; } }
@keyframes headerSettle { to { background-color: color-mix(in srgb, var(--surface) 88%, transparent); border-bottom-color: var(--line); box-shadow: var(--shadow-float); } }

/* Settled-header fallback for browsers without scroll-driven animations
   (Safari): reveal.js toggles this class past 90px of scroll. Values must
   stay identical to the headerSettle keyframe above — the background-color
   sits UNDER the header's white-fade gradient in both paths. */
.site-header--settled {
  background-color: color-mix(in srgb, var(--surface) 88%, transparent);
  border-bottom-color: var(--line);
  box-shadow: var(--shadow-float);
}
@keyframes drawRule     { to { transform: scaleX(1); } }
@keyframes ctaGlow      { to { opacity: 1; translate: 0 -6%; } }

/* ============================================================
   Scroll-aware header CTA. Hidden while the hero's own CTA row
   is on screen; appears once that row scrolls away. JS-gated
   via html.js: with JS off the button is simply always visible.
   `visibility` on the hidden state drops the button from the
   tab order and accessibility tree while keeping its box in the
   flex flow. While the slot is empty, "Log in" parks flush with
   the right edge by translating across the slot (--cta-slot is
   measured by reveal.js: button width + 12px gap); transforms
   don't relayout, so the choreography is CLS-free. Entrance is
   staged: the link glides left first, then the button drops in
   on the spring. Exit reverses fast with no delay.
   :where() pins every rule at (0,1,0) specificity so
   .btn:hover/:active keep winning; the shown-state transition
   therefore must repeat .btn's channels (scale, box-shadow) and
   add opacity — a bare `transition: opacity` would kill the
   button's hover/press feel. Under reduced motion the block
   below swaps choreography for a discrete display toggle.
   ============================================================ */
:where(html.js) .header-link {
  transition: translate 0.28s var(--ease-out);
}
:where(html.js .site-header:not(.site-header--cta)) .header-link {
  translate: var(--cta-slot, 0px) 0;
}
:where(html.js .site-header--cta) .header-cta {
  transition: opacity 0.26s var(--ease-out) 0.08s, translate 0.32s var(--ease-spring) 0.08s,
              scale 0.18s var(--ease-out), box-shadow 0.15s ease;
}
:where(html.js .site-header:not(.site-header--cta)) .header-cta {
  visibility: hidden; opacity: 0; translate: 0 -8px;
  transition: opacity 0.16s var(--ease-out), translate 0.16s var(--ease-out),
              visibility 0s linear 0.16s;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
    /* individual transform channels used by entrances/interactions — NOT
       `transform: none`, which would flatten .mock-leaf's static rotate */
    translate: none !important;
    scale: none !important;
    rotate: none !important;
  }
  .btn:hover, .feature-card:hover, .role-card:hover { transform: none; }
  /* discrete swap instead of slide choreography: the empty slot collapses,
     so "Log in" sits flush right with no translate needed */
  html.js .site-header:not(.site-header--cta) .header-cta { display: none; }
}
