/* ==========================================================================
   Custback — commercial website
   Charcoal + lime. 70% dark / 20% light / 10% lime.
   ========================================================================== */

/* ------------------------------- 1. Tokens ------------------------------- */
:root {
  /* Brand */
  --custback-charcoal: #0D1117;
  --custback-lime: #B2EA43;
  --custback-off-white: #F5F6F2;
  --custback-white: #FFFFFF;
  --custback-dark-slate: #1A2028;
  --custback-slate: #6B7280;
  --custback-body: #C5CAD1;
  --custback-muted: #8B939F;
  --custback-border: #3A414B;

  /* The eyebrow is supporting text and should read that way. In brand lime
     it shouted as loudly as the headline's punchline and flattened the
     hierarchy. Both of these sit on hue 80 with the saturation pulled down;
     which one applies is only a question of what they sit on — lighter to
     recede on the dark ground, darker to recede on the light one. */
  --eyebrow-on-dark: #C2D898;
  --eyebrow-on-light: #587819;

  /* The handset. Two sections draw a phone — the hero and the wallet
     preview — and they are meant to be the same phone. Defining the bezel
     here is what keeps them one object instead of two that drifted apart.
     Size and radius stay local: the hero's phone is smaller, and a smaller
     phone has a proportionally smaller corner. */
  /* A real handset, so the mockups read as one. Modern phones sit at about
     19.5:9 — an iPhone 15 is 2556×1179, a Pixel 8 2400×1080. The mockups were
     drawn between 1.28:1 and 1.67:1, which is nearer a small tablet, and a
     complete phone with impossible proportions is the thing the eye catches. */
  --device-ratio: 9 / 19.5;
  --device-bezel: #05080c;
  /* Near-black is right against the dark hero and too hard against the
     off-white section, where it cuts a hole in the page. Same phone, one
     step of relief for the ground it sits on. */
  --device-bezel-soft: #11161c;
  --device-bezel-width: 0.5rem;
  --device-screen: #f5f6f2;
  --device-cam: #1a2028;

  /* Surfaces derived from the brand palette */
  --surface: var(--custback-charcoal);
  --surface-raised: var(--custback-dark-slate);
  --surface-sunken: #0A0E13;
  --hairline: rgba(255, 255, 255, 0.08);
  --hairline-strong: rgba(255, 255, 255, 0.14);

  /* Type */
  --font: "Satoshi", "Inter", "Geist", "Manrope", -apple-system, BlinkMacSystemFont,
    "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* Rhythm */
  --container: 1180px;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --section-y: clamp(5rem, 9vw, 8.5rem);

  /* Shape */
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 24px;
  --r-xl: 32px;

  /* Depth */
  --shadow-card: 0 24px 60px -30px rgba(0, 0, 0, 0.85);
  --shadow-float: 0 40px 80px -40px rgba(0, 0, 0, 0.9);
  --glow-lime: 0 0 0 1px rgba(178, 234, 67, 0.35), 0 18px 50px -22px rgba(178, 234, 67, 0.55);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ------------------------------- 2. Base --------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 96px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--custback-body);
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  margin: 0;
  color: var(--custback-white);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.08;
}

p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img, svg { max-width: 100%; }
img { height: auto; display: block; }
b, strong { font-weight: 600; }
blockquote { margin: 0; }

a {
  color: var(--custback-white);
  text-decoration: none;
  transition: color 0.2s var(--ease);
}
a:hover { color: var(--custback-lime); }

:focus-visible {
  outline: 2px solid var(--custback-lime);
  outline-offset: 3px;
  border-radius: 4px;
}

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.text-lime { color: var(--custback-lime); }

.skip-link {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 200;
  padding: 0.75rem 1.25rem;
  border-radius: var(--r-sm);
  background: var(--custback-lime);
  color: var(--custback-charcoal);
  font-weight: 600;
  transition: top 0.2s var(--ease);
}
.skip-link:focus { top: 1rem; color: var(--custback-charcoal); }

.eyebrow {
  margin-bottom: 1rem;
  color: var(--eyebrow-on-dark);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.note {
  color: var(--custback-muted);
  font-size: 0.9375rem;
}

/* ----------------------------- 3. Wordmark ------------------------------- */
.wordmark {
  display: inline-flex;
  align-items: center;
}
.wordmark img {
  display: block;
  height: 1.5rem;
  width: auto;
}
.wordmark:hover { color: var(--custback-white); }
.wordmark__accent { color: var(--custback-lime); }

/* ------------------------------ 4. Buttons ------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.625rem 1.125rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
  cursor: pointer;
  transition: transform 0.2s var(--ease), background-color 0.2s var(--ease),
    border-color 0.2s var(--ease), color 0.2s var(--ease), box-shadow 0.25s var(--ease);
}
.btn--lg { padding: 0.9rem 1.6rem; font-size: 1rem; }

.btn--primary {
  background: var(--custback-lime);
  color: var(--custback-charcoal);
}
.btn--primary:hover {
  color: var(--custback-charcoal);
  transform: translateY(-2px);
  box-shadow: var(--glow-lime);
}

.btn--outline {
  border-color: var(--custback-border);
  background: rgba(255, 255, 255, 0.02);
  color: var(--custback-white);
}
.btn--outline:hover {
  border-color: var(--custback-lime);
  color: var(--custback-white);
  transform: translateY(-2px);
}

.btn--ghost { color: var(--custback-body); }
.btn--ghost:hover { color: var(--custback-white); }

.arrow {
  display: inline-block;
  transition: transform 0.2s var(--ease);
}
.btn:hover .arrow { transform: translateX(3px); }

/* ---------------------------- 5. Navigation ------------------------------ */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  border-bottom: 1px solid transparent;
  transition: background-color 0.3s var(--ease), border-color 0.3s var(--ease);
}
.nav.is-scrolled {
  border-bottom-color: var(--hairline);
  background: rgba(13, 17, 23, 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.nav__inner {
  display: flex;
  align-items: center;
  gap: 2rem;
  height: 72px;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: 1.75rem;
  margin-inline: auto;
}
.nav__links a {
  color: var(--custback-body);
  font-size: 0.9375rem;
  font-weight: 500;
}
.nav__links a:hover,
.nav__links a.is-active { color: var(--custback-white); }
.nav__links a.is-active { text-shadow: 0 0 24px rgba(178, 234, 67, 0.4); }

.nav__actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.nav__toggle {
  display: none;
  width: 42px;
  height: 42px;
  padding: 0;
  border: 1px solid var(--custback-border);
  border-radius: 12px;
  background: transparent;
  cursor: pointer;
}
.nav__toggle span {
  display: block;
  width: 18px;
  height: 1.5px;
  margin: 3.5px auto;
  background: var(--custback-white);
  transition: transform 0.25s var(--ease), opacity 0.2s var(--ease);
}
.nav__toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/* ------------------------------- 6. Hero --------------------------------- */
.hero {
  position: relative;
  padding: clamp(3.5rem, 7vw, 6rem) 0 clamp(4rem, 8vw, 7rem);
  overflow: hidden;
}
.hero__glow {
  position: absolute;
  inset: -30% 0 auto -10%;
  height: 720px;
  background:
    radial-gradient(46% 52% at 22% 32%, rgba(178, 234, 67, 0.16), transparent 70%),
    radial-gradient(40% 46% at 78% 12%, rgba(120, 170, 255, 0.08), transparent 70%);
  pointer-events: none;
}

.hero__inner {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 4rem);
}

.hero__title {
  font-size: clamp(2.75rem, 6.2vw, 4.5rem);
  letter-spacing: -0.045em;
  line-height: 1.02;
}
.hero__sub {
  max-width: 30rem;
  margin-top: 1.5rem;
  font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
  color: var(--custback-body);
}
.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.875rem;
  margin-top: 2.25rem;
}

/* Card fan ---------------------------------------------------------------- */
.hero__stage { position: relative; }
.cardfan {
  position: relative;
  height: 620px;
}
/* The hero cards are Card design's own "In wallet" export — handset, Google
   Wallet header and all — so they are positioned like the phones they replace
   and given no frame of their own. Same offsets, same tilt, same float: what
   changed is that the picture is now the product's rather than a rebuild of
   it in CSS. */
.cardshot {
  position: absolute;
  height: auto;
  filter: drop-shadow(0 1.75rem 3.5rem rgba(0, 0, 0, 0.55));
  animation: float 7s ease-in-out infinite;
}
/* Narrower than the phones they replace, because these are a real handset's
   proportions rather than the squat frame the preview panel renders at, and a
   620x1345 picture at the old width would have run off the bottom of the
   stage. */
.cardshot--lead {
  width: 232px;
  top: 4px;
  right: 14px;
  transform: rotate(-4deg);
  z-index: 2;
}
.cardshot--behind {
  width: 186px;
  top: 190px;
  left: 6px;
  transform: rotate(6deg);
  z-index: 1;
  opacity: 0.92;
  animation-delay: -2.6s;
}

.cardfan .lcard {
  position: absolute;
  animation: float 7s ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * -2.2s);
}
/* Cards cascade downwards, each one overlapping only the footer edge of the
   card above it — so every merchant name stays readable. */
/* Direct children only.
   These place a fan of loose cards, which is what the stage used to hold. It
   holds phones now, and the card inside one is the second child of its screen
   — so `.cardfan .lcard:nth-child(2)` was reaching through the handset and
   rotating the card 4 degrees against a frame tilted 4 the other way. Eight
   degrees out, inside its own phone. The child combinator keeps these to the
   fan they were written for. */
.cardfan > .lcard:nth-child(1) { top: 0; left: 0; transform: rotate(-6deg); z-index: 1; }
.cardfan > .lcard:nth-child(2) { top: 176px; left: 46%; transform: rotate(4deg); z-index: 2; }
.cardfan > .lcard:nth-child(3) { top: 398px; left: 4%; transform: rotate(-2deg); z-index: 3; }

@keyframes float {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -12px; }
}

/* Floating activity pills ------------------------------------------------- */
.events { position: absolute; inset: 0; z-index: 4; pointer-events: none; }
.event {
  position: absolute;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.85rem;
  border: 1px solid var(--hairline-strong);
  border-radius: 999px;
  background: rgba(26, 32, 40, 0.9);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: var(--shadow-card);
  color: var(--custback-white);
  font-size: 0.8125rem;
  font-weight: 500;
  white-space: nowrap;
  animation: float 8s ease-in-out infinite;
}
.event .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--custback-lime);
  box-shadow: 0 0 0 4px rgba(178, 234, 67, 0.18);
}
.event--1 { top: 12px; right: 4%; animation-delay: -1s; }
.event--2 { top: 118px; right: -3%; animation-delay: -3s; }
.event--3 { bottom: 150px; right: 1%; animation-delay: -5s; }

/* --------------------------- 7. Loyalty cards ----------------------------
   The card belongs to the merchant: their name is the loudest thing on it,
   then the stamps, then the progress line. Custback signs it at the bottom.
   ------------------------------------------------------------------------ */
.lcard {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  width: 300px;
  min-height: 186px;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--hairline-strong);
  border-radius: 20px;
  box-shadow: var(--shadow-float);
  color: var(--custback-white);
  overflow: hidden;
  isolation: isolate;
}
.lcard::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(120% 80% at 12% 0%, rgba(255, 255, 255, 0.22), transparent 55%);
  pointer-events: none;
}
/* Merchant palettes — swap these for the merchant's own colours. */
.lcard--cafe { background: linear-gradient(150deg, #2B1B10, #6B4326); }
.lcard--retail { background: linear-gradient(150deg, #10161F, #263449); }

.lcard__head { display: flex; flex-direction: column; gap: 0.2rem; }
.lcard__brand {
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  line-height: 1.15;
}
.lcard__type {
  color: rgba(255, 255, 255, 0.6);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.lcard__stamps { display: flex; flex-wrap: wrap; gap: 5px; margin-top: auto; }
.lcard__stamps i {
  width: 16px;
  height: 16px;
  border: 1.5px solid rgba(255, 255, 255, 0.38);
  border-radius: 50%;
}
.lcard__stamps i.on {
  border-color: rgba(255, 255, 255, 0.92);
  background: rgba(255, 255, 255, 0.92);
}

.lcard__count { font-size: 0.9375rem; font-weight: 600; letter-spacing: -0.01em; }

/* Completed card — the one moment the card borrows Custback lime. */
.lcard--complete .lcard__stamps i.on {
  border-color: var(--custback-lime);
  background: var(--custback-lime);
}
.lcard--complete .lcard__count { color: var(--custback-lime); }

.tilt { transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease); }

/* ------------------------------ 8. Trust --------------------------------- */
.trust {
  padding: 2.5rem 0 3.5rem;
  border-block: 1px solid var(--hairline);
  background: var(--surface-sunken);
}
.trust__label {
  text-align: center;
  color: var(--custback-muted);
  font-size: 0.9375rem;
}
.trust__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(1.5rem, 5vw, 3.5rem);
  margin-top: 1.75rem;
  color: var(--custback-body);
  font-size: clamp(1rem, 1.6vw, 1.25rem);
  font-weight: 500;
  letter-spacing: -0.01em;
}
.trust__row li { position: relative; }
.trust__row li::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -8px;
  height: 1px;
  background: var(--custback-lime);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.4s var(--ease);
}
.trust__row li:hover::after { transform: scaleX(1); }

/* ----------------------------- 9. Sections ------------------------------- */
.section { padding-block: var(--section-y); }
.section--tight { padding-block: clamp(3rem, 5vw, 4.5rem); }

.section--light {
  background: var(--custback-off-white);
  color: #454C56;
}
.section--light h1, .section--light h2, .section--light h3 { color: #11161C; }
.section--light .eyebrow { color: var(--eyebrow-on-light); }
.section--light .section__sub { color: #545B65; }
.section--light .note { color: #6B7280; }

.section__head {
  max-width: 46rem;
  margin-bottom: clamp(2.5rem, 5vw, 4rem);
}
.section__title {
  font-size: clamp(2rem, 3.8vw, 3.1rem);
  letter-spacing: -0.04em;
}
.section__sub {
  margin-top: 1.125rem;
  max-width: 42rem;
  font-size: clamp(1rem, 1.3vw, 1.125rem);
  color: var(--custback-body);
}

.grid { display: grid; gap: clamp(1.25rem, 2.5vw, 1.75rem); }

/* Pillars ----------------------------------------------------------------- */

/* --------------------------- 10. How it works ---------------------------- */
.step {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 4.5rem);
  padding-block: clamp(2rem, 4vw, 3.5rem);
}
.step + .step { border-top: 1px solid var(--hairline); }

.phone {
  position: relative;
  width: 268px;
  padding: 12px;
  border: 1px solid var(--custback-border);
  border-radius: 34px;
  background: linear-gradient(180deg, #161C24, #0E1319);
  box-shadow: var(--shadow-float);
}

.panel {
  padding: 1.5rem;
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0)),
    var(--surface-raised);
  box-shadow: var(--shadow-card);
}
.earn { width: min(380px, 100%); }
.earn .lcard__stamps { margin-top: 1rem; }

/* ----------------------------- 11. Return -------------------------------- */

.flow {
  display: grid;
  gap: 0;
  max-width: 34rem;
  margin-inline: auto;
  width: 100%;
}

/* --------------------------- 12. Brand wall ------------------------------ */

/* ----------------------------- 13. Journey ------------------------------- */
.section--journey { border-top: 1px solid var(--hairline); }

/* --------------------------- 14. Integrations ---------------------------- */

/* ----------------------------- 15. Pricing ------------------------------- */
.pricing {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(1.5rem, 4vw, 3rem);
  padding: clamp(1.75rem, 4vw, 2.75rem);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  background:
    radial-gradient(80% 120% at 100% 0%, rgba(178, 234, 67, 0.08), transparent 60%),
    var(--surface-raised);
}
.pricing .section__sub { margin-top: 0.9rem; }

/* ------------------------------- 16. CTA --------------------------------- */
.cta {
  position: relative;
  padding-block: clamp(5rem, 10vw, 9rem);
  border-top: 1px solid var(--hairline);
  overflow: hidden;
  text-align: center;
}
.cta__glow {
  position: absolute;
  inset: auto 0 -60% 0;
  height: 620px;
  background: radial-gradient(45% 60% at 50% 50%, rgba(178, 234, 67, 0.16), transparent 70%);
  pointer-events: none;
}
.cta__inner { position: relative; }
.cta__title {
  font-size: clamp(2.1rem, 5vw, 3.75rem);
  letter-spacing: -0.045em;
}
.cta__sub {
  margin-top: 1.25rem;
  font-size: clamp(1rem, 1.5vw, 1.25rem);
}
.cta__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.875rem;
  margin-top: 2.25rem;
}

/* ------------------------------ 17. Footer ------------------------------- */
.footer {
  padding-top: clamp(3rem, 6vw, 4.5rem);
  border-top: 1px solid var(--hairline);
  background: var(--surface-sunken);
}
.footer__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2.2fr);
  gap: clamp(2rem, 5vw, 4rem);
  padding-bottom: 3rem;
}
.footer__brand p { margin-top: 1rem; color: var(--custback-muted); font-size: 0.9375rem; }
.footer__cols {
  display: grid;
  /* Three, since Solutions went: five links to one anchor was a menu where
     every door opened on the same room. A fourth empty track left the columns
     bunched against the left with a hole where the fifth choice used to be. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2rem;
}
.footer__cols h2 {
  margin-bottom: 1rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--custback-muted);
}
.footer__cols ul { display: grid; gap: 0.6rem; }
.footer__cols a { color: var(--custback-body); font-size: 0.9375rem; }
.footer__base {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.5rem;
  border-top: 1px solid var(--hairline);
  color: var(--custback-muted);
  font-size: 0.8125rem;
}

/* --------------------------- 18. Scroll reveal --------------------------- */
.js .reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}
.js .reveal.is-visible { opacity: 1; transform: none; }

/* --------------------------- 19. Responsive ------------------------------ */

@media (max-width: 960px) {
  .nav__links {
    position: absolute;
    left: 0;
    right: 0;
    top: 72px;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin: 0;
    padding: 0.5rem var(--gutter) 1.25rem;
    border-bottom: 1px solid var(--hairline);
    background: rgba(13, 17, 23, 0.98);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
  }
  .nav__links.is-open { display: flex; }
  .nav__links a { padding: 0.85rem 0; border-bottom: 1px solid var(--hairline); font-size: 1rem; }
  .nav__toggle { display: block; margin-left: auto; }
  .nav__actions { display: none; }

  .hero__inner { grid-template-columns: minmax(0, 1fr); }
  .hero__stage { margin-top: 1rem; }
  .cardfan { height: auto; display: flex; flex-direction: column; align-items: center; gap: 1rem; }
  .cardfan .lcard,
  .cardfan .lcard:nth-child(1),
  .cardfan .lcard:nth-child(2),
  .cardfan .lcard:nth-child(3),
  .cardshot,
  .cardshot--lead,
  .cardshot--behind {
    position: static;
    transform: none;
    width: min(340px, 100%);
    animation: none;
  }
  /* Stacked rather than fanned at this width, so the second one is a second
     card rather than something half behind the first. Both at full opacity:
     the one behind was dimmed to sit back in the fan, and there is no fan. */
  .cardshot--behind { opacity: 1; }
  .events { position: static; display: flex; flex-wrap: wrap; justify-content: center; gap: 0.6rem; margin-top: 1.5rem; }
  .event { position: static; animation: none; }

  .step { grid-template-columns: minmax(0, 1fr); order: 0; }
  .step { gap: 2rem; }

  .pricing { grid-template-columns: minmax(0, 1fr); }

  .footer__inner { grid-template-columns: minmax(0, 1fr); }
  .footer__cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 640px) {
  .hero__cta .btn, .cta__actions .btn { flex: 1 1 100%; }
  .trust__row { gap: 1rem 1.5rem; }
  .flow { max-width: none; }
}

/* --------------------------- 20. Reduced motion -------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .js .reveal { opacity: 1; transform: none; }
}

/* ------------------------------- 21. Print ------------------------------- */
@media print {
  .nav, .hero__glow, .cta__glow, .events { display: none; }
  body { background: #fff; color: #000; }
}

/* --------------------------- Start form ---------------------------------
   The primary action is one field and one button. A shop owner reading this
   on a phone between customers should be able to start without a call, so
   the address they type here travels to the sign-up page with them. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

/* ------------------------- Security & FAQ -------------------------------
   Both are read by someone deciding whether to trust this with their
   customers, so they favour legibility over density. */
.security-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}
.security-grid li {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.375rem 1.5rem;
  border: 1px solid var(--custback-border, #3a414b);
  border-radius: 1rem;
  background: rgba(255, 255, 255, 0.02);
}
.security-grid strong {
  color: var(--custback-white, #fff);
  font-size: 1rem;
  font-weight: 600;
}
.security-grid span {
  color: #c5cad1;
  font-size: 0.9375rem;
  line-height: 1.6;
}

.faq-list {
  display: grid;
  gap: 0.625rem;
  max-width: 46rem;
}
.faq-list details {
  border: 1px solid var(--custback-border, #3a414b);
  border-radius: 0.875rem;
  background: rgba(255, 255, 255, 0.02);
  overflow: hidden;
}
.faq-list summary {
  cursor: pointer;
  padding: 1.0625rem 1.25rem;
  color: var(--custback-white, #fff);
  font-weight: 600;
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  align-items: center;
}
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary::after {
  content: "+";
  color: var(--custback-lime, #b2ea43);
  font-size: 1.25rem;
  line-height: 1;
  flex: 0 0 auto;
}
.faq-list details[open] summary::after { content: "\2013"; }
.faq-list summary:hover { background: rgba(255, 255, 255, 0.03); }
.faq-list summary:focus-visible {
  outline: 2px solid var(--custback-lime, #b2ea43);
  outline-offset: -2px;
}
.faq-list details p {
  margin: 0;
  padding: 0 1.25rem 1.25rem;
  color: #c5cad1;
  font-size: 0.9375rem;
  line-height: 1.65;
}

.text-link {
  display: inline-block;
  margin-top: 1.75rem;
  color: var(--custback-lime, #b2ea43);
  font-weight: 600;
  text-decoration: none;
}
.text-link:hover { text-decoration: underline; }

/* The FAQ sits on the off-white section, where white type on a dark panel is
   invisible. Same component, inverted for its ground. */
.section--light .faq-list details {
  border-color: #dcded8;
  background: #ffffff;
}
.section--light .faq-list summary { color: #11161c; }
.section--light .faq-list summary:hover { background: #f7f8f4; }
.section--light .faq-list summary::after { color: #5c7c1e; }
.section--light .faq-list details p { color: #454c56; }
.section--light .text-link { color: #5c7c1e; }

/* ------------------------- Integration status ---------------------------
   A roadmap item and a shipping one must not look the same. Lime is reserved
   for what actually works today. */

/* An anchored section landing under the fixed navigation reads as a broken link. */
section[id] { scroll-margin-top: 5rem; }

/* ---------------------------- Security page -----------------------------
   Long-form and meant to be read closely, so it is a single column at a
   comfortable measure rather than a grid of cards. */

/* ---------------------------- Comparison --------------------------------
   A comparison is only worth reading if the alternatives are described
   fairly, so the highlight on our column stays modest: a tint, a rule and a
   word. The word matters — colour alone leaves the emphasis invisible to
   anyone who cannot see it. */
.comparison__scroll {
  overflow-x: auto;
  border-radius: 1.25rem;
  border: 1px solid var(--custback-border, #3a414b);
  -webkit-overflow-scrolling: touch;

  /*
   * Scroll shadows. Two fixed panels give the base tint, two scrolling
   * gradients sit on top of them — so the shading only shows on a side that
   * has more table behind it, and fades out on its own at either end. No
   * JavaScript, and nothing to keep in sync with the scroll position.
   */
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0.01)) local,
    linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0.01)) local,
    radial-gradient(farthest-side at 0 50%, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0)) scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0)) scroll;
  background-position: 0 0, 100% 0, 0 0, 100% 0;
  background-size: 100% 100%, 100% 100%, 1.75rem 100%, 1.75rem 100%;
  background-repeat: no-repeat;
}
.comparison__scroll:focus-visible {
  outline: 2px solid var(--custback-lime, #b2ea43);
  outline-offset: 2px;
}

.comparison__table {
  width: 100%;
  min-width: 52rem;
  border-collapse: collapse;
  font-size: 0.9375rem;
}
.comparison__table th,
.comparison__table td {
  padding: 0.9375rem 1.125rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
.comparison__table tbody tr:last-child th,
.comparison__table tbody tr:last-child td { border-bottom: 0; }

.comparison__table thead th {
  position: sticky;
  top: 0;
  background: #151b23;
  color: var(--custback-white, #fff);
  font-weight: 600;
  white-space: nowrap;
  z-index: 2;
}

/* The row label stays put while the alternatives scroll past it. */
.comparison__table tbody th[scope="row"] {
  position: sticky;
  left: 0;
  background: #131920;
  color: var(--custback-white, #fff);
  font-weight: 500;
  white-space: nowrap;
  z-index: 1;
}
.comparison__table td { color: #c5cad1; }

.comparison__table .comparison__custback {
  background: rgba(178, 234, 67, 0.07);
  color: #e9f6d2;
}
.comparison__table thead .comparison__custback {
  background: #1b2418;
  box-shadow: inset 0 3px 0 var(--custback-lime, #b2ea43);
}
.comparison__brand { display: block; color: var(--custback-lime, #b2ea43); }
.comparison__recommended {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #9fb87a;
}
.comparison__positive { color: var(--custback-lime, #b2ea43); margin-right: 0.25rem; }

.comparison__note {
  margin-top: 1rem;
  max-width: 46rem;
  color: #8b939f;
  font-size: 0.8125rem;
  line-height: 1.6;
}

.comparison__cta {
  margin-top: 2.5rem;
  padding: 2rem;
  border: 1px solid var(--custback-border, #3a414b);
  border-radius: 1.25rem;
  background: rgba(255, 255, 255, 0.02);
}
.comparison__cta h3 {
  margin: 0.25rem 0 1.5rem;
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--custback-white, #fff);
}
.comparison__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }

@media (max-width: 40rem) {
  .comparison__actions { flex-direction: column; }
  .comparison__actions .btn { width: 100%; }
  .comparison__cta { padding: 1.5rem; }
}

/* -------------------------- Wallet preview -------------------------------
   Four steps beside one phone. The phone never moves between steps — only
   what is on its screen — because the point being made is that all of this
   happens in the same place the customer already keeps their cards. */
.wp {
  display: grid;
  gap: 3rem;
  grid-template-columns: 45fr 55fr;
  align-items: start;
}

.wp__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.75rem; }
.wp__assurance { margin-top: 0.875rem; font-size: 0.8125rem; color: #8b939f; }

/* ---- the device ---- */
.wp__device { display: flex; flex-direction: column; align-items: center; gap: 1rem; }
.wp__phone {
  position: relative;
  width: 20rem;
  max-width: 100%;
  aspect-ratio: 9 / 15;
  padding: 0.75rem;
  border: var(--device-bezel-width) solid var(--device-bezel);
  border-radius: 2.5rem;
  /* Cropped, and drawn so it reads as cropped.
     A phone beside a column of text cannot be shown whole without leaving
     most of the screen empty, so only its top is here. That only works if the
     bottom leaves the frame: with a bezel and four rounded corners it read as
     a whole phone of the wrong shape, which is what made these look off. */
  border-bottom: 0;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  background: var(--device-screen);
  box-shadow:
    0 2rem 4rem rgba(0, 0, 0, 0.55),
    0 0 5rem rgba(178, 234, 67, 0.09);
  overflow: hidden;
}
.wp__notch {
  position: absolute;
  top: 0.55rem;
  left: 50%;
  transform: translateX(-50%);
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--device-bezel);
}
.wp__bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 1.25rem 0.25rem 0.875rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: #454c56;
}
.wp__gmark {
  width: 0.875rem;
  height: 0.875rem;
  border-radius: 0.25rem;
  background: linear-gradient(135deg, #4285f4 0 50%, #34a853 50% 100%);
}

/* The panels now hold pictures of the product rather than a rebuild of it, so
   the phone that used to be drawn here in CSS is gone: the handset is part of
   the Card design export. What is left is sizing — one width for the card
   shots, a wider one for the printed sheet, which is landscape-ish next to a
   phone and would look tiny at the same width. */
.wp__shot {
  display: block;
  width: 16rem;
  max-width: 100%;
  height: auto;
  margin: 0 auto;
  filter: drop-shadow(0 1.5rem 3rem rgba(0, 0, 0, 0.22));
}
.wp__shot--poster {
  width: 19rem;
  border-radius: 0.5rem;
}

.wp__panel { animation: wpIn 0.24s var(--ease) both; }
@keyframes wpIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.wp__panel:focus-visible { outline: 2px solid var(--custback-lime, #b2ea43); outline-offset: 2px; }

.wp__screen { display: flex; flex-direction: column; gap: 0.75rem; }
.wp__screen-title { margin: 0; font-size: 1.0625rem; font-weight: 700; color: #11161c; text-align: center; }
.wp__screen-sub { margin: 0; font-size: 0.8125rem; color: #545b65; text-align: center; }
.wp__screen-note { margin: 0; font-size: 0.75rem; color: #6b7280; text-align: center; }

.wp__scanframe {
  display: grid;
  place-items: center;
  margin: 0.5rem auto 0.25rem;
  width: 8.5rem;
  height: 8.5rem;
  border: 2px solid #11161c;
  border-radius: 1rem;
  background: #e9ebe4;
}
.wp__qr {
  width: 5rem; height: 5rem;
  background:
    repeating-linear-gradient(90deg, #11161c 0 12%, transparent 12% 20%),
    repeating-linear-gradient(0deg, #11161c 0 12%, transparent 12% 20%);
  background-color: #e9ebe4;
}
.wp__gbtn {
  align-self: center;
  padding: 0.5rem 1rem;
  border-radius: 999px;
  background: #11161c;
  color: #fff;
  font-size: 0.75rem;
  font-weight: 600;
}

.wp__wcard {
  padding: 1rem;
  border-radius: 1rem;
  background: #1a2028;
  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.18);
}
.wp__wcard-brand { margin: 0; font-size: 0.9375rem; font-weight: 700; color: #fff; }
.wp__wcard-reward { margin: 0.125rem 0 0.75rem; font-size: 0.75rem; color: #c5cad1; }
.wp__wcard-count { margin: 0.625rem 0 0; font-size: 0.75rem; color: #c5cad1; }
.wp__wcard-unlocked { margin: 0.5rem 0 0; font-size: 0.8125rem; font-weight: 700; color: var(--custback-lime, #b2ea43); }
.wp__wcard.is-complete { box-shadow: 0 0 0 2px var(--custback-lime, #b2ea43), 0 0.5rem 1rem rgba(0, 0, 0, 0.18); }

.wp__stamps {
  /* Five and five, like the pass and like the hero. Wrapping by width put
     seven on one row and three on the next, which is a card nobody receives. */
  display: grid;
  grid-template-columns: repeat(5, auto);
  justify-content: space-between;
  gap: 0.5rem;
}
.wp__stamp {
  width: 0.9375rem; height: 0.9375rem;
  border-radius: 50%;
  border: 1px dashed #4a525d;
}
.wp__stamp.on { background: var(--custback-lime, #b2ea43); border-color: transparent; }
.wp__stamp.is-new { animation: wpStamp 0.42s var(--ease) both; }
@keyframes wpStamp { from { transform: scale(0.3); opacity: 0; } 60% { transform: scale(1.18); } to { transform: none; opacity: 1; } }

.wp__callout {
  display: flex; align-items: center; justify-content: center; gap: 0.4375rem;
  margin: 0.875rem 0 0;
  font-size: 0.75rem; font-weight: 600; color: #454c56;
}
.wp__dot { width: 0.4375rem; height: 0.4375rem; border-radius: 50%; background: var(--custback-lime, #b2ea43); }
.wp__panel .wp__wcard.is-complete { animation: wpPulse 0.9s var(--ease) 1; }
@keyframes wpPulse { 0%,100% { box-shadow: 0 0 0 2px var(--custback-lime, #b2ea43), 0 0.5rem 1rem rgba(0,0,0,0.18); } 50% { box-shadow: 0 0 0 6px rgba(178,234,67,0.35), 0 0.5rem 1rem rgba(0,0,0,0.18); } }

.wp__platform { margin: 0; font-size: 0.8125rem; color: #8b939f; text-align: center; }

@media (max-width: 60rem) {
  .wp { grid-template-columns: 1fr; gap: 2rem; }
  /* Phone first on a narrow screen: the picture explains faster than the list. */
  .wp__device { order: -1; }
  .wp__phone { width: 18rem; }
  .wp__actions { flex-direction: column; }
  .wp__actions .btn { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .wp__panel, .wp__stamp.is-new, .wp__panel .wp__wcard.is-complete { animation: none; }
}

/* The sixth stamp starts empty and fills when the step is opened, so the
   visitor watches five become six rather than being told that it did. */
.wp__stamp--sixth { background: transparent; border: 1px dashed #4a525d; }
.wp__panel.is-stamped .wp__stamp--sixth {
  background: var(--custback-lime, #b2ea43);
  border-color: transparent;
  animation: wpStamp 0.42s var(--ease) both;
}

/* The count changes in the same instant the stamp lands. Swapped in silence
   it reads as a typo you half-noticed; lifted, it reads as the number going
   up, which is the only thing the customer cares about. */
.wp__panel.is-stamped .wp__wcard-count,
.wp__panel.is-stamped .wp__screen-note {
  animation: wpTally 0.42s var(--ease) both;
}
@keyframes wpTally {
  from { transform: translateY(0.375rem); opacity: 0; }
  to { transform: none; opacity: 1; }
}

.wp__sub-minor { margin-top: 0.5rem; font-size: 0.875rem; color: #8b939f; }

@media (prefers-reduced-motion: reduce) {
  .wp__panel.is-stamped .wp__stamp--sixth,
  .wp__panel.is-stamped .wp__wcard-count,
  .wp__panel.is-stamped .wp__screen-note { animation: none; }
}

/* --------------------------- Hero phones --------------------------------
   A phone is portrait, and the previous attempt was not: wrapping a landscape
   card in padding produced a squat white box that read as a box. These have
   the proportions of an actual handset, and the card is sized to the screen
   rather than the screen to the card.

   Two of them, not three: one leading, one behind and smaller, so the eye is
   told where to look. The frame stays nobody's phone in particular. */
.hphone {
  position: absolute;
  /* Whole handsets, floating in open space, so they have to be the right
     shape — there is no frame here for a crop to read against. Width came
     down instead, which keeps them inside the stage at the true ratio. */
  aspect-ratio: var(--device-ratio);
  padding: 0.5rem;
  border: var(--device-bezel-width) solid var(--device-bezel);
  border-radius: 2.25rem;
  background: var(--device-bezel);
  box-shadow:
    0 1.75rem 3.5rem rgba(0, 0, 0, 0.6),
    0 0 4rem rgba(178, 234, 67, 0.07);
  animation: float 7s ease-in-out infinite;
}
.hphone--lead {
  width: 244px;
  top: 16px;
  right: 22px;
  transform: rotate(-4deg);
  z-index: 2;
}
.hphone--behind {
  width: 188px;
  top: 214px;
  left: 0;
  transform: rotate(6deg);
  z-index: 1;
  opacity: 0.9;
  animation-delay: -2.6s;
}

.hphone__cam {
  position: absolute;
  top: 0.5rem;
  left: 50%;
  transform: translateX(-50%);
  width: 0.375rem;
  height: 0.375rem;
  border-radius: 50%;
  background: var(--device-cam);
  z-index: 2;
}
.hphone__screen {
  height: 100%;
  /* The card sits in the middle of the screen, not at the top.
     At a real handset's height there is more screen than card, and a card
     pinned under the status bar left all of that emptiness in one slab at the
     bottom — which reads as a screenshot that failed to load rather than as a
     wallet with one pass in it. The auto margins below split the free space. */
  display: flex;
  flex-direction: column;
  padding: 1.375rem 0.5rem 0.5rem;
  border-radius: 1.75rem;
  background: var(--device-screen);
  overflow: hidden;
}
.hphone__wallet {
  margin: 0 0 0.5rem;
  padding-left: 0.375rem;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #8b939f;
}

/* The card fills the screen's width and keeps its own proportions. */
.hphone .lcard {
  position: static;
  width: 100%;
  min-height: 0;
  margin: auto 0 0;
  padding: 0.75rem 0.8rem;
  border-radius: 14px;
  transform: none;
  animation: none;
  gap: 0.4rem;
}
.hphone .lcard__brand { font-size: 0.8125rem; }
.hphone .lcard__type { font-size: 0.5rem; }
.hphone .lcard__stamps { gap: 4px; }
.hphone .lcard__stamps i { width: 22px; height: 22px; }
.hphone .lcard__count { font-size: 0.75rem; }
.hphone--behind .lcard__brand { font-size: 0.6875rem; }
.hphone--behind .lcard__stamps i { width: 19px; height: 19px; }

/* The code the customer shows at the counter. On the real pass it sits under
   the stamps, so it sits there here too. */
.lcard__code {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  justify-content: center;
  margin-top: 0.45rem;
}
/* A real code, generated from the site's own URL rather than drawn to look
   like one — which is why it has finder squares in the corners and scans.
   Dark modules on a white plate, never the reverse: an inverted code with no
   quiet zone around it is refused outright by a good part of the scanners in
   circulation, and the picture on this page should not teach a habit that
   fails at a counter. */
.lcard__qr {
  flex: 0 0 auto;
  width: 54px;
  height: 54px;
  display: block;
  padding: 3px;
  border-radius: 4px;
  background: #fff;
}
.hphone--behind .lcard__qr { width: 44px; height: 44px; }

/* The mark a merchant picks for their stamps, drawn from the same paths the
   product uses on the real pass — so the picture and the card agree. */
.hphone .lcard__stamps i {
  display: grid;
  place-items: center;
  border: 1px dashed rgba(255, 255, 255, 0.34);
  background: none;
}
.hphone .lcard__stamps i svg {
  width: 68%;
  height: 68%;
  fill: none;
  stroke: rgba(255, 255, 255, 0.42);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* A solid disc, because that is what the pass draws — the mark is knocked
   out of white rather than laid on a wash of it. The wash was close
   enough while every mark was a white line; a mark with its own dark
   outline sinks into it. */
.hphone .lcard__stamps i.on { border-color: transparent; background: #fff; }
.hphone .lcard__stamps i.on svg { stroke: #fff; }

/* A merchant's own mark, which is what the product now lets them upload. Same
   rule as the real pass: one image, faded when the stamp is not yet collected
   and full colour when it is — so the picture on this page and the card in a
   customer's pocket say the same thing the same way. */
.hphone .lcard__stamps i { overflow: hidden; }
/* Only an uploaded mark loses its ring; a drawn one keeps the dashed outline
   that tells an empty stamp from a collected one. */
.hphone .lcard__stamps i:has(img) { border: none; background: none; }
.hphone .lcard__stamps i img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* Not yet collected: the shape stays legible but the colour drains out, so a
     customer reads progress at a glance instead of comparing two brightnesses
     of the same brown. */
  filter: grayscale(1) brightness(1.7);
  opacity: 0.4;
}
/* Scoped to images. Written inside this block and meant for them, but it
   matched every collected stamp — invisible while the drawn marks had no
   disc to lose. */
.hphone .lcard__stamps i.on:has(img) { background: none; }
.hphone .lcard__stamps i.on img { filter: none; opacity: 1; }

/* Five and five, the way the real pass lays out ten — the renderer splits into
   two rows past five stamps, so a single long row here would show a card the
   customer never receives. */
.hphone .lcard__stamps {
  display: grid;
  /* Columns sized to the marks, then spread edge to edge — so the first stamp
     begins exactly where the shop's name begins and the last ends where the
     card's padding ends. Anything centred inside its own width would float
     between those two lines and read as a separate block. */
  grid-template-columns: repeat(5, auto);
  justify-content: space-between;
  width: 100%;
  margin: 0.15rem 0 0.3rem;
  row-gap: 12px;
}

/* The wallet the product actually uses, named and marked the same way the
   section further down names it. "Wallet" alone reads as a placeholder. */
.hphone__wallet { display: flex; align-items: center; gap: 0.375rem; }
.hphone__gmark {
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 0.1875rem;
  background: linear-gradient(135deg, #4285f4 0 50%, #34a853 50% 100%);
}

/* Which wallet works today, and which does not yet. Saying both plainly costs
   one line and avoids a merchant finding out from a customer. */
.hero__platform {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  margin-top: 1.125rem;
  font-size: 0.8125rem;
}
.hero__live {
  display: inline-flex;
  align-items: center;
  gap: 0.4375rem;
  padding: 0.25rem 0.6875rem;
  border-radius: 999px;
  background: rgba(178, 234, 67, 0.12);
  color: var(--custback-lime, #b2ea43);
  font-weight: 700;
  letter-spacing: 0.02em;
}
.hero__live::before {
  content: "";
  width: 0.4375rem;
  height: 0.4375rem;
  border-radius: 50%;
  background: var(--custback-lime, #b2ea43);
}

.hphone__status {
  margin: 0.625rem 0 auto;
  font-size: 0.6875rem;
  font-weight: 600;
  color: #6b7280;
  text-align: center;
}

/* ---------------------- Wallet preview: the step line -------------------
   Four equal boxes made four equal claims. A line with one open step says
   which part you are looking at, and the rest stay legible without competing
   for the same attention. */
.wp__steps-list { position: relative; display: grid; gap: 0; }
.wp__steps-list::before {
  content: "";
  position: absolute;
  left: 7px;
  top: 14px;
  bottom: 14px;
  width: 2px;
  background: #dcded8;
}

.wp__step {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0.875rem;
  padding: 0.875rem 0 0.875rem 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.wp__step:focus-visible { outline: 2px solid #5c7c1e; outline-offset: 2px; border-radius: 0.5rem; }

.wp__step-bullet {
  position: relative;
  z-index: 1;
  grid-row: 1 / span 3;
  width: 16px;
  height: 16px;
  margin-top: 0.2rem;
  border-radius: 50%;
  border: 2px solid #cdd0c8;
  background: var(--custback-off-white, #f5f6f2);
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.wp__step.is-active .wp__step-bullet {
  border-color: var(--custback-lime, #b2ea43);
  background: var(--custback-lime, #b2ea43);
  box-shadow: 0 0 0 4px rgba(178, 234, 67, 0.25);
}

.wp__step-label {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #6b7280;
}
.wp__step.is-active .wp__step-label { color: #5c7c1e; }
.wp__step-title { font-size: 1.0625rem; font-weight: 600; color: #11161c; }

/* Only the open step explains itself; the others stay a title. */
.wp__step-body {
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: #454c56;
  transition: max-height 0.3s var(--ease), opacity 0.25s var(--ease), margin-top 0.3s var(--ease);
}
.wp__step.is-active .wp__step-body { max-height: 9rem; opacity: 1; margin-top: 0.25rem; }

/* ---- the device on a light ground ---- */
.section--light .wp__phone {
  border-color: var(--device-bezel-soft);
  box-shadow: 0 1.5rem 3rem rgba(17, 22, 28, 0.22);
}
.section--light .wp__platform { color: #6b7280; }
.section--light .wp__assurance { color: #6b7280; }
.section--light .wp__callout { color: #454c56; }

/* Buttons designed for a dark ground disappear on the off-white section. */
.section--light .btn--outline {
  border-color: #cdd0c8;
  color: #11161c;
}
.section--light .btn--outline:hover { background: #ecEEE8; border-color: #b6bab0; }
.section--light .btn--ghost { color: #11161c; border-color: #cdd0c8; }

/* The card is the subject, so it takes the room rather than sitting in it. */
.wp__wcard { padding: 1.25rem 1.125rem; }
.wp__wcard-brand { font-size: 1.0625rem; }
.wp__wcard-reward { font-size: 0.8125rem; margin-bottom: 1rem; }
.wp__stamp { width: 1.125rem; height: 1.125rem; }
.wp__wcard-count { margin-top: 0.875rem; font-size: 0.8125rem; }

/* ---------------------- The hero on a light ground -----------------------
   The page used to open dark and turn light halfway down. Opening light and
   letting the dark sections punctuate it puts the product — a white phone
   with a coloured card in it — against a ground that does not fight it.

   Everything below is a consequence of the ground moving, not a new idea:
   text that was legible on charcoal is not legible on off-white, and the
   glow that suggested depth on black turns to haze on paper. */

/* Brand lime on off-white is 1.3:1. As a headline it is not a colour choice,
   it is an unreadable one, so the punchline takes the deep green the light
   sections already use for their labels. */
.hero.section--light .text-lime { color: var(--eyebrow-on-light); }
.hero.section--light .hero__sub { color: #545b65; }

/* Same pill, enough ink to read on paper. */
.hero.section--light .hero__live {
  background: rgba(110, 154, 34, 0.14);
  color: #4c6a19;
}
.hero.section--light .hero__live::before { background: #6e9a22; }

/* A lime wash that read as light on black reads as a stain on off-white.
   Kept only as much as says "there is something behind the phones". */
.hero.section--light .hero__glow {
  background:
    radial-gradient(46% 52% at 22% 32%, rgba(178, 234, 67, 0.22), transparent 68%),
    radial-gradient(40% 46% at 78% 12%, rgba(120, 170, 255, 0.1), transparent 70%);
}

/* The bezel softens like the wallet preview's, and the shadow stops being a
   hole: on a light ground a black halo reads as dirt, not as depth. */
.hero.section--light .hphone {
  border-color: var(--device-bezel-soft);
  background: var(--device-bezel-soft);
  box-shadow: 0 1.5rem 3rem rgba(17, 22, 28, 0.2);
}

/* ---- the header, which rides on the hero and so changes with it ----
   It stays light all the way down rather than flipping back at the scroll
   threshold: a bar that changes colour mid-scroll needs its logo to change
   with it, and a logo that swaps under you is a worse problem than a light
   bar over a dark section. */
.nav--light .nav__links a { color: #454c56; }
.nav--light .nav__links a:hover,
.nav--light .nav__links a.is-active { color: #11161c; }
.nav--light .nav__links a.is-active { text-shadow: none; }
.nav--light .btn--ghost { color: #454c56; }
.nav--light .btn--ghost:hover { color: #11161c; }
.nav--light .nav__toggle { border-color: #cdd0c8; }
.nav--light .nav__toggle span { background: #11161c; }
/* At rest the bar is transparent and what shows through is the body, which
   is still charcoal — so a transparent bar over a light hero was a dark strip
   with a dark logo on it. It carries the hero's ground itself. */
.nav--light { background: var(--custback-off-white); }
.nav--light.is-scrolled {
  background: rgba(245, 246, 242, 0.86);
  border-bottom-color: rgba(17, 22, 28, 0.1);
}

/* The three objections a local owner raises before they read anything else,
   answered on the same line as the trades they recognise. */
.trust__proof {
  margin-top: 1.75rem;
  text-align: center;
  color: var(--custback-muted);
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
}

/* The demo shows the customer's side. Two more sections used to narrate the
   owner's, which is one sentence's worth of information. */
.wp__operator {
  max-width: 34rem;
  margin: 0.75rem auto 0;
  text-align: center;
  font-size: 0.875rem;
  line-height: 1.6;
  color: #545b65;
}

/* ------------------------- Campaigns: physical + digital -----------------
   The section that shows a digital action producing a visit to a shop. Every
   campaign here is unbuilt, so the whole thing is labelled as such — a mock
   dashboard is convincing enough to be mistaken for a feature, and a merchant
   who asks for Tuesday campaigns on the first call was misled by this page. */
.cmp__notice {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.625rem;
  max-width: 42rem;
  margin: 1.25rem auto 0;
  color: var(--custback-muted);
  font-size: 0.875rem;
  line-height: 1.6;
}

.cmp { margin-top: clamp(2rem, 4vw, 3rem); }
.cmp__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
}
.cmp__tab {
  padding: 0.5rem 1rem;
  border: 1px solid var(--custback-border);
  border-radius: 999px;
  background: transparent;
  color: var(--custback-body);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease), background-color 0.2s var(--ease);
}
.cmp__tab:hover { color: var(--custback-white); border-color: var(--hairline-strong); }
.cmp__tab.is-active {
  background: var(--custback-lime);
  border-color: var(--custback-lime);
  color: var(--custback-charcoal);
}
.cmp__tab:focus-visible { outline: 2px solid var(--custback-lime); outline-offset: 2px; }

.cmp__panel { animation: wpIn 0.24s var(--ease) both; }
.cmp__panel:focus-visible { outline: 2px solid var(--custback-lime); outline-offset: 4px; }

.cmp__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
  align-items: start;
  gap: clamp(1.5rem, 4vw, 3rem);
}

/* ---- the merchant's side ---- */
.cmp__console {
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: var(--surface-raised);
}
.cmp__console-title {
  margin: 0 0 1.25rem;
  font-size: 1.125rem;
  color: var(--custback-white);
}
.cmp__fields { margin: 0; display: grid; gap: 0.875rem; }
.cmp__fields > div {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  padding-bottom: 0.875rem;
  border-bottom: 1px solid var(--hairline);
}
.cmp__fields > div:last-child { padding-bottom: 0; border-bottom: none; }
.cmp__fields dt {
  color: var(--custback-muted);
  font-size: 0.8125rem;
}
.cmp__fields dd {
  margin: 0;
  color: var(--custback-white);
  font-size: 0.9375rem;
  font-weight: 600;
  text-align: right;
}
.cmp__pill {
  display: inline-block;
  padding: 0.125rem 0.5rem;
  border: 1px solid rgba(178, 234, 67, 0.35);
  border-radius: 999px;
  color: var(--custback-lime);
  font-size: 0.75rem;
  font-weight: 700;
}

/* ---- the customer's side: the same handset as everywhere else ---- */
.cmp__device { display: flex; justify-content: center; }
.cmp__phone {
  position: relative;
  width: 17rem;
  max-width: 100%;
  padding: 0.75rem;
  border: var(--device-bezel-width) solid var(--device-bezel);
  border-radius: 2.25rem;
  /* Cropped, and drawn so it reads as cropped.
     A phone beside a column of text cannot be shown whole without leaving
     most of the screen empty, so only its top is here. That only works if the
     bottom leaves the frame: with a bezel and four rounded corners it read as
     a whole phone of the wrong shape, which is what made these look off. */
  border-bottom: 0;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  background: var(--device-screen);
  box-shadow: 0 1.75rem 3.5rem rgba(0, 0, 0, 0.55);
  overflow: hidden;
}
.cmp__notch {
  position: absolute; top: 0.55rem; left: 50%;
  transform: translateX(-50%);
  width: 0.5rem; height: 0.5rem;
  border-radius: 50%;
  background: var(--device-bezel);
}
.cmp__bar {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 1.25rem 0.25rem 0.875rem;
  font-size: 0.8125rem; font-weight: 600; color: #454c56;
}
.cmp__gmark {
  width: 0.875rem; height: 0.875rem;
  border-radius: 0.25rem;
  background: linear-gradient(135deg, #4285f4 0 50%, #34a853 50% 100%);
}
.cmp__card {
  padding: 1.125rem 1rem 1.25rem;
  border-radius: 1.125rem;
  background: var(--custback-charcoal);
}
.cmp__card-brand { margin: 0; font-size: 1rem; font-weight: 700; color: #fff; }
.cmp__card-type {
  margin: 0.125rem 0 0;
  font-size: 0.625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--custback-muted);
}
/* The campaign's one line, in the place a customer actually reads it. */
.cmp__shout {
  margin: 1rem 0 0;
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--custback-lime);
}
.cmp__card-note {
  margin: 0.3125rem 0 0;
  font-size: 0.75rem;
  line-height: 1.55;
  color: var(--custback-body);
}
.cmp__stamps {
  display: grid;
  grid-template-columns: repeat(5, auto);
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: 1rem;
}
.cmp__stamps i {
  width: 1.125rem; height: 1.125rem;
  border-radius: 50%;
  border: 1px dashed #4a525d;
}
.cmp__stamps i.on { background: var(--custback-lime); border-color: transparent; }
.cmp__card-count { margin: 0.875rem 0 0; font-size: 0.8125rem; color: var(--custback-body); }

/* A streak is counted in days, so it is drawn in days rather than in dots. */
.cmp__days {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0.375rem;
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
}
.cmp__days li {
  padding: 0.4375rem 0.125rem;
  border: 1px dashed #4a525d;
  border-radius: 0.5rem;
  color: var(--custback-muted);
  font-size: 0.6875rem;
  font-weight: 600;
  text-align: center;
}
.cmp__days li.on {
  border-style: solid;
  border-color: transparent;
  background: var(--custback-lime);
  color: var(--custback-charcoal);
}

/* ---- what happens at the counter ---- */
.cmp__flow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  margin: clamp(1.5rem, 3vw, 2rem) 0 0;
  padding: 0;
  list-style: none;
  counter-reset: cmpflow;
}
.cmp__flow li {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4375rem 0.875rem;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  color: var(--custback-body);
  font-size: 0.8125rem;
}
.cmp__flow li + li::before {
  content: "\2192";
  margin-left: -0.375rem;
  margin-right: 0.125rem;
  color: var(--custback-muted);
}

.cmp__close { max-width: 42rem; margin: clamp(2.5rem, 5vw, 4rem) auto 0; text-align: center; }
.cmp__close-title { margin: 0; font-size: clamp(1.375rem, 2.4vw, 1.75rem); }
.cmp__close-body { margin: 0.75rem 0 0; color: var(--custback-body); line-height: 1.7; }

.cmp__benefits {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.25rem, 2.5vw, 1.75rem);
  margin: clamp(2rem, 4vw, 3rem) 0 0;
  padding: 0;
  list-style: none;
}
.cmp__benefits h4 { margin: 0; font-size: 1.0625rem; color: var(--custback-white); }
.cmp__benefits p { margin: 0.5rem 0 0; color: var(--custback-body); font-size: 0.9375rem; line-height: 1.65; }

@media (max-width: 60rem) {
  .cmp__grid { grid-template-columns: 1fr; }
  .cmp__device { order: -1; }
  .cmp__benefits { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .cmp__panel { animation: none; }
}

/* ---------------------------- The card builder ---------------------------
   A light ground on purpose: this is the one place on the page where someone
   is working rather than reading, and a workbench is not lit like a poster. */
.section--preview { background: var(--custback-off-white); color: #454C56; }
.section--preview h2, .section--preview h3 { color: #11161C; }
.section--preview .eyebrow { color: var(--eyebrow-on-light); }
.section--preview .section__sub { color: #545B65; }
.section--preview .note { color: #6B7280; }

   screenshot printed in grey. */

.section--preview .btn--outline { border-color: #CDD0C8; color: #11161C; }
.section--preview .btn--outline:hover { background: #ECEEE8; border-color: #B6BAB0; }

@media (max-width: 60rem) {

  /* The picture explains faster than the form, so it goes first — and stays
     put while the controls below it are worked. */

}

/* -------------------------- Works with your setup ------------------------
   What used to be a seven-row integrations table, most of it unbuilt. A grid
   of "Via API" and "Planned" reads as a product with holes in it, and the
   owner of a café was never going to be won or lost on webhooks. The one
   question they do have — do I have to change my till — is answered in a
   strip, after the price, where an objection belongs. */
.setup__inner { max-width: 52rem; margin-inline: auto; text-align: center; }
.setup__title {
  margin: 0;
  font-size: clamp(1.5rem, 3vw, 2rem);
  letter-spacing: -0.02em;
}
.setup__body {
  margin: 0.875rem auto 0;
  max-width: 38rem;
  color: var(--custback-body);
  line-height: 1.7;
}
.setup__chips {
  /* Wider than the prose it sits under: the three claims are one row or they
     are a ragged 2+1, and a lone chip on its own line reads as an
     afterthought rather than as the third of three. */
  max-width: 52rem;
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin: 1.5rem 0 0;
  padding: 0;
  list-style: none;
}
.setup__chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4375rem;
  padding: 0.4375rem 0.875rem;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  color: var(--custback-body);
  font-size: 0.8125rem;
  font-weight: 500;
}
.setup__chip::before {
  content: "";
  width: 0.4375rem;
  height: 0.4375rem;
  border-radius: 50%;
  background: var(--custback-muted);
}
.setup__chip--live::before { background: var(--custback-lime); }
/* Not yet is drawn as an outline rather than a filled dot, so "coming soon"
   never reads at a glance like something that already works. */
.setup__inner .text-link { display: inline-block; margin-top: 1.5rem; }

/* ------------------------ Try the real thing ---------------------------
   A QR on a page about a QR, which would be a joke if it were decorative.
   This one resolves to a working card, so it is the only element here that
   is the product rather than a picture of one. */
.trydemo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(1.25rem, 3vw, 2rem);
  max-width: 40rem;
  margin: clamp(1.75rem, 4vw, 2.5rem) auto 0;
  padding: clamp(1.125rem, 2.5vw, 1.5rem);
  border: 1px solid rgba(17, 22, 28, 0.1);
  border-radius: var(--r-lg);
  background: #fff;
}
.trydemo__code {
  flex: 0 0 auto;
  padding: 0.75rem;
  border-radius: 0.75rem;
  background: #fff;
  box-shadow: inset 0 0 0 1px rgba(17, 22, 28, 0.08);
}
.trydemo__code img { display: block; width: 11rem; height: 11rem; }
.trydemo__copy { flex: 1 1 16rem; display: flex; flex-direction: column; gap: 0.5rem; }
.trydemo__title { margin: 0; font-size: 1.125rem; color: #11161C; }
.trydemo__copy p { margin: 0; font-size: 0.9375rem; line-height: 1.6; color: #545B65; }
.trydemo__btn { align-self: flex-start; margin-top: 0.375rem; }

@media (max-width: 40rem) {
  /* A phone cannot scan its own screen, so the button leads and the code
     becomes the thing you show somebody else. */
  .trydemo { flex-direction: column-reverse; align-items: stretch; }
  .trydemo__btn { align-self: stretch; justify-content: center; }
  .trydemo__code { align-self: center; }
}

/* ------------------------------- Pricing ---------------------------------
   Three cards and a calculator. The calculator is the point: the pricing is
   a multiplication, so putting it behind a form would be hiding arithmetic,
   and a chain of eighty can work out its own bill without talking to
   anybody. */
.pr {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
  margin-top: clamp(2rem, 4vw, 3rem);
  align-items: start;
}
.pr__aux { margin-top: 0.5rem; }
.pr__plan {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  height: 100%;
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: var(--surface-raised);
}
/* The plan most businesses land on carries the accent; the others do not, so
   the emphasis means something. */
.pr__plan--lead { border-color: var(--custback-lime); }
.pr__plan--addon { background: transparent; border-style: dashed; }
.pr__tag {
  margin: 0;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--custback-muted);
}
.pr__name { margin: 0; font-size: 1.25rem; color: var(--custback-white); }
.pr__price {
  display: flex;
  align-items: baseline;
  gap: 0.3125rem;
  margin: 0.25rem 0 0;
  font-variant-numeric: tabular-nums;
}
.pr__price b { font-size: clamp(1.75rem, 3.5vw, 2.125rem); color: var(--custback-white); letter-spacing: -0.02em; }
.pr__price span { font-size: 0.875rem; color: var(--custback-muted); }
.pr__for { margin: 0.25rem 0 0.5rem; font-size: 0.9375rem; color: var(--custback-body); line-height: 1.55; }
.pr__list { margin: 0; padding: 0; list-style: none; display: grid; gap: 0.5rem; }
.pr__list li {
  position: relative;
  padding-left: 1.25rem;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--custback-body);
}
.pr__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.5rem;
  width: 0.4375rem;
  height: 0.4375rem;
  border-radius: 50%;
  background: var(--custback-lime);
}
.pr__soon { margin: 0.75rem 0 0; font-size: 0.8125rem; line-height: 1.5; color: var(--custback-muted); }
.pr__btn {
  margin-top: auto;
  padding-top: 0;
  justify-content: center;
}
/* The gap above the button is the list's business, not the button's. */
.pr__list { margin-bottom: 1.25rem; }

/* ---- the calculator ---- */
.calc {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
  gap: clamp(1.25rem, 3vw, 2.5rem);
  margin-top: clamp(2rem, 4vw, 3rem);
  padding: clamp(1.25rem, 3vw, 2rem);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: var(--surface-sunken);
}
.calc__controls { display: flex; flex-direction: column; gap: 1rem; }
.calc__title { margin: 0; font-size: 1.125rem; color: var(--custback-white); }
.calc__field { display: flex; flex-direction: column; gap: 0.375rem; }
.calc__label { font-size: 0.875rem; font-weight: 600; color: var(--custback-white); }
.calc__input {
  width: 100%;
  max-width: 9rem;
  min-height: 2.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--custback-border);
  border-radius: 0.625rem;
  background: var(--custback-charcoal);
  color: var(--custback-white);
  font: inherit;
  font-size: 1.125rem;
  font-variant-numeric: tabular-nums;
}
.calc__check { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9375rem; color: var(--custback-body); cursor: pointer; }
.calc__check input { width: 1.0625rem; height: 1.0625rem; }
.calc__note { margin: 0; font-size: 0.8125rem; line-height: 1.6; color: var(--custback-muted); }
.calc__input:focus-visible, .calc__check input:focus-visible {
  outline: 2px solid var(--custback-lime);
  outline-offset: 2px;
}

.calc__out {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: clamp(1rem, 2.5vw, 1.5rem);
  border-radius: var(--r-lg);
  background: var(--surface-raised);
}
.calc__row { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.calc__row-label { font-size: 0.9375rem; color: var(--custback-body); }
.calc__row-label em { display: block; font-style: normal; font-size: 0.75rem; color: var(--custback-muted); font-variant-numeric: tabular-nums; }
.calc__row-value { font-size: 0.9375rem; color: var(--custback-white); font-variant-numeric: tabular-nums; }
.calc__row--total {
  margin-top: 0.25rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--hairline);
}
.calc__row--total .calc__row-label { font-weight: 700; color: var(--custback-white); }
.calc__row--total .calc__row-value { font-size: 1.375rem; font-weight: 700; letter-spacing: -0.02em; }
.calc__btn { margin-top: 0.5rem; justify-content: center; }
.calc__fine { margin: 0; font-size: 0.75rem; text-align: center; color: var(--custback-muted); }

/* ---- what a bill never grows with ---- */
.pr__never {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  margin: clamp(2rem, 4vw, 2.5rem) 0 0;
  padding: 0;
  list-style: none;
}
.pr__never li {
  padding: 0.3125rem 0.6875rem;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  font-size: 0.8125rem;
  color: var(--custback-body);
}
.pr__never-head {
  border: none;
  padding-left: 0;
  color: var(--custback-muted);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: 0.75rem;
}
.pr__rule {
  max-width: 42rem;
  margin: 1rem 0 0;
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--custback-white);
}

@media (max-width: 60rem) {
  .calc { grid-template-columns: minmax(0, 1fr); }
}

/* The GST line belongs with the pricing rule above it rather than in fine
   print: a café owner works out their costs from this number, and a footnote
   they have to hunt for is a number they will get wrong. */
.pr__gst {
  max-width: 42rem;
  margin: 0.75rem 0 0;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--custback-muted);
}

/* The rule under the trades. The list can only ever name a handful, and a
   music teacher who does not see themselves in five words leaves — so the
   sentence that includes them sits right underneath. */
.trust__also {
  max-width: 44rem;
  margin: 0.75rem auto 0;
  text-align: center;
  color: var(--custback-muted);
  font-size: 0.9375rem;
  line-height: 1.6;
}

/* ===================== 22. Narrative hierarchy (2026-09) =================
   Added for the messaging pass. Nothing here restyles an existing component:
   these are the few pieces the new page order needs and did not have. */

/* ---- the line under the primary action ----
   The trial terms belong next to the button that starts the trial, not three
   scrolls away in the pricing section. Two grounds, so two colours. */
.hero__assurance {
  margin: 0.875rem 0 0;
  font-size: 0.8125rem;
  color: #6B7280;
}
.cta__assurance {
  margin: 1rem 0 0;
  font-size: 0.8125rem;
  color: var(--custback-muted);
}

/* ---- the sign-up link inside the mobile drawer ----
   `.nav__actions` is display:none below 960px, which left the mobile menu
   with four section links and no way to start. These are the same two
   actions, and they exist only where the drawer is the navigation. */
.nav__links-cta { display: none; }
@media (max-width: 960px) {
  .nav__links-cta {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    padding-top: 1rem;
  }
  .nav__links-cta .btn { justify-content: center; width: 100%; }
  /* The drawer is dark, but `.nav--light .nav__links a` paints every link in
     it #454c56 for the light bar — which put dark grey on near-black here.
     The primary button carries its own colour; the outline one did not. */
  .nav__links .nav__links-cta a.btn--outline {
    color: var(--custback-white);
    border-color: var(--custback-border);
  }
  /* And the same rule was painting the four section links #454c56 on the
     drawer's near-black — 2.2:1, which is a menu you cannot read. The light
     colours belong to the bar, not to the panel that drops out of it. */
  .nav .nav__links > a { color: var(--custback-body); }
  .nav .nav__links > a:hover,
  .nav .nav__links > a.is-active { color: var(--custback-white); }
}

/* ---- two plans, not three ----
   Solo and Business are alternatives a visitor picks between. Held to a pair
   they read as a choice; stretched across the full container they read as a
   list of things to scroll past. */
.pr--base {
  grid-template-columns: repeat(auto-fit, minmax(min(19rem, 100%), 1fr));
  max-width: 54rem;
  margin-inline: auto;
}

/* ---- Engage ----
   An add-on has to look like one. As a third card in the same grid it read as
   a third plan, equal to Solo and Business and buyable on the same day, and
   it is none of those things. Full width, dashed, and below the pair. */
.addon {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: clamp(1.25rem, 3vw, 2.5rem);
  max-width: 54rem;
  margin: clamp(1.25rem, 3vw, 2rem) auto 0;
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  border: 1px dashed var(--custback-border);
  border-radius: var(--r-lg);
}
.addon__name { margin: 0.25rem 0 0; font-size: 1.25rem; color: var(--custback-white); }
.addon__price {
  display: flex;
  align-items: baseline;
  gap: 0.3125rem;
  margin: 0.25rem 0 0;
  font-variant-numeric: tabular-nums;
}
.addon__price b { font-size: 1.625rem; color: var(--custback-white); letter-spacing: -0.02em; }
.addon__price span { font-size: 0.875rem; color: var(--custback-muted); }
.addon__for { margin: 0.5rem 0 0; font-size: 0.9375rem; line-height: 1.55; color: var(--custback-body); }
/* The condition, said where the price is rather than in a footnote. */
.addon__gate {
  margin: 0.875rem 0 0;
  padding: 0.5rem 0.75rem;
  border-radius: 0.625rem;
  background: rgba(178, 234, 67, 0.1);
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--custback-body);
}
.addon__body { display: flex; flex-direction: column; }
.addon__list { margin-bottom: 1rem; }
.addon__link { margin-top: auto; }
@media (max-width: 48rem) {
  .addon { grid-template-columns: minmax(0, 1fr); }
}

/* ---- the calculator ----
   The checkbox prices Engage. It must not imply Engage is available on the day
   somebody ticks it, so the later figure is a separate, dated block below the
   total rather than folded into it. */
.calc__later {
  display: block;
  margin-top: 0.1875rem;
  font-style: normal;
  font-size: 0.75rem;
  line-height: 1.5;
  color: var(--custback-muted);
}
.calc__check { align-items: flex-start; }
.calc__check input { margin-top: 0.1875rem; flex: 0 0 auto; }

/* Solo or Business, as one control rather than two radios a thumb can miss.
   `.calc__field` was only ever a div until now; as a fieldset it brought the
   browser's default border and legend inset with it. */
fieldset.calc__field { min-width: 0; margin: 0; padding: 0; border: 0; }

fieldset.calc__field > .calc__label { padding: 0; }
.calc__seg { display: flex; gap: 0.375rem; }
.calc__seg-opt { flex: 1 1 0; }
.calc__seg-opt input {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0);
}
.calc__seg-opt span {
  display: block;
  min-height: 2.75rem;
  padding: 0.6875rem 0.75rem;
  border: 1px solid var(--custback-border);
  border-radius: 0.625rem;
  background: var(--custback-charcoal);
  color: var(--custback-body);
  font-size: 0.9375rem;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}
.calc__seg-opt input:checked + span {
  border-color: var(--custback-lime);
  background: rgba(178, 234, 67, 0.12);
  color: var(--custback-white);
}
.calc__seg-opt input:focus-visible + span {
  outline: 2px solid var(--custback-lime);
  outline-offset: 2px;
}

/* The month-four figure. Separated by a rule and introduced by a sentence
   with the date in it, so it cannot be mistaken for this month's bill. */
.calc__later-block {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin-top: 0.5rem;
  padding-top: 1rem;
  border-top: 1px dashed var(--custback-border);
}
.calc__later-head {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--custback-muted);
}
.calc__later-block .calc__row--total .calc__row-value {
  font-size: 1.125rem;
  color: var(--custback-body);
}

/* ---- touch targets ----
   The two plan buttons are the page's conversion, and on a phone they were
   37px tall — under the 44px a thumb needs. Given as a minimum rather than as
   padding so the desktop proportions are untouched. */
.pr__btn, .calc__btn { min-height: 2.875rem; }
@media (max-width: 40rem) {
  .btn { min-height: 2.75rem; }
}
/* ---- the demo card's button ----
   The comment on line 1479 applies to this too, and it used to be covered by
   it: the try-it card sat inside the off-white section and inherited
   `.section--light .btn--outline`. Pulling the card out into its own section
   put a white label on a white card. The card is light by its own definition,
   whatever it sits in, so the rule belongs to the card. */
.trydemo__btn.btn--outline { border-color: #cdd0c8; color: #11161c; }
.trydemo__btn.btn--outline:hover { background: #ecEEE8; border-color: #b6bab0; }

/* The hidden attribute, made to mean it.

   Any author `display` beats the user agent's rule for `[hidden]`, and this
   stylesheet sets one on three elements that are toggled that way: the venue
   box (flex), the Engage block (flex) and the card's conditions list (grid).
   All three stayed on screen while the DOM believed they were gone. Last rule
   in the file, so it wins on order rather than on !important. */
[hidden] { display: none; }

/* ═══════════════════ 23. Visual hierarchy pass (2026-09) ═══════════════════
   Not a redesign: no new palette, no new family, no new components. What this
   fixes is that the page was one padding value repeated twelve times, four
   heading sizes competing, five greys doing the job of two, and four corner
   radii. The result read as section + section + section rather than as an
   argument. Everything below is rhythm, scale and grouping. */

:root {
  /* Three step rhythm instead of one. A section that carries a decision may
     breathe; one that answers an objection should not take a screen to do it. */
  --section-y:    clamp(4rem, 6.5vw, 6.5rem);
  --section-y-lg: clamp(5rem, 8vw, 8rem);
  --section-y-sm: clamp(2.75rem, 4.5vw, 4rem);

  /* One family of corners. Was 14, 16, 20 and 24 across nine components. */
  --r-sm: 12px;
  --r-md: 16px;
  --r-lg: 20px;

  /* Supporting text on the off-white ground, as two roles rather than five
     near-identical greys. */
  --ink:        #11161C;
  --ink-body:   #4E555F;
  --ink-muted:  #6B7280;
}

.section    { padding-block: var(--section-y); }
.section--lg { padding-block: var(--section-y-lg); }
.section--tight { padding-block: var(--section-y-sm); }

/* ---- reading measure ----
   Supporting copy ran to 672px, about ninety characters. The eye loses the
   line start at that width; the headline stays wide, the paragraph does not. */
.section__head { max-width: 44rem; margin-bottom: clamp(2rem, 3.5vw, 3rem); }
.section__sub  { max-width: 36rem; margin-top: 0.875rem; }
.hero__sub     { max-width: 33rem; }

/* ---- heading scale ----
   H1 72 / H2 49 / closing 60 / setup 32 put the closing title almost level
   with the hero and left two orphan sizes. One ladder, four rungs. */
.hero__title {
  font-size: clamp(2.75rem, 5.2vw, 4.25rem);
  line-height: 1.02;
  letter-spacing: -0.035em;
}
.section__title,
.cta__title,
.setup__title {
  font-size: clamp(1.875rem, 3.1vw, 2.625rem);
  line-height: 1.12;
  letter-spacing: -0.03em;
}
.cta__title { font-size: clamp(2rem, 3.6vw, 3rem); }

/* Eyebrows label a section; they were competing with it. */
.eyebrow { font-size: 0.75rem; letter-spacing: 0.14em; }

/* ---- supporting text, unified ----
   `.note` at 15px and `.hint` at 17px were the same role at two sizes. */
.section--light .note,
.section--light .hint,
.note, .hint { font-size: 0.875rem; line-height: 1.6; }
.section--light .section__sub { color: var(--ink-body); }
.section--light .note, .section--light .hint { color: var(--ink-muted); }

/* ---- one card system ----
   Same border, same corner, same padding scale, whichever ground it sits on.
   Surfaces still differ — that is what tells a panel from a plane. */
.pr__plan, .addon, .calc, .calc__out, .cmp__console,
.security-grid li, .faq-list details, .trydemo,
.comparison__scroll {
  border-radius: var(--r-lg);
}
.security-grid li { padding: clamp(1.125rem, 2vw, 1.375rem); }

/* ---- button system ----
   Primary is the only filled shape on the page. Secondary is an outline that
   does not ask for the click. A text link is a link. */
.btn { font-weight: 600; letter-spacing: -0.01em; }
.btn--lg { padding: 0.9375rem 1.5rem; font-size: 1.0625rem; }
.btn--primary { box-shadow: 0 1px 2px rgba(17, 22, 28, 0.16); }
.btn--primary:focus-visible,
.btn--outline:focus-visible,
.text-link:focus-visible {
  outline: 2px solid var(--custback-lime);
  outline-offset: 3px;
}
/* 4.4:1 against the off-white ground was under AA for body-size text. */
.section--light .text-link { color: #4C6A19; }

/* ───────────────── Chapters ─────────────────
   Four grounds, three transitions, each one marking a change of subject
   rather than decorating a seam:

     light  the product      hero · who it's for · how it works · builder · demo
     dark   the argument     comparison · Engage · POS · pricing
     light  reassurance      your data · questions
     dark   the close        start

   Before this, `who it's for` was a dark band dropped between two light
   sections and the demo was dark between two of its own chapter, so the
   grounds told the reader nothing. */

/* Who it's for: the hero's last line, not its own chapter. */
.trust {
  padding: var(--section-y-sm) 0;
  border-block: 0;
  border-bottom: 1px solid rgba(17, 22, 28, 0.08);
  background: var(--custback-off-white);
}
.trust__label { color: var(--ink-muted); font-size: 0.9375rem; }
.trust__row { color: var(--ink); margin-top: 1.25rem; }
.trust__also, .trust__proof { color: var(--ink-muted); }
.trust__row li::after { background: #6E9A22; }

/* The demo belongs to the product chapter, and it is proof rather than a
   footnote — so it gets the ground of what it is proving. */
#demo.section--light { border-top: 1px solid rgba(17, 22, 28, 0.08); }

/* Reassurance reads as relief after the commercial chapter, which is the one
   job a background change can do that a heading cannot. */
.section--light .security-grid li {
  border-color: rgba(17, 22, 28, 0.1);
  background: #fff;
}
.section--light .security-grid strong { color: var(--ink); }
.section--light .security-grid span   { color: var(--ink-body); }

/* Pricing opens the commercial chapter's conclusion. One step deeper than the
   sections above it, so the eye knows the argument has arrived somewhere. */
#pricing { background: var(--surface-sunken); }
#pricing .calc { background: var(--surface); }

/* ───────────────── Hero ─────────────────
   The headline had an eyebrow, a badge pair and a five-line paragraph around
   it, all at weights close enough to argue with it. They are still there and
   they are now clearly beneath it. */
.hero__inner { gap: clamp(2rem, 5vw, 4.5rem); align-items: center; }
.hero__sub { margin-top: 1.25rem; font-size: clamp(1.0625rem, 1.4vw, 1.1875rem); line-height: 1.6; }
.hero__cta { margin-top: 2rem; gap: 0.75rem; }
.hero__assurance { margin-top: 1rem; }
.hero__platform { margin-top: 1.25rem; font-size: 0.75rem; }
.hero__live { padding: 0.1875rem 0.5625rem; font-size: 0.75rem; }

/* ───────────────── How it works ─────────────────
   Four steps whose bodies only open one at a time already; the titles are what
   carries the sequence, so the titles get the weight. */
.wp { gap: clamp(2rem, 4vw, 3.5rem); }
.wp__step-title { font-size: 1.125rem; font-weight: 600; }
.wp__step-body { font-size: 0.9375rem; line-height: 1.6; }
.wp__step { padding-block: 1rem; }
.wp__actions { margin-top: 1.5rem; }

/* ───────────────── Real wallet demo ─────────────────
   The best proof on the page was sized like a footnote. */
.trydemo { max-width: 46rem; padding: clamp(1.5rem, 3vw, 2rem); gap: clamp(1.5rem, 3vw, 2.25rem); }
.trydemo__title { font-size: clamp(1.25rem, 2vw, 1.5rem); }
.trydemo__btn { min-height: 3rem; padding-inline: 1.5rem; }

/* ───────────────── Comparison ─────────────────
   Custback's column is marked by weight and a wash rather than by a badge that
   awards itself the prize. */
.comparison__table thead th { font-size: 0.8125rem; letter-spacing: 0.04em; }
.comparison__table .comparison__custback { background: rgba(178, 234, 67, 0.06); }
.comparison__table thead .comparison__custback { background: rgba(178, 234, 67, 0.1); }
.comparison__table tbody .comparison__custback { color: var(--custback-white); font-weight: 500; }
.comparison__table th, .comparison__table td { padding: 0.875rem 1rem; font-size: 0.9375rem; }

/* Below this width the table is eight rows of four columns dragged sideways,
   which is not reading. One card per row, each value saying whose it is. */
@media (max-width: 46rem) {
  .comparison__scroll { overflow: visible; border: 0; border-radius: 0; }
  /* The 52rem floor is what makes the table scroll sideways on a wide-enough
     screen. As a stack of cards it has to come off, or every card is 832px. */
  .comparison__table { min-width: 0; }
  .comparison__table, .comparison__table tbody, .comparison__table tr,
  .comparison__table tbody th, .comparison__table td { display: block; width: auto; }
  .comparison__table thead { display: none; }
  .comparison__table tbody tr {
    margin-bottom: 0.75rem;
    padding: 1rem 1.125rem;
    border: 1px solid var(--hairline);
    border-radius: var(--r-lg);
    background: var(--surface-raised);
  }
  .comparison__table tbody th[scope="row"] {
    margin-bottom: 0.75rem;
    padding: 0 0 0.625rem;
    border-bottom: 1px solid var(--hairline);
    color: var(--custback-white);
    font-size: 1rem;
  }
  /* Label beside the value, not above it. Stacked, eight rows of three values
     ran three and a half screens — longer than the table it replaced, which
     defeats the point of replacing it. */
  /* The label sits in a gutter rather than in a grid or flex track. Both of
     those turn the tick and the sentence beside it into separate items, which
     put "A few minutes" on its own line under its own checkmark. */
  .comparison__table td {
    position: relative;
    padding: 0.3125rem 0 0.3125rem 6.75rem;
    border: 0;
    font-size: 0.875rem;
    line-height: 1.45;
  }
  .comparison__table td::before {
    content: attr(data-label);
    position: absolute;
    left: 0;
    top: 0.4375rem;
    width: 6.25rem;
    color: var(--custback-muted);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    line-height: 1.35;
    text-transform: uppercase;
  }
  .comparison__table tbody .comparison__custback {
    margin: 0 -0.5rem 0.1875rem;
    padding: 0.4375rem 0.5rem 0.4375rem 6.25rem;
    border-radius: var(--r-sm);
  }
  .comparison__table tbody .comparison__custback::before { left: 0.5rem; }
  .comparison__table tbody tr { padding: 0.875rem 1rem; margin-bottom: 0.625rem; }
  .comparison__table tbody th[scope="row"] {
    margin-bottom: 0.5rem;
    padding-bottom: 0.5rem;
    font-size: 0.9375rem;
  }
}

/* ───────────────── Engage ─────────────────
   The condition and the price are facts the merchant needs; the benefit is
   what makes them worth reading. The notice was a box as loud as the heading. */
.cmp__notice {
  max-width: 36rem;
  margin-top: 1rem;
  padding: 0;
  border: 0;
  border-left: 2px solid rgba(178, 234, 67, 0.45);
  padding-left: 0.875rem;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--custback-muted);
}
.cmp__tabs { margin-bottom: 1.5rem; }
.cmp__console-title { font-size: 1.0625rem; }
.cmp__benefits { margin-top: clamp(2rem, 4vw, 3rem); }
.cmp__benefits h4 { font-size: 1rem; }
.cmp__benefits p { font-size: 0.9375rem; line-height: 1.6; }

/* ───────────────── POS ─────────────────
   An objection answered in one sentence does not need a screen. */
.setup__inner { max-width: 44rem; }
.setup__body { max-width: 38rem; font-size: 1rem; line-height: 1.65; }
.setup__title { margin-top: 0.5rem; }

/* ───────────────── Pricing ─────────────────
   The number is the thing being compared, so the number is the biggest thing
   in the card. It was 34px against a 15px feature list — legible, but not
   dominant, and the eye went to the list. */
.pr { margin-top: clamp(1.75rem, 3vw, 2.5rem); }
.pr__plan { padding: clamp(1.5rem, 2.6vw, 2rem); gap: 0.375rem; }
.pr__name { font-size: 1.0625rem; font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase; color: var(--custback-muted); }
.pr__price { margin-top: 0.375rem; }
.pr__price b { font-size: clamp(2.25rem, 4vw, 2.875rem); line-height: 1; }
.pr__for { margin: 0.75rem 0 1.125rem; font-size: 0.9375rem; }
.pr__list { gap: 0.625rem; margin-bottom: 1.5rem; }
.pr__list li { font-size: 0.9375rem; }
.pr__plan--lead { box-shadow: 0 0 0 1px var(--custback-lime); }

/* The add-on, kept plainly subordinate to the pair above it. */
.addon { padding: clamp(1.25rem, 2.4vw, 1.75rem); background: rgba(255, 255, 255, 0.015); }
.addon__name { font-size: 1.125rem; }
.addon__price b { font-size: 1.75rem; }
.addon__for { font-size: 0.9375rem; }
.addon__gate { font-size: 0.8125rem; padding: 0.5rem 0.6875rem; }
.addon__list li { font-size: 0.9375rem; }

/* ───────────────── Calculator ─────────────────
   A tool answers a question. The answer should be the largest thing in it, and
   the two controls that produce it should read as controls. */
.calc { padding: clamp(1.25rem, 2.6vw, 1.875rem); }
/* Scoped: unscoped it overrode the 60rem rule that collapses this to one
   column, so on a phone the result panel was 160px wide and the total spilled
   a hundred pixels past the viewport. */
@media (min-width: 60.0625rem) {
  .calc { grid-template-columns: minmax(0, 0.82fr) minmax(0, 1fr); }
}
.calc__title { font-size: 1rem; color: var(--custback-muted); font-weight: 600; letter-spacing: 0.02em; }
.calc__out { padding: clamp(1.25rem, 2.4vw, 1.75rem); }
.calc__row--total .calc__row-value { font-size: clamp(1.75rem, 3vw, 2.25rem); line-height: 1.1; }
.calc__row--total .calc__row-label { font-size: 0.875rem; color: var(--custback-muted); font-weight: 600; }
.calc__later-block .calc__row--total .calc__row-value { font-size: 1.25rem; }
.calc__btn { margin-top: 1rem; }

/* ───────────────── Trust ─────────────────
   Four short answers, not a security paper. */
.security-grid { gap: 0.875rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.security-grid strong { font-size: 0.9375rem; }
.security-grid span { font-size: 0.875rem; }

/* ───────────────── FAQ ─────────────────
   Questions a visitor scans. Enough air between them to scan. */
.faq-list { gap: 0.5rem; max-width: 44rem; }
.faq-list summary { padding: 0.9375rem 1.125rem; font-size: 0.9375rem; }
.faq-list details p { padding: 0 1.125rem 1.125rem; font-size: 0.9375rem; }

/* ───────────────── Close ─────────────────
   One statement, one action. Not a second landing page. */
/* 40rem broke the headline mid-clause and wrapped the two buttons onto two
   rows. The close is one statement and one action; both need to read as one. */
.cta__inner { max-width: 46rem; margin-inline: auto; text-align: center; }
.cta__title { text-wrap: balance; }
.cta__sub { max-width: 32rem; margin-inline: auto; font-size: 1.0625rem; }
.cta__actions { justify-content: center; margin-top: 1.75rem; }
.cta__assurance { text-align: center; }
/* Secondary detail: one line under the list rather than four more bullets. */
.pr__fine {
  margin: 0 0 1.25rem;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--custback-muted);
}

/* ───────────────── Mobile pass (≤ 40rem) ─────────────────
   The page was twenty-one screens on a phone. Most of that was desktop
   spacing scaled down rather than designed, plus two sections that stack into
   towers. Nothing is removed here that a phone reader needs. */
@media (max-width: 40rem) {
  /* The hero has to put the headline, the promise and the button on one
     screen. It was doing it, but only just. */
  .hero { padding-block: 2.5rem 3rem; }
  .hero__title { font-size: clamp(2.375rem, 11vw, 3rem); }
  .hero__sub { font-size: 1rem; }
  .hero__cta { margin-top: 1.5rem; }
  .hero__stage { margin-top: 2rem; }

  .section__head { margin-bottom: 1.75rem; }
  .section__title { font-size: clamp(1.625rem, 7.5vw, 2rem); }
  .cta__title { font-size: clamp(1.75rem, 8vw, 2.25rem); }

  /* Who it's for reads as a list of trades; on a phone it should still be
     one glance rather than six lines. */
  .trust__row { gap: 0.5rem 1.25rem; font-size: 1rem; }
  .trust__also { font-size: 0.875rem; }

  /* The builder is the tallest section on a phone. The preview leads, the
     controls follow, and the sticky preview is dropped — on a phone it would
     pin a card over the controls somebody is trying to use. */

  /* Pricing was 3.8 screens. The cards keep their air; the gaps between the
     blocks inside the section do not need desktop values. */
  .pr { gap: 0.875rem; }
  .pr__plan { padding: 1.25rem; }
  .addon { margin-top: 0.875rem; }
  .calc { gap: 1.25rem; padding: 1.125rem; }
  .calc__out { padding: 1.125rem; }
  .pr__never { margin-top: 1.75rem; }

  .cmp__benefits { gap: 1.25rem; }
  .security-grid { gap: 0.75rem; }
  .trydemo { padding: 1.25rem; gap: 1.25rem; }
}

/* The sticky preview needs a scrolled-nav offset, and only where it sticks. */

@media (max-width: 40rem) {
  /* The card leads, the form follows. A builder whose first screen is a form
     is a form; one whose first screen is the card is a demonstration. */

}

@media (max-width: 40rem) {
  /* "NZ$74.94/month" at display size will not sit beside its label on a 390px
     screen — it pushed the document 100px wider than the viewport. The label
     goes above the number, which is the right order to read it in anyway. */
  .calc__row--total {
    display: block;
    padding-top: 0.875rem;
  }
  .calc__row--total .calc__row-label { display: block; margin-bottom: 0.125rem; }
  .calc__row--total .calc__row-value { font-size: 2rem; }
  .calc__later-block .calc__row--total .calc__row-value { font-size: 1.5rem; }
}

/* One touch target for every button, not only the ones a phone sees. */
.btn { min-height: 2.75rem; }

/* The Wallet label inside the mockups sat at 2.9:1 on the off-white screen.
   Google's own chrome is darker than this, so the fix is also the truer
   drawing. (The card text below it measures badly only because the card is
   painted with a gradient a contrast walker cannot read — it is white on a
   dark card and legible.) */
.hphone__wallet, .wp__bar, .cmp__bar { color: #5F6672; }

/* ───────────────── Calculator on a phone ─────────────────
   Stacked, the controls came first and the answer landed about 450px below
   the title — you had to scroll past the whole form to see the number the
   form exists to produce. The answer goes first: you read what you would pay,
   then you change the two things that change it. */
@media (max-width: 60rem) {
  .calc__out { order: -1; }
}
/* The plan toggle and the Engage box were painting in the browser's default
   blue, the one colour on the page that is not ours. */
.calc__check input,
input[type="checkbox"],
input[type="radio"] { accent-color: var(--custback-lime); }

@media (max-width: 40rem) {
  /* The sign-up button sat at the foot of the form, 2325px below the top of
     the section — past nine controls. Stacked, the order that makes sense is
     the card, then what to do about it, then the knobs for anyone still
     playing. "Start over" belongs next to the card it resets anyway. */

  /* Sitting under the primary before anything has been changed, a second
     outlined button read as a second choice. It is a reset, so it reads as one. */
  #bx-reset {
    border-color: transparent;
    background: transparent;
    color: var(--ink-muted);
    text-decoration: underline;
    text-underline-offset: 3px;
    font-weight: 500;
  }
}

@media (max-width: 40rem) {
  /* On a phone the code is useless — you cannot scan your own screen — so the
     button is the action and the QR is the thing you hold up to somebody else.
     The existing layout already put the button first; this gives it the weight
     to match, and stops a 176px code dominating the card. */
  .trydemo__btn {
    border-color: transparent;
    background: var(--custback-lime);
    color: #11161C;
  }
  .trydemo__btn:hover { background: #a3dd2f; border-color: transparent; }
  .trydemo__code img { width: 8.5rem; height: 8.5rem; }
}

/* The step numbers sat at 4.4:1 on the off-white ground — just under AA for
   text this size, and they are the labels that carry the sequence. */
.wp__step-label { color: #5A626D; }
.wp__step.is-active .wp__step-label { color: #4C6A19; }

/* ---- tap targets that were just short ----
   The campaign tabs and the menu button are controls, not links in a
   sentence, and both sat at 41–42px. The footer's columns are a list of
   links a thumb has to hit, so they get room between them on a phone. */
.cmp__tab { min-height: 2.75rem; }
.nav__toggle { min-height: 2.75rem; min-width: 2.75rem; }
@media (max-width: 40rem) {
  .footer__cols a { display: inline-block; padding-block: 0.3125rem; }
}

/* ---- links inside body copy on the light ground ----
   Anchors default to white for the dark sections. The one inside the builder's
   hint sits on a white panel, so "Custback Engage" — the link that explains
   what the campaign chips are — was white on white and could not be seen.
   `.text-link` was already covered; running text was not. */
/* `.section--preview` (the builder) is a light ground too — it just does not
   carry the `--light` class — which is why the first attempt at this missed
   the one link that was actually broken. */
.section--light p a,
.section--light li a,
.section--light .hint a,
.section--light .note a,
.section--preview p a,
.section--preview .hint a,
.section--preview .note a,
.trust p a {
  color: #4C6A19;
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.section--light p a:hover,
.section--light li a:hover,
.section--light .hint a:hover,
.section--light .note a:hover,
.section--preview p a:hover,
.section--preview .hint a:hover { color: #3B5414; }

/* ═════════════════════ 24. Card gallery (2026-09) ═════════════════════
   The interactive builder was replaced by four finished cards. They are the
   site's own `.lcard` component, painted with colours from the customiser's
   palette and stamped with its own marks, so nothing here is a promise the
   product cannot keep. What varies between them is what varies between real
   shops: the trade, the colour, the stamp, the target and the reward. */

/* Two by two rather than four across. At a quarter of the container the cards
   were 258px and their stamps 16px — the marks that are the whole point of the
   section read as grey specks, and a twelve-stamp card wrapped out of line
   with the rest. Half the container gives the stamps room to be recognisable. */
.gallery {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
  max-width: 52rem;
  /* Left, not centred: the heading sits on the container's edge and a centred
     grid put the cards on a second axis. */
  margin: clamp(1.75rem, 3vw, 2.5rem) 0 0;
}
.gallery__card { width: auto; min-height: 14.5rem; padding: 1.375rem 1.5rem; }
.gallery__card .lcard__brand {
  font-size: 1rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
/* Big enough to tell a coffee cup from a pair of scissors. */
.gallery__card .lcard__stamps { gap: 7px; }
.gallery__card .lcard__stamps i { width: 26px; height: 26px; border-radius: 50%; }
.gallery__card .lcard__count { font-size: 0.8125rem; }
.lcard__reward {
  margin: 0.375rem 0 0;
  color: rgba(255, 255, 255, 0.72);
  font-size: 0.75rem;
  line-height: 1.4;
}
.lcard__reward b { color: var(--custback-white); font-weight: 600; }

/* Four more palettes from the customiser's own ten. */
.lcard--barber { background: linear-gradient(150deg, #0B0E13, #1E2530); }
.lcard--bakery { background: linear-gradient(150deg, #5C2A12, #A24B21); }
.lcard--shop   { background: linear-gradient(150deg, #101F3A, #1B3A6B); }

@media (max-width: 40rem) {
  /* A 2×2 grid on a phone makes four thumbnails. One card per screen-width,
     swiped, keeps them the size the section exists to show off. */
  .gallery {
    display: flex;
    gap: 0.875rem;
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }
  .gallery::-webkit-scrollbar { display: none; }
  .gallery__card {
    flex: 0 0 min(17rem, 78vw);
    scroll-snap-align: center;
  }
}
