/* ==========================================================================
   BREWED IN PIXELS — components v2
   Requires tokens.css. Every class is prefixed .bp- so this file can be
   dropped onto any existing page without colliding with styles.css.
   Fonts: <link> Archivo (wdth,wght) + Inter before this file.
   ========================================================================== */

/* ---- 1. type roles ------------------------------------------------------ */
.bp-d{font-family:var(--bp-display);font-weight:var(--bp-display-weight);
  font-variation-settings:"wdth" var(--bp-wdth);
  letter-spacing:var(--bp-track-display);line-height:.98}
.bp-h1{font-size:clamp(2.5rem,6.6vw,5.1rem);text-wrap:balance}
.bp-h2{font-size:clamp(1.9rem,4.4vw,3.05rem);text-wrap:balance}
.bp-h3{font-size:1.3rem}

/* the label. this is what replaced Space Mono — case + tracking, not a family. */
.bp-label{font-family:var(--bp-body);font-weight:var(--bp-lbl-weight);
  font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);
  text-transform:uppercase;font-variant-numeric:tabular-nums}
.bp-label--orange{color:var(--bp-orange)}
.bp-label--faint{color:var(--bp-faint)}
/* every figure that lines up in a column gets this */
.bp-num{font-variant-numeric:tabular-nums}

/* ---- 2. elevation utilities --------------------------------------------- */
.bp-lift-1{box-shadow:var(--bp-lift-1)}
.bp-lift-2{box-shadow:var(--bp-lift-2)}
.bp-lift-3{box-shadow:var(--bp-lift-3)}

/* ---- 3. card — borderless, always ---------------------------------------- */
.bp-card{background:var(--bp-white);border:0;border-radius:var(--bp-r-card);
  padding:32px;box-shadow:var(--bp-lift-2);
  transition:box-shadow var(--bp-dur) var(--bp-ease),transform var(--bp-dur) var(--bp-ease)}
.bp-card:hover{box-shadow:var(--bp-lift-3);transform:translateY(-4px)}
.bp-card--flat:hover{transform:none;box-shadow:var(--bp-lift-2)}

/* ---- 4. buttons ---------------------------------------------------------- */
@keyframes bp-sweep{0%{background-position:200% center}100%{background-position:-200% center}}
.bp-cta{display:inline-block;border:0;cursor:pointer;
  background:var(--bp-orange);color:#fff;border-radius:var(--bp-r-pill);
  padding:16px 32px;font-family:var(--bp-body);font-weight:600;font-size:15px;
  box-shadow:var(--bp-glow);
  background-image:linear-gradient(100deg,var(--bp-orange) 30%,rgba(255,140,60,.92) 50%,var(--bp-orange) 70%);
  background-size:250% 100%;animation:bp-sweep 2.8s linear infinite;
  transition:transform var(--bp-dur) var(--bp-ease),box-shadow var(--bp-dur) var(--bp-ease)}
.bp-cta:hover{transform:translateY(-2px);box-shadow:var(--bp-glow-hover)}
.bp-cta--sm{padding:11px 22px;font-size:13px}
/* no sweep, glow only — the version I'd argue for; kept for A/B */
.bp-cta--still{animation:none;background-image:none}

.bp-btn-dark{display:inline-block;text-align:center;background:var(--bp-ink);color:#fff;
  border:0;cursor:pointer;border-radius:var(--bp-r-pill);padding:16px 28px;
  font-family:var(--bp-body);font-weight:600;font-size:11.5px;
  letter-spacing:var(--bp-lbl-track);text-transform:uppercase;
  /* the ramp at REST, not only on hover: this is what makes the control read
     as floating above the page rather than printed on it. */
  box-shadow:var(--bp-lift-3);
  transition:transform var(--bp-dur) var(--bp-ease),box-shadow var(--bp-dur) var(--bp-ease)}
.bp-btn-dark:hover{transform:translateY(-3px)}

/* ---- 5. sticky pill nav -------------------------------------------------- */
.bp-navwrap{position:sticky;top:16px;z-index:40;display:flex;justify-content:center;
  padding:20px 0 0;pointer-events:none}
.bp-pill{display:flex;align-items:center;gap:3px;background:var(--bp-ink);color:#fff;
  border-radius:var(--bp-r-pill);padding:6px 6px 6px 20px;box-shadow:var(--bp-lift-2);
  max-width:94%;pointer-events:auto}
.bp-pill__mark{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:14.5px;
  letter-spacing:-.02em;margin-right:14px;white-space:nowrap}
.bp-pill__lk{font-size:12.5px;color:rgba(255,255,255,.6);padding:8px 11px;
  border-radius:var(--bp-r-pill);white-space:nowrap;text-decoration:none;
  transition:color var(--bp-dur) var(--bp-ease),background var(--bp-dur) var(--bp-ease)}
.bp-pill__lk:hover{color:#fff;background:rgba(255,255,255,.1)}
.bp-pill__cta{background:var(--bp-orange);color:#fff;border-radius:var(--bp-r-pill);
  padding:9px 17px;font-size:12px;font-weight:600;margin-left:8px;
  white-space:nowrap;text-decoration:none}
.bp-pill__round{width:32px;height:32px;border-radius:100%;background:rgba(255,255,255,.13);
  display:grid;place-items:center;font-size:10.5px;font-weight:600;letter-spacing:.08em;
  margin-left:3px;text-decoration:none;color:#fff;
  transition:background var(--bp-dur) var(--bp-ease)}
.bp-pill__round:hover{background:rgba(255,255,255,.28)}
/* Open at the top of the page, compact once scrolling starts. scripts.js adds
   .is-stuck past 40px. Below 940px it is always compact. */
.bp-pill__lk{display:inline-block}
.bp-navwrap.is-stuck .bp-pill__lk{display:none}
@media(max-width:940px){.bp-pill__lk{display:none}}
.bp-pill{transition:padding var(--bp-dur) var(--bp-ease)}

/* ---- 6. dot field, brightens around the cursor --------------------------- */
/* markup: <div class="bp-dotzone"><i class="bp-dots"></i><i class="bp-dots-hi"></i> …content… </div>
   JS below sets --bp-mx/--bp-my on .bp-dots-hi */
.bp-dotzone{position:relative;overflow:hidden}
.bp-dots,.bp-dots-hi{position:absolute;inset:0;pointer-events:none;
  background-image:radial-gradient(circle,var(--bp-ink) 1.1px,transparent 1.1px);
  background-size:24px 24px}
.bp-dots{opacity:.055}
/* on an ink ground the ink dots vanish; paint them white instead */
.bp-dotzone--dark .bp-dots,.bp-dotzone--dark .bp-dots-hi{
  background-image:radial-gradient(circle,#fff 1.1px,transparent 1.1px)}
.bp-dotzone--dark .bp-dots{opacity:.09}
.bp-dotzone--dark .bp-dots-hi{opacity:.34}
.bp-dots-hi{opacity:.30;transition:opacity .6s var(--bp-ease);
  -webkit-mask-image:radial-gradient(200px circle at var(--bp-mx,50%) var(--bp-my,40%),#000 0%,rgba(0,0,0,.35) 45%,transparent 72%);
  mask-image:radial-gradient(200px circle at var(--bp-mx,50%) var(--bp-my,40%),#000 0%,rgba(0,0,0,.35) 45%,transparent 72%)}

/* ---- 7. edge-faded strip (logos, marquees) ------------------------------- */
.bp-strip{position:relative;overflow:hidden}
.bp-strip__track{display:flex;gap:56px;align-items:center;white-space:nowrap;
  width:max-content;animation:bp-slide 40s linear infinite}
@keyframes bp-slide{from{transform:translateX(0)}to{transform:translateX(-50%)}}
.bp-strip::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(90deg,var(--bp-white) 0%,rgba(255,255,255,.01) 14%,
    rgba(255,255,255,.01) 86%,var(--bp-white) 100%)}
/* on the tinted ground, override the fade colour */
.bp-strip--onpaper::after{background:linear-gradient(90deg,var(--bp-paper) 0%,
  rgba(241,241,240,.01) 14%,rgba(241,241,240,.01) 86%,var(--bp-paper) 100%)}
.bp-logo{display:inline-flex;align-items:center;gap:13px;
  font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" 108;font-size:1.42rem;letter-spacing:-.03em;
  color:var(--bp-ink);opacity:.42;transition:opacity var(--bp-dur) var(--bp-ease)}
.bp-logo:hover{opacity:1}
/* client app icons in a strip. --ico drops the wordmark and the dimming,
   because a colour app icon at .42 opacity reads as broken rather than subtle.
   The inset hairline keeps pale icons from vanishing on a white ground. */
.bp-logo--ico{opacity:1;gap:0}
.bp-logo--ico:hover{transform:translateY(-2px)}
.bp-logo--ico{transition:transform var(--bp-dur) var(--bp-ease)}
.bp-logo__ico{width:48px;height:48px;border-radius:12px;flex:none;display:block;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.07)}
@media (max-width:640px){.bp-logo__ico{width:40px;height:40px;border-radius:10px}}

/* ---- 8. boxless figure (ONE / big number / caption) ---------------------- */
.bp-figs{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:56px 30px}
.bp-fig{text-align:center}
.bp-fig__ord{display:block;margin:0 0 24px;color:var(--bp-faint)}
.bp-fig__n{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);
  font-size:clamp(3.4rem,8vw,5.4rem);line-height:.9;letter-spacing:-.05em;
  font-variant-numeric:tabular-nums;margin:0 0 24px}
.bp-fig__d{color:var(--bp-dim);font-size:13px;font-weight:600;letter-spacing:.1em;
  text-transform:uppercase;line-height:1.7;max-width:26ch;margin:0 auto}

/* ---- 9. pricing card ----------------------------------------------------- */
.bp-price{background:var(--bp-white);border:0;border-radius:26px;padding:36px 34px;
  position:relative;box-shadow:var(--bp-lift-2);display:flex;flex-direction:column;
  transition:box-shadow var(--bp-dur) var(--bp-ease),transform var(--bp-dur) var(--bp-ease)}
.bp-price:hover{box-shadow:var(--bp-lift-3);transform:translateY(-4px)}
.bp-price>a:last-child{margin-top:auto}
.bp-price--hi{box-shadow:var(--bp-lift-3);transform:translateY(-14px)}
.bp-price--hi:hover{transform:translateY(-18px)}
.bp-price__amt{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:clamp(2.6rem,6vw,3.5rem);
  letter-spacing:-.045em;line-height:1;margin:0 0 16px;font-variant-numeric:tabular-nums}
.bp-price__amt em{font-style:normal;font-family:var(--bp-body);font-weight:500;
  font-size:1rem;color:var(--bp-dim);letter-spacing:0;margin-left:6px}
.bp-price__who{color:var(--bp-dim);line-height:1.75;margin:0 0 26px;max-width:32ch;
  font-weight:500;font-size:11px;letter-spacing:.09em;text-transform:uppercase}
.bp-price__rule{height:1px;background:var(--bp-paper);margin:0 0 24px;border:0}
.bp-feats{display:grid;grid-template-columns:1fr 1fr;gap:12px 22px;margin:0 0 28px}
.bp-feats div{font-size:10.5px;color:var(--bp-dim);line-height:1.6;display:flex;gap:8px;
  font-weight:500;letter-spacing:.07em;text-transform:uppercase;font-variant-numeric:tabular-nums}
.bp-feats b{color:var(--bp-orange);font-weight:400;flex:none}
@media(max-width:560px){.bp-feats{grid-template-columns:1fr}}
.bp-orb{position:absolute;top:32px;right:32px;width:58px;height:58px;border-radius:100%;
  background:radial-gradient(circle at 32% 28%,#FF9A5C 0%,var(--bp-orange) 46%,#B43100 100%);
  box-shadow:var(--bp-glow)}
.bp-orb--dark{background:radial-gradient(circle at 32% 28%,#4A4A4A 0%,#1C1C1C 55%,#000 100%);
  box-shadow:var(--bp-lift-2)}

/* ---- 10. toggle ---------------------------------------------------------- */
.bp-toggle{width:46px;height:26px;border-radius:var(--bp-r-pill);background:#E4E4E3;
  position:relative;flex:none;border:0;cursor:pointer;padding:0}
.bp-toggle i{position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:100%;
  background:#fff;box-shadow:var(--bp-lift-1);transition:transform var(--bp-dur) var(--bp-ease)}
.bp-toggle[aria-pressed="true"],.bp-toggle.is-on{background:var(--bp-ink)}
.bp-toggle[aria-pressed="true"] i,.bp-toggle.is-on i{transform:translateX(20px)}

/* ---- 11. work list — hover swaps the preview (CSS only) ------------------ */
.bp-works{display:grid;grid-template-columns:1.05fr .95fr;gap:52px;align-items:center}
@media(max-width:860px){.bp-works{grid-template-columns:1fr;gap:30px}}
.bp-wlist{display:flex;flex-direction:column}
.bp-wlist a{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:clamp(1.6rem,3.6vw,2.5rem);
  letter-spacing:-.035em;line-height:1.28;color:var(--bp-faint);text-decoration:none;
  display:flex;align-items:baseline;gap:16px;
  transition:color var(--bp-dur) var(--bp-ease),transform var(--bp-dur) var(--bp-ease)}
.bp-wlist a:hover{color:var(--bp-ink);transform:translateX(8px)}
.bp-preview{position:relative;aspect-ratio:4/3;border-radius:26px;overflow:hidden;
  box-shadow:var(--bp-lift-2);background:var(--bp-paper)}
.bp-preview figure{position:absolute;inset:0;margin:0;opacity:0;transform:scale(1.03);
  display:grid;place-items:center;text-align:center;padding:34px;
  transition:opacity var(--bp-dur) var(--bp-ease),transform var(--bp-dur) var(--bp-ease)}
.bp-works:has(.bp-w1:hover) .bp-p1,.bp-works:has(.bp-w2:hover) .bp-p2,
.bp-works:has(.bp-w3:hover) .bp-p3,.bp-works:has(.bp-w4:hover) .bp-p4,
.bp-works:has(.bp-w5:hover) .bp-p5,
.bp-works:not(:has(.bp-wlist a:hover)) .bp-p1{opacity:1;transform:scale(1)}

/* ---- 12. signal panel — the closing CTA, ported ------------------------- */
/* the original (Space Mono + pixel sprites) is preserved untouched at
   ../../old-website/design-system/preserved/final-cta-original.html. same idea in v2. */
.bp-signal{position:relative;overflow:hidden;background:var(--bp-orange);
  border-radius:var(--bp-r-panel);padding:80px 64px;color:#fff}
.bp-signal__ring{position:absolute;border:3px solid rgba(255,255,255,.15);
  border-radius:50%;pointer-events:none}
.bp-signal__grid{display:grid;grid-template-columns:1fr 1fr;gap:48px;
  align-items:center;position:relative;z-index:2}
@media(max-width:768px){.bp-signal{padding:56px 26px}
  .bp-signal__grid{grid-template-columns:1fr;gap:32px}}
.bp-bookcard{background:var(--bp-white);color:var(--bp-ink);border:0;
  border-radius:var(--bp-r-card);padding:32px;box-shadow:var(--bp-lift-3);
  max-width:340px;width:100%;position:relative}
.bp-bookcard__tag{position:absolute;top:-12px;right:-16px;display:flex;align-items:center;
  background:var(--bp-ink);color:#fff;padding:5px 11px;border-radius:6px;
  font-family:var(--bp-body);font-weight:600;font-size:10px;
  letter-spacing:var(--bp-lbl-track);text-transform:uppercase;white-space:nowrap}
.bp-status{display:flex;align-items:center;gap:8px;margin-bottom:20px;color:var(--bp-dim)}
.bp-status i{width:8px;height:8px;border-radius:50%;background:var(--bp-good);flex:none;
  box-shadow:0 0 0 4px rgba(0,200,83,.16)}
.bp-avatars{display:flex;align-items:center;gap:12px;margin-bottom:20px}
.bp-avatars img,.bp-avatars .bp-you{width:48px;height:48px;border-radius:50%;flex:none}
.bp-avatars img{object-fit:cover;box-shadow:var(--bp-lift-1)}
.bp-you{background:var(--bp-ink);color:#fff;display:grid;place-items:center;
  font-family:var(--bp-body);font-weight:600;font-size:12px}

/* ---- 13. big footer ------------------------------------------------------ */
.bp-foot{background:var(--bp-ink);color:rgba(255,255,255,.5)}
.bp-foot a{color:inherit;text-decoration:none;display:block;margin-bottom:11px;
  font-size:14px;transition:color var(--bp-dur) var(--bp-ease)}
.bp-foot a:hover{color:#fff}
.bp-foot h4{color:rgba(255,255,255,.34);margin:0 0 18px}
.bp-bigmark{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:clamp(3rem,13.5vw,11rem);
  letter-spacing:-.055em;line-height:.82;color:rgba(255,255,255,.07);
  user-select:none;white-space:nowrap;overflow:hidden;padding:14px 0 26px}

/* ---- 14. faint column rules --------------------------------------------- */
/* Runs behind the content. Tinted sections and cards cover it, which is the
   whole point: the rules are the page's underlying grid showing through the
   gaps between the things floating on top of it. */
.bp-cols{position:absolute;inset:0;pointer-events:none;display:grid;
  grid-template-columns:repeat(3,1fr);z-index:0}
.bp-cols i{position:relative;border-right:1px solid var(--bp-rule)}
.bp-cols i:last-child{border-right:0}
/* the marker where a rule meets the top and bottom edge */
.bp-cols i:not(:last-child)::before,
.bp-cols i:not(:last-child)::after{content:"";position:absolute;right:-4px;
  width:7px;height:7px;border-radius:100%;background:var(--bp-rule-dot)}
.bp-cols i:not(:last-child)::before{top:-4px}
.bp-cols i:not(:last-child)::after{bottom:-4px}

/* ---- 15. reduced motion — non-negotiable -------------------------------- */
@media (prefers-reduced-motion:reduce){
  .bp-cta{animation:none;background-image:none}
  .bp-strip__track{animation:none;flex-wrap:wrap;white-space:normal;width:auto}
  .bp-dots-hi{display:none}
  *{transition-duration:.01ms !important;animation-duration:.01ms !important}
}

/* ==========================================================================
   PART TWO — LAYOUT & PAGE BLOCKS
   Promoted out of the homepage's page.css on 4 Sep 2026 so every page
   composes from the same named blocks instead of re-declaring them.
   A page should need almost no CSS of its own. If you are writing a rule
   that another page would also want, it belongs in this file.
   ========================================================================== */

/* ---- 16. page shell ----------------------------------------------------- */
.bp-page{max-width:1180px;margin:0 auto 60px;background:var(--bp-white);
  border-radius:var(--bp-r-panel);box-shadow:var(--bp-lift-3);position:relative;overflow:hidden}

/* ---- 17. section --------------------------------------------------------- */
.bp-sec{padding:88px 56px;position:relative}
.bp-sec--tint{background:var(--bp-paper)}
.bp-sec--center{text-align:center}
.bp-sec--center .bp-lede{margin-left:auto;margin-right:auto}
.bp-sec--tight{padding-top:56px;padding-bottom:56px}
.bp-sec h2{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.028em;line-height:.98;
  font-size:clamp(1.9rem,4.4vw,3.05rem);margin:0 0 14px;text-wrap:balance}
.bp-eyebrow{display:block;margin:0 0 16px;color:var(--bp-orange);font-weight:600;
  font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);text-transform:uppercase}
.bp-lede{color:var(--bp-dim);max-width:56ch;margin:0 0 46px;font-size:1.03rem}
@media(max-width:720px){.bp-sec{padding:64px 24px}}

/* ---- 18. hero ------------------------------------------------------------ */
/* compose: <div class="bp-hero bp-dotzone"><i class="bp-dots"></i><i class="bp-dots-hi"></i>
            <div class="bp-hero__inner"> … </div></div>                        */
.bp-hero{position:relative;overflow:hidden;padding:66px 56px 60px}
.bp-hero__inner{position:relative;z-index:2;max-width:1000px}
.bp-hero__title{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.028em;line-height:.98;
  font-size:clamp(2.5rem,6.6vw,5.1rem);margin:0 0 22px;max-width:16ch;text-wrap:balance}
.bp-hero__title em{font-style:normal;color:var(--bp-orange)}
.bp-hero__sub{font-size:1.2rem;line-height:1.5;color:var(--bp-dim);max-width:47ch;margin:0 0 34px}
.bp-hero__sub u{text-decoration-color:var(--bp-orange);text-decoration-thickness:2px;
  text-underline-offset:3px;font-weight:600;color:var(--bp-ink)}
.bp-hero__row{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.bp-hero__note{color:var(--bp-faint);font-size:14px;margin:14px 0 0}
@media(max-width:760px){.bp-hero{padding:50px 24px 46px}.bp-hero__title{max-width:none}}

/* proof row — figure over caption, never beside it */
.bp-proof{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:26px 34px;
  max-width:800px;margin:0 0 38px;padding:0;list-style:none}
.bp-proof li{display:block;margin:0;max-width:26ch;font-size:13.5px;
  color:var(--bp-dim);line-height:1.5}
.bp-proof strong{display:block;margin:0 0 10px;font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:clamp(2.1rem,4.4vw,2.9rem);
  line-height:1;letter-spacing:-.042em;color:var(--bp-orange);font-variant-numeric:tabular-nums;
  /* a figure never breaks across lines — "20-40%+" must not wrap to "20-" / "40%+" */
  white-space:nowrap}
@media(max-width:760px){.bp-proof{grid-template-columns:1fr}}

/* ---- 19. ghost button ---------------------------------------------------- */
/* the one place a border is allowed: a control affordance, not a surface edge */
.bp-btn-ghost{display:inline-block;border:1.5px solid var(--bp-ink);
  border-radius:var(--bp-r-pill);padding:14px 28px;font-weight:600;font-size:14px;
  transition:background var(--bp-dur) var(--bp-ease),color var(--bp-dur) var(--bp-ease),
             transform var(--bp-dur) var(--bp-ease)}
.bp-btn-ghost:hover{background:var(--bp-ink);color:var(--bp-white);transform:translateY(-2px)}

/* ---- 20. three-up grid + its two inhabitants ----------------------------- */
.bp-grid3{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));
  gap:44px 34px;position:relative;z-index:2}
.bp-grid3 h3{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.028em;
  font-size:1.16rem;margin:0 0 8px}
.bp-grid3 p{font-size:14.5px;color:var(--bp-dim);margin:0;line-height:1.6;max-width:34ch}
/* a. the stat: label, big orange figure, explanation */
.bp-stat__k{color:var(--bp-faint);margin:0 0 18px;font-weight:600;
  font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);text-transform:uppercase}
.bp-stat__n{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:3.6rem;letter-spacing:-.045em;
  line-height:1;color:var(--bp-orange);margin:0 0 18px;font-variant-numeric:tabular-nums}
/* b. the step: numeral, title, explanation */
.bp-step__n{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:2.4rem;color:var(--bp-orange);
  line-height:1;letter-spacing:-.04em;margin:0 0 16px;font-variant-numeric:tabular-nums}

/* ---- 21. service card ---------------------------------------------------- */
/* compose: <a class="bp-card bp-svc"> … <span class="bp-svc__go">…<span>→</span></span></a> */
.bp-svcs{display:grid;grid-template-columns:repeat(auto-fit,minmax(268px,1fr));gap:20px}
.bp-svc{display:flex;flex-direction:column}
.bp-svc h3{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.028em;
  font-size:1.3rem;margin:0 0 10px}
.bp-svc p{font-size:14.5px;color:var(--bp-dim);margin:0 0 26px;flex:1;line-height:1.55}
.bp-svc__go{display:inline-flex;align-items:center;gap:8px;font-weight:600;
  font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);text-transform:uppercase}
.bp-svc__go span{display:inline-block;transition:transform var(--bp-dur) var(--bp-ease)}
.bp-svc:hover .bp-svc__go span{transform:translateX(5px)}

/* ---- 22. testimonial, boxless ------------------------------------------- */
.bp-tst{text-align:center;position:relative;z-index:2}
.bp-tst__avatars{display:flex;justify-content:center;gap:16px;flex-wrap:wrap;margin:0 0 40px}
.bp-av{width:64px;height:64px;border-radius:100%;display:grid;place-items:center;color:#fff;
  font-family:var(--bp-display);font-weight:800;font-size:1.1rem;box-shadow:var(--bp-lift-2)}
.bp-tst blockquote{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:clamp(1.5rem,3.6vw,2.5rem);
  line-height:1.16;letter-spacing:-.03em;max-width:24ch;margin:0 auto 28px;text-wrap:balance}
.bp-tst__who{font-weight:600;font-size:13px;letter-spacing:.1em;text-transform:uppercase}
.bp-tst__role{color:var(--bp-faint);font-size:11.5px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;margin-top:7px}

/* ---- 23. FAQ — native <details>, no JS ----------------------------------- */
.bp-faq{max-width:860px;margin:0 auto}
.bp-faq details{padding:24px 4px;border-bottom:1px solid var(--bp-hair)}
.bp-faq summary{list-style:none;cursor:pointer;font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:1.14rem;letter-spacing:-.022em;
  display:flex;align-items:center;gap:14px}
.bp-faq summary::-webkit-details-marker{display:none}
.bp-faq summary::after{content:"+";margin-left:auto;color:var(--bp-orange);
  font-family:var(--bp-body);font-weight:400;font-size:1.4rem;
  transition:transform var(--bp-dur) var(--bp-ease)}
.bp-faq details[open] summary::after{transform:rotate(45deg)}
.bp-faq p{font-size:14.5px;color:var(--bp-dim);margin:16px 0 0;line-height:1.65;max-width:66ch}

/* ---- 24. post links ------------------------------------------------------ */
.bp-posts{display:grid;grid-template-columns:repeat(auto-fit,minmax(238px,1fr));gap:20px}
.bp-post{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:1.06rem;letter-spacing:-.02em;
  line-height:1.22;display:block}
.bp-post span{color:var(--bp-orange);display:block;margin-top:14px;font-size:1.2rem;
  transition:transform var(--bp-dur) var(--bp-ease)}
.bp-post:hover span{transform:translateX(5px)}

/* ---- 25. closing band ---------------------------------------------------- */
.bp-close{background:var(--bp-ink);color:#fff;padding:80px 56px}
.bp-close h2{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.028em;line-height:.98;
  font-size:clamp(1.9rem,4.4vw,2.9rem);margin:0 0 16px;max-width:20ch;color:#fff}
.bp-close p{color:rgba(255,255,255,.62);max-width:44ch;margin:0;font-size:1rem}
.bp-close__grid{display:grid;grid-template-columns:1fr 1fr;gap:48px;align-items:center}
@media(max-width:820px){.bp-close{padding:60px 24px}
  .bp-close__grid{grid-template-columns:1fr;gap:32px}}

/* ---- 26. footer ---------------------------------------------------------- */
/* Full bleed. The footer is NOT a card: it sits on the ground below the page
   panel, edge to edge, with its own inner measure so the columns still line up
   with the content above. */
.bp-foot{padding:0;position:relative;margin-top:560px}
/* A long, late fade. 300px of reserved ground, and the curve stays almost
   clear for the first half so the page does not go muddy grey - the darkening
   happens in the last third, close to the band. */
.bp-foot::before{content:"";position:absolute;left:0;right:0;bottom:100%;height:560px;
  background:linear-gradient(180deg,
    rgba(10,10,10,0) 0%,
    rgba(10,10,10,.012) 35%,
    rgba(10,10,10,.05) 55%,
    rgba(10,10,10,.14) 70%,
    rgba(10,10,10,.34) 82%,
    rgba(10,10,10,.64) 91%,
    rgba(10,10,10,.88) 96%,
    var(--bp-ink) 100%);
  pointer-events:none}
.bp-foot__inner{max-width:none;margin:0;
  padding:0 calc(10px + clamp(24px,6vw,96px))}
.bp-foot__grid{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr;gap:40px;
  padding:56px 0 48px;border-top:1px solid rgba(255,255,255,.09)}
.bp-foot__blurb{color:rgba(255,255,255,.62);font-size:15px;max-width:34ch;margin:0 0 22px}
.bp-foot__meta{font-size:12.5px;color:rgba(255,255,255,.42);line-height:1.9;
  font-variant-numeric:tabular-nums}
.bp-foot__meta b{color:rgba(255,255,255,.85);font-weight:400}
.bp-foot__bar{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;
  padding:22px 0 30px;border-top:1px solid rgba(255,255,255,.09);
  font-size:11.5px;font-weight:600;letter-spacing:.11em;text-transform:uppercase;
  color:rgba(255,255,255,.34)}
@media(max-width:820px){.bp-foot__inner{padding:0 24px}
  .bp-foot__grid{grid-template-columns:1fr 1fr}}

/* ---- 27. clients strip wrapper ------------------------------------------ */
.bp-clients{padding:34px 0 44px;background:var(--bp-white)}
.bp-clients__cap{text-align:center;color:var(--bp-faint);margin:0 0 26px;font-weight:600;
  font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);text-transform:uppercase}

/* ---- 28. mobile nav (paired with scripts.js .nav-mobile/.nav-hamburger) --- */
.nav-mobile{display:none}
/* A panel, not a bar. It was stretching edge to edge with the links stacked in
   the far left corner, which is what read as an ugly line. */
.nav-mobile.open{display:flex;flex-direction:column;gap:4px;position:fixed;
  top:78px;left:50%;transform:translateX(-50%);width:min(340px,calc(100vw - 32px));
  background:var(--bp-ink);color:#fff;padding:30px 28px;text-align:center;
  border-radius:28px;z-index:60;box-shadow:var(--bp-lift-3)}
.nav-mobile a{color:rgba(255,255,255,.62);font-size:19px;padding:9px 0;
  font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.02em;
  transition:color var(--bp-dur) var(--bp-ease)}
.nav-mobile a:hover{color:#fff}
.nav-mobile a:last-child{color:var(--bp-orange);margin-top:12px}
.nav-hamburger{display:flex;background:rgba(255,255,255,.14);border:0;
  width:40px;height:40px;border-radius:100%;cursor:pointer;flex-direction:column;
  gap:4px;align-items:center;justify-content:center;margin-left:6px;flex:none;
  transition:background var(--bp-dur) var(--bp-ease)}
.nav-hamburger:hover{background:rgba(255,255,255,.24)}
.nav-hamburger span{width:15px;height:1.5px;background:#fff;display:block;
  transition:transform var(--bp-dur) var(--bp-ease),opacity var(--bp-dur) var(--bp-ease)}
.nav-hamburger.open span:nth-child(1){transform:translateY(5.5px) rotate(45deg)}
.nav-hamburger.open span:nth-child(2){opacity:0}
.nav-hamburger.open span:nth-child(3){transform:translateY(-5.5px) rotate(-45deg)}
/* the CTA sits beside it, matching height */
.bp-pill__cta{padding:12px 20px;font-size:13px;margin-left:auto}

/* ---- 29. pricing grid + add-on row --------------------------------------- */
/* stretch, not start: two cards of unequal copy length still line up, and the
   CTA is pinned to the bottom of each so the two buttons sit on one line. */
.bp-prices{display:grid;grid-template-columns:1fr 1fr;gap:22px;align-items:stretch;
  position:relative;z-index:2}
@media(max-width:840px){.bp-prices{grid-template-columns:1fr}}
.bp-addon{display:flex;align-items:center;gap:14px;margin:0 0 28px}
.bp-addon__txt{font-size:10.5px;color:var(--bp-dim);line-height:1.6;font-weight:500;
  letter-spacing:.07em;text-transform:uppercase}
.bp-addon__amt{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:1.05rem;margin-left:auto;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}

/* ---- 30. switch — a real checkbox, for JS that listens to `change` -------- */
/* .bp-toggle (10) is a static visual. Use this when script must read state.  */
.bp-switch{position:relative;display:inline-block;width:46px;height:26px;flex:none}
.bp-switch input{position:absolute;opacity:0;width:100%;height:100%;margin:0;cursor:pointer;z-index:2}
.bp-switch__slider{position:absolute;inset:0;border-radius:var(--bp-r-pill);background:#E4E4E3;
  transition:background var(--bp-dur) var(--bp-ease)}
.bp-switch__slider::after{content:"";position:absolute;top:3px;left:3px;width:20px;height:20px;
  border-radius:100%;background:#fff;box-shadow:var(--bp-lift-1);
  transition:transform var(--bp-dur) var(--bp-ease)}
.bp-switch input:checked ~ .bp-switch__slider{background:var(--bp-orange)}
.bp-switch input:checked ~ .bp-switch__slider::after{transform:translateX(20px)}
.bp-switch input:focus-visible ~ .bp-switch__slider{outline:2px solid var(--bp-orange);outline-offset:3px}
.bp-switchrow{display:flex;align-items:center;gap:12px;margin:24px 0}
.bp-switchrow__txt{font-size:12.5px;color:var(--bp-dim);font-weight:500;
  letter-spacing:.06em;text-transform:uppercase}
.bp-switchrow.urgent-on .bp-switchrow__txt{color:var(--bp-orange)}

/* ---- 31. calculator ------------------------------------------------------ */
.bp-calc{display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:start;
  position:relative;z-index:2}
@media(max-width:840px){.bp-calc{grid-template-columns:1fr;gap:28px}}
.bp-field{margin:0 0 22px}
.bp-field label{display:block;margin:0 0 8px;color:var(--bp-faint);font-weight:600;
  font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);text-transform:uppercase}
.bp-field input{width:100%;font-family:var(--bp-body);font-size:1.4rem;font-weight:600;
  font-variant-numeric:tabular-nums;color:var(--bp-ink);background:var(--bp-white);
  border:0;border-radius:var(--bp-r-sm);padding:16px 18px;box-shadow:var(--bp-lift-1);
  transition:box-shadow var(--bp-dur) var(--bp-ease)}
.bp-field input:focus{outline:none;box-shadow:var(--bp-lift-2),0 0 0 2px var(--bp-orange)}
.bp-field .hint{display:block;margin-top:8px;font-size:12.5px;color:var(--bp-faint)}
.bp-results{display:grid;gap:18px}
.bp-result{background:var(--bp-white);border-radius:var(--bp-r-card);padding:22px 24px;
  box-shadow:var(--bp-lift-2)}
.bp-result__k{color:var(--bp-faint);margin:0 0 10px;font-weight:600;
  font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);text-transform:uppercase}
.bp-result__v{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:2.4rem;line-height:1;
  letter-spacing:-.04em;color:var(--bp-orange);font-variant-numeric:tabular-nums}
.bp-result--muted .bp-result__v{color:var(--bp-ink)}
.bp-calc__note{font-size:12.5px;color:var(--bp-faint);margin:18px 0 0}

/* ---- 32. case study — before / after / result ---------------------------- */
.bp-cases{display:grid;gap:22px}
.bp-case{background:var(--bp-white);border-radius:var(--bp-r-card);padding:28px;
  box-shadow:var(--bp-lift-2);
  transition:box-shadow var(--bp-dur) var(--bp-ease),transform var(--bp-dur) var(--bp-ease)}
.bp-case:hover{box-shadow:var(--bp-lift-3);transform:translateY(-4px)}
.bp-case__ba{display:grid;grid-template-columns:1fr;gap:18px}
.bp-case__shot{margin:0}
.bp-case__shot img{width:100%;display:block;border-radius:var(--bp-r-sm);box-shadow:var(--bp-lift-1)}
.bp-case__shot--before img{opacity:.72}
.bp-case__tag{display:block;margin:0 0 10px;color:var(--bp-faint);font-weight:600;
  font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);text-transform:uppercase}
.bp-case__result{color:var(--bp-orange);font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:1.5rem;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;margin:22px 0 0}
.bp-case__meta{display:flex;align-items:center;gap:14px;margin:22px 0 0}
.bp-case__icon{width:44px;height:44px;border-radius:12px;flex:none;object-fit:cover;
  box-shadow:var(--bp-lift-1)}
.bp-case__name{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:1.1rem;letter-spacing:-.02em}
.bp-case__cat{color:var(--bp-faint);margin-top:5px;font-weight:600;font-size:10.5px;
  letter-spacing:var(--bp-lbl-track);text-transform:uppercase;line-height:1.6}
@media(min-width:820px){.bp-case__ba{grid-template-columns:1fr 1fr}}

/* ---- 33. inclusion list -------------------------------------------------- */
.bp-incl{list-style:none;margin:0;padding:0;display:grid;gap:12px}
.bp-incl li{display:flex;gap:10px;font-size:14px;color:var(--bp-dim);line-height:1.5}
.bp-incl li::before{content:"+";color:var(--bp-orange);flex:none;font-weight:600}

/* ---- 34. bio: portrait beside prose -------------------------------------- */
/* compose: <div class="bp-bio"><img class="bp-bio__photo"><div class="bp-bio__body"> */
.bp-bio{display:grid;grid-template-columns:minmax(0,280px) minmax(0,1fr);
  gap:52px;align-items:start;position:relative;z-index:2}
.bp-bio__photo{width:100%;height:auto;display:block;
  border-radius:var(--bp-r-card);box-shadow:var(--bp-lift-2)}
.bp-bio__body{display:flex;flex-direction:column;gap:20px}
.bp-bio__body p{margin:0;color:var(--bp-dim);font-size:1.02rem;line-height:1.68;max-width:60ch}
.bp-bio__body p b{color:var(--bp-ink);font-weight:600}
.bp-bio__aside{font-size:12.5px;color:var(--bp-faint);line-height:1.5}
@media(max-width:820px){
  .bp-bio{grid-template-columns:1fr;gap:34px}
  .bp-bio__photo{max-width:220px}
}

/* ---- 35. compact quote card ---------------------------------------------- */
/* compose: <div class="bp-quotes"><figure class="bp-card bp-quote"> */
.bp-quotes{display:grid;grid-template-columns:repeat(auto-fit,minmax(290px,1fr));gap:20px}
.bp-quote{display:flex;flex-direction:column;gap:18px;margin:0}
.bp-quote blockquote{margin:0;font-size:14.8px;line-height:1.62;color:var(--bp-ink)}
.bp-quote figcaption{margin-top:auto}
.bp-quote__who{font-weight:600;font-size:12px;letter-spacing:.1em;text-transform:uppercase}
.bp-quote__role{display:block;margin-top:4px;color:var(--bp-faint);
  font-size:11px;font-weight:600;letter-spacing:.11em;text-transform:uppercase}

/* ---- 36. dark band: centred header variant ------------------------------- */
.bp-close--center{text-align:center}
.bp-close__head{max-width:640px;margin:0 auto 52px}
.bp-close__head h2{max-width:none;margin-left:auto;margin-right:auto}
.bp-close__head p{max-width:56ch;margin:20px auto 0}

/* ---- 37. form, on the dark band ------------------------------------------ */
/* compose: <form class="bp-form"> inside .bp-close. Left-aligns inside a
   centred band, so it still reads as a form and not as prose. */
.bp-form{display:flex;flex-direction:column;gap:18px;text-align:left}
.bp-form__f{display:flex;flex-direction:column;gap:8px}
.bp-form__f>label{color:rgba(255,255,255,.72);font-weight:600;
  font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);text-transform:uppercase}
.bp-form input[type="text"],
.bp-form input[type="email"],
.bp-form input[type="url"]{width:100%;box-sizing:border-box;
  font-family:var(--bp-body);font-size:16px;color:#fff;
  background:rgba(255,255,255,.07);border:0;border-radius:var(--bp-r-sm);
  padding:14px 16px;transition:box-shadow var(--bp-dur) var(--bp-ease)}
.bp-form input::placeholder{color:rgba(255,255,255,.3)}
.bp-form input:focus{outline:none;box-shadow:0 0 0 2px var(--bp-orange)}
.bp-form__hint{font-size:12.5px;color:rgba(255,255,255,.5)}
.bp-form__check{display:flex;gap:12px;align-items:flex-start;
  background:rgba(255,255,255,.04);border-radius:var(--bp-r-sm);padding:16px}
.bp-form__check input{flex:none;margin-top:3px;width:18px;height:18px;
  accent-color:var(--bp-orange);cursor:pointer}
.bp-form__check label{font-size:13.5px;color:rgba(255,255,255,.78);
  line-height:1.55;cursor:pointer}
.bp-form__check label b{color:#fff;font-weight:600}
.bp-form button{width:100%;margin-top:4px;font-family:var(--bp-body);
  font-size:15px;font-weight:600;color:#fff;background:var(--bp-orange);
  border:0;border-radius:var(--bp-r-pill);padding:15px 24px;cursor:pointer;
  box-shadow:var(--bp-glow);
  transition:box-shadow var(--bp-dur) var(--bp-ease),transform var(--bp-dur) var(--bp-ease)}
.bp-form button:hover{box-shadow:var(--bp-glow-hover);transform:translateY(-2px)}
.bp-form button:focus-visible{outline:2px solid #fff;outline-offset:3px}

/* ---- 38. tick list, on the dark band ------------------------------------- */
.bp-checks{list-style:none;margin:0;padding:0;
  display:flex;flex-direction:column;gap:18px;text-align:left}
.bp-checks li{display:flex;gap:14px;align-items:flex-start;
  font-size:15px;line-height:1.55;color:rgba(255,255,255,.88)}
.bp-checks li::before{content:"\2713";flex:none;color:var(--bp-orange);
  font-weight:700;font-size:18px;line-height:1.35}

/* ---- 39. data table ------------------------------------------------------ */
/* compose: <div class="bp-tablewrap"><table class="bp-table">
   The wrapper scrolls, so a wide table never makes the page scroll sideways. */
.bp-tablewrap{overflow-x:auto;margin:22px 0 0}
.bp-table{border-collapse:collapse;width:100%;min-width:440px;font-size:13.5px}
.bp-table th{text-align:left;padding:0 20px 10px 0;color:var(--bp-faint);
  font-weight:600;font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);
  text-transform:uppercase;white-space:nowrap}
.bp-table td{padding:12px 20px 12px 0;color:var(--bp-dim);vertical-align:top;
  line-height:1.5;box-shadow:inset 0 1px 0 var(--bp-hair);font-variant-numeric:tabular-nums}
.bp-table td:first-child{color:var(--bp-ink);font-weight:600;white-space:nowrap}

/* ---- 40. tool tags ------------------------------------------------------- */
.bp-tags{display:flex;flex-wrap:wrap;gap:8px;margin:26px 0 0;padding:0;list-style:none}
.bp-tags li{background:var(--bp-paper);color:var(--bp-dim);border-radius:var(--bp-r-pill);
  padding:7px 14px;font-size:10.5px;font-weight:600;
  letter-spacing:var(--bp-lbl-track);text-transform:uppercase}

/* ---- 41. numbered finding — ordinal beside prose ------------------------- */
/* bp-grid3 caps prose at 34ch, which is right for a short blurb and wrong for
   a paragraph. This runs full width with the numeral in the margin. */
.bp-finds{display:flex;flex-direction:column;gap:46px;position:relative;z-index:2}
.bp-find{display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:12px 26px;align-items:start}
.bp-find__n{grid-column:1;grid-row:1/-1;font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:2.4rem;line-height:.95;
  letter-spacing:-.04em;color:var(--bp-orange);font-variant-numeric:tabular-nums}
.bp-find>*:not(.bp-find__n){grid-column:2}
.bp-find h3{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.028em;
  font-size:1.3rem;line-height:1.2;margin:0}
.bp-find p{margin:0;color:var(--bp-dim);font-size:14.8px;line-height:1.68;max-width:68ch}
.bp-find a{display:inline-flex;align-items:center;gap:8px;font-weight:600;
  font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);
  text-transform:uppercase;color:var(--bp-orange)}
.bp-find a span{transition:transform var(--bp-dur) var(--bp-ease)}
.bp-find a:hover span{transform:translateX(5px)}
@media(max-width:640px){.bp-find{grid-template-columns:1fr}
  .bp-find__n{grid-row:auto;grid-column:1}
  .bp-find>*:not(.bp-find__n){grid-column:1}}

/* ---- 42. pull note ------------------------------------------------------- */
.bp-note{background:var(--bp-paper);border-radius:var(--bp-r-card);
  padding:26px 30px;margin:30px 0 0;font-size:14.5px;color:var(--bp-dim);
  line-height:1.65;max-width:68ch}
.bp-note b{color:var(--bp-ink);font-weight:600}

/* ---- 43. stat band ------------------------------------------------------- */
/* Four figures in .bp-grid3 fall to 3-up and orphan the fourth. This fills the
   rows exactly: 2x2, and 4-across only when there is genuinely room. */
.bp-stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:44px 34px;position:relative;z-index:2}
.bp-stats>div p{font-size:14.5px;color:var(--bp-dim);margin:0;line-height:1.6;max-width:38ch}
@media(min-width:1240px){.bp-stats{grid-template-columns:repeat(4,minmax(0,1fr))}}
@media(max-width:600px){.bp-stats{grid-template-columns:1fr}}

/* ---- 44. four-up prose grid ---------------------------------------------- */
/* Pairs with .bp-step__n the way .bp-stats pairs with .bp-stat__n.
   bp-grid3's minmax(250px) fits exactly three at content width, so a fourth
   item strands on a row of its own. Four paragraphs want 2x2, not 4-across:
   at 4-across each column is ~240px and a 50-word step runs ten lines. */
.bp-steps{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:46px 34px;position:relative;z-index:2}
.bp-steps h3{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.028em;
  font-size:1.16rem;margin:0 0 8px}
.bp-steps p{font-size:14.5px;color:var(--bp-dim);margin:0;line-height:1.6;max-width:46ch}
@media(max-width:700px){.bp-steps{grid-template-columns:1fr}}

/* ---- 45. article card ---------------------------------------------------- */
/* .bp-post is a bare title + arrow. An index needs the standfirst too.
   auto-FILL, not auto-fit: categories hold 3-11 articles, so the last row is
   often short — auto-fit would stretch a lone card to full width. */
.bp-arts{display:grid;grid-template-columns:repeat(auto-fill,minmax(292px,1fr));gap:20px}
.bp-art{display:flex;flex-direction:column;gap:12px}
.bp-art h3{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.022em;
  font-size:1.12rem;line-height:1.24;margin:0}
.bp-art p{font-size:14px;color:var(--bp-dim);line-height:1.58;margin:0;flex:1}
.bp-art__go{display:inline-flex;align-items:center;gap:8px;margin-top:4px;
  font-weight:600;font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);
  text-transform:uppercase;color:var(--bp-orange)}
.bp-art__go span{transition:transform var(--bp-dur) var(--bp-ease)}
.bp-art:hover .bp-art__go span{transform:translateX(5px)}

/* ==========================================================================
   ARTICLE TEMPLATE (46-52)
   Shared by all 32 guides under en/indie-creator-faqs/. Ported from the
   legacy .article-* / .pw-* vocabulary; see the mapping in README.
   base.css zeroes p margins and link underlines, so both are restored here
   rather than assumed.
   ========================================================================== */

/* ---- 46. the reading column ---------------------------------------------- */
/* .bp-artwrap is the single column every article block sits in. .bp-article is
   only the prose run inside it - it must NOT set its own width, or sibling
   blocks (breadcrumb, key points, figures) escape to full bleed. */
.bp-artwrap{max-width:716px;margin:0 auto;padding:54px 24px 88px}
.bp-article{}
.bp-article>*+*{margin-top:26px}
.bp-article h2{font-size:clamp(1.5rem,3vw,1.95rem);line-height:1.12;margin-top:76px}
/* the labelled lead-ins ('What it looks like', 'When it works') promoted out
   of the paragraphs they used to open. Short, so tighter than a section head. */
.bp-article h3{font-size:1.12rem;line-height:1.3;margin-top:44px}
.bp-article h3+p{margin-top:10px}
.bp-article p,.bp-article li{font-size:18px;line-height:1.78;color:var(--bp-ink)}
.bp-article ul,.bp-article ol{padding-left:1.15em;margin-top:18px}
.bp-article li+li{margin-top:9px}
.bp-article strong{font-weight:600}
/* an inline link needs an affordance; underline, never a border */
.bp-article p a,.bp-article li a{color:var(--bp-orange);
  text-decoration:underline;text-underline-offset:3px;
  text-decoration-thickness:1px;text-decoration-color:rgba(255,77,0,.4);
  transition:text-decoration-color var(--bp-dur) var(--bp-ease)}
.bp-article p a:hover,.bp-article li a:hover{text-decoration-color:var(--bp-orange)}

/* ---- 47. breadcrumb + article header ------------------------------------- */
.bp-crumb{display:flex;flex-wrap:wrap;align-items:center;gap:9px;margin:0 0 22px;
  font-weight:600;font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);
  text-transform:uppercase;color:var(--bp-faint)}
.bp-crumb a{color:var(--bp-orange)}
.bp-arthead{margin:0 0 34px}
.bp-arthead h1{font-size:clamp(2rem,4.6vw,3rem);line-height:1.04}
.bp-arthead__meta{margin-top:18px;font-size:13.5px;color:var(--bp-faint)}

/* ---- 48. summary box — "In short" / "Quick reference" / TL;DR ------------ */
/* One of two article box styles. This one SUMMARISES: neutral ground, flat, no
   lift. It is a recap, so it should sit quietly under the prose. Its pair is
   .bp-applied (50), which is raised and warm because it is first-hand work. */
.bp-tldr{background:var(--bp-paper);border-radius:var(--bp-r-card);
  padding:36px 38px;margin:56px 0}
.bp-tldr h2,.bp-tldr h3{margin:0 0 18px;font-family:var(--bp-body);font-weight:600;
  font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);
  text-transform:uppercase;color:var(--bp-faint);line-height:1.4}
.bp-tldr ul{list-style:none;margin:0;padding:0;display:grid;gap:13px}
.bp-tldr li{display:flex;gap:12px;font-size:15.5px;line-height:1.62;color:var(--bp-dim)}
.bp-tldr li::before{content:"";flex:none;width:6px;height:6px;margin-top:9px;
  border-radius:2px;background:var(--bp-faint)}

/* ---- 49. screenshot figure + gallery ------------------------------------- */
.bp-shot{margin:64px 0;text-align:center}
.bp-shot img{border-radius:var(--bp-r-card);box-shadow:var(--bp-lift-2);display:inline-block}
.bp-shot figcaption,.bp-gallery figcaption{margin-top:16px;font-size:13.5px;
  line-height:1.6;color:var(--bp-dim);text-align:left;max-width:46ch;
  margin-left:auto;margin-right:auto}
.bp-shot figcaption strong,.bp-gallery figcaption strong{color:var(--bp-ink);font-weight:600}
/* 250px min gives exactly 2 columns inside the 748px reading column, so a
   4-shot gallery fills 2x2 instead of leaving one stranded - and a phone
   screenshot at ~338px is legible where one at 217px is not. */
.bp-gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));
  gap:34px 24px;margin:64px 0}
.bp-gallery figure{margin:0}
.bp-gallery img{border-radius:var(--bp-r-sm);box-shadow:var(--bp-lift-2);width:100%}
.bp-gallery figcaption{font-size:12.8px;max-width:none;text-align:left}
.bp-gallery figcaption strong{display:block;margin-bottom:4px}

/* ---- 50. applied box — "How we applied this" ----------------------------- */
/* The pair to .bp-tldr. They differ by ELEVATION and STRUCTURE, not hue:
   summary is flat on the tint and recedes; this is a raised white card
   carrying the app icon, so it reads as a specific piece of work. Orange
   stays an accent here (eyebrow, marker) and never becomes the ground —
   --bp-paper is the only tint in the system. */
/* NOT a card. It sits inside one, so it is a flat tinted inset at the inner
   radius, distinguished by the app icon and the orange eyebrow rather than by
   elevation. No card inside a card, anywhere. */
.bp-applied{background:var(--bp-paper);border-radius:var(--bp-r-card);
  padding:38px 40px;margin:64px 0;box-shadow:none}
.bp-applied__head{display:flex;align-items:center;gap:15px;margin:0 0 22px}
.bp-applied__ico{width:46px;height:46px;border-radius:12px;flex:none;display:block;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.07),var(--bp-lift-1)}
p.bp-applied__label{margin:0;display:flex;align-items:center;gap:8px;
  font-weight:600;font-size:var(--bp-lbl-size);letter-spacing:var(--bp-lbl-track);
  text-transform:uppercase;color:var(--bp-orange)}
p.bp-applied__label::before{content:"";flex:none;width:6px;height:6px;
  border-radius:2px;background:var(--bp-orange)}
.bp-applied__app{margin:5px 0 0;font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.022em;
  font-size:1.12rem;line-height:1.2;color:var(--bp-ink)}
.bp-applied p{color:var(--bp-ink);font-size:16.5px;line-height:1.74}
.bp-applied p+p{margin-top:15px}
.bp-applied strong{font-weight:600}

/* ---- 51. (retired) sources / related ------------------------------------- */
/* Removed 2026-09-04. The article foot had four blocks competing for the same
   decision — sources, CTA, related articles, prev/next. Sources and related are
   gone; the CTA below is the one thing that should win there. */

/* ---- 52. article CTA + prev/next ----------------------------------------- */
/* Near-black is spent HERE rather than on the case box: this is short, it is
   the one decision the article foot should present, and contrast is what makes
   it stop the reader. */
.bp-artcta{background:var(--bp-ink);color:#fff;border-radius:var(--bp-r-panel);
  padding:72px 52px;margin:72px 0 0;text-align:center}
.bp-artcta .bp-eyebrow{margin-bottom:14px}
.bp-artcta h2{color:#fff;font-size:clamp(1.5rem,3.2vw,2.05rem);line-height:1.1;
  margin:0 auto 18px;max-width:20ch}
.bp-artcta p{color:rgba(255,255,255,.66);font-size:15.5px;line-height:1.7;
  margin:0 auto 36px;max-width:48ch}
.bp-artcta .bp-cta{display:inline-block;margin-top:8px}
.bp-artcta__note{margin-top:24px;font-size:13px;color:rgba(255,255,255,.5)}

.bp-prevnext{display:flex;justify-content:space-between;gap:18px;flex-wrap:wrap;
  margin-top:56px;padding-top:30px;box-shadow:inset 0 1px 0 var(--bp-hair)}
.bp-prevnext a{font-weight:600;font-size:var(--bp-lbl-size);
  letter-spacing:var(--bp-lbl-track);text-transform:uppercase;color:var(--bp-orange)}
.bp-prevnext a:only-child:last-child{margin-left:auto}

/* ---- 53. article header ---------------------------------------------------
   Full-bleed so the dot field has room to read, with the text still on the
   reading measure inside. The dots stop here: they must never sit behind the
   prose, where the cursor rests while someone reads for eight minutes. */
.bp-arthero{padding:60px 24px 8px}
.bp-arthero__inner{max-width:716px;margin:0 auto;position:relative;z-index:2}
.bp-arthero h1{font-size:clamp(2rem,4.6vw,3rem);line-height:1.04;margin:0}
.bp-arthero .bp-crumb{margin-bottom:20px}

/* ---- 54. article page — full-bleed cards on the ground ------------------- */
/* Measured off the reference at 1440 and 1920: the big cards are the viewport
   minus a 10px gutter each side, radius 64px, and they do NOT cap at a
   max-width - they scale with the window. Text keeps its own measure inside.
   Nesting is capped at ONE level and the inner surface is never a card:
   flat tint, 24px radius, no shadow. */
.bp-artpage{max-width:none;margin:0;position:relative;padding:44px 10px 0}
.bp-stack{display:flex;flex-direction:column;gap:16px;margin:0;position:relative;z-index:2}
.bp-stack>*{background:var(--bp-white);border-radius:var(--bp-r-panel);
  box-shadow:var(--bp-lift-2);padding:104px clamp(24px,6vw,96px);position:relative}
/* the card is the width of the window; the reading column inside it is not */
/* everything the card holds sits on the reading measure, whether it is prose,
   a summary inset or a figure. The CARD is full width; its contents are not. */
.bp-artsec>*,
.bp-stack .bp-article,
.bp-stack .bp-arthead>*,
.bp-artcta>*{max-width:716px;margin-left:auto;margin-right:auto}
.bp-stack .bp-article{padding:0}
/* Both dark panels have to restate their ground: .bp-stack>* sets white and
   wins over a single class simply by coming later in this file. */
.bp-stack>.bp-artcta{background:var(--bp-ink);padding:120px 40px}
.bp-stack>.bp-close{background:var(--bp-ink);padding:96px clamp(24px,6vw,96px)}

/* the pixel field, inside the card. Masked to the SIDE MARGINS only: the card
   is ~1420px and the reading column is 716px, so the dots fill the empty
   flanks and never sit behind a line of text. Texture at no cost to reading. */
.bp-stack>*::before{content:"";position:absolute;inset:0;border-radius:inherit;
  pointer-events:none;z-index:0;
  background-image:radial-gradient(circle,var(--bp-rule-dot) 1px,transparent 1px);
  background-size:28px 28px;
  -webkit-mask-image:linear-gradient(90deg,#000 0,#000 14%,transparent 30%,
    transparent 70%,#000 86%,#000 100%);
  mask-image:linear-gradient(90deg,#000 0,#000 14%,transparent 30%,
    transparent 70%,#000 86%,#000 100%)}
/* on the ink CTA the ink dots vanish; paint them white */
.bp-stack>.bp-artcta::before{
  background-image:radial-gradient(circle,rgba(255,255,255,.13) 1px,transparent 1px)}
/* content sits above the field */
.bp-stack>*>*{position:relative;z-index:1}
/* the same field again, brighter, revealed only where the cursor is. Two masks
   intersected: the flank window AND a spotlight at the pointer, so it can never
   light up behind a line of text. dots.js sets --bp-mx/--bp-my per card. */
.bp-stack>*::after{content:"";position:absolute;inset:0;border-radius:inherit;
  pointer-events:none;z-index:0;opacity:0;
  transition:opacity .55s var(--bp-ease);
  background-image:radial-gradient(circle,rgba(10,10,10,.30) 1px,transparent 1px);
  background-size:28px 28px;
  -webkit-mask-image:
    linear-gradient(90deg,#000 0,#000 14%,transparent 30%,transparent 70%,#000 86%,#000 100%),
    radial-gradient(190px circle at var(--bp-mx,50%) var(--bp-my,50%),#000 0%,rgba(0,0,0,.45) 48%,transparent 74%);
  -webkit-mask-composite:source-in;
  mask-image:
    linear-gradient(90deg,#000 0,#000 14%,transparent 30%,transparent 70%,#000 86%,#000 100%),
    radial-gradient(190px circle at var(--bp-mx,50%) var(--bp-my,50%),#000 0%,rgba(0,0,0,.45) 48%,transparent 74%);
  mask-composite:intersect}
.bp-stack>*.is-lit::after{opacity:1}
.bp-stack>.bp-artcta::after{
  background-image:radial-gradient(circle,rgba(255,255,255,.34) 1px,transparent 1px)}
@media(max-width:1100px){.bp-stack>*::before,.bp-stack>*::after{display:none}}
@media (prefers-reduced-motion:reduce){.bp-stack>*::after{display:none}}
.bp-prevnext{max-width:716px;margin-left:auto;margin-right:auto}

/* ---- 55. ground treatments ------------------------------------------------
   Two ways to guide the eye across the plain ground behind the cards. Use ONE.
   Both sit under the stack and never touch the cards themselves. */
/* a. vertical guides, with a dot where each meets an edge */
/* the guides run past the content and down through the gap before the footer,
   so the eye is carried into the fade rather than dropped at the last card. */
.bp-ground-rules{position:absolute;left:0;right:0;top:0;bottom:-540px;
  pointer-events:none;display:grid;grid-template-columns:repeat(3,1fr);z-index:0}
.bp-ground-rules i{position:relative;border-right:1px solid var(--bp-rule)}
.bp-ground-rules i:last-child{border-right:0}
.bp-ground-rules i:not(:last-child)::before,
.bp-ground-rules i:not(:last-child)::after{content:"";position:absolute;right:-3px;
  width:5px;height:5px;border-radius:100%;background:var(--bp-rule-dot)}
.bp-ground-rules i:not(:last-child)::before{top:0}
.bp-ground-rules i:not(:last-child)::after{bottom:0}
/* b. a pixel grid. The house motif, at a whisper. */
.bp-ground-grid{position:absolute;inset:0;pointer-events:none;z-index:0;
  background-image:radial-gradient(circle,var(--bp-rule-dot) 1px,transparent 1px);
  background-size:30px 30px;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 8%,#000 92%,transparent 100%);
  mask-image:linear-gradient(180deg,transparent 0,#000 8%,#000 92%,transparent 100%)}

@media(max-width:820px){
  .bp-artpage{padding:16px 16px 0}
  .bp-stack{gap:40px}
  .bp-stack>*{padding:36px 26px;border-radius:var(--bp-r-card)}
  .bp-stack>.bp-artcta{padding:52px 28px}
}

/* ---- 56. bare header — option B ------------------------------------------
   The title sits directly on the ground with no card under it, so the first
   card the reader meets is the article itself. One fewer surface. */
.bp-arthead--bare{background:none!important;box-shadow:none!important;
  padding:20px 8px 4px!important}

/* ---- 57. FAQ stack — one card per question, on the ground ---------------- */
/* Outside the article card and following the reference's FAQ pattern: each
   question is its own card, stacked with a gap, centred on plain ground. */
.bp-faqsec{max-width:812px;margin:0 auto;padding:150px 24px 60px;position:relative;z-index:2}
.bp-faqsec__head{text-align:center;margin:0 0 40px}
.bp-faqsec__head h2{font-size:clamp(1.7rem,3.4vw,2.4rem);line-height:1.08;margin:0}
.bp-faqstack{display:flex;flex-direction:column;gap:14px}
.bp-faqstack details{background:var(--bp-white);border-radius:var(--bp-r-card);
  box-shadow:var(--bp-lift-2);padding:32px 36px;
  transition:box-shadow var(--bp-dur) var(--bp-ease)}
.bp-faqstack details:hover{box-shadow:var(--bp-lift-3)}
.bp-faqstack summary{list-style:none;cursor:pointer;display:flex;align-items:flex-start;
  gap:24px;font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:1.22rem;
  letter-spacing:-.022em;line-height:1.28}
.bp-faqstack summary::-webkit-details-marker{display:none}
.bp-faqstack summary::after{content:"+";margin-left:auto;flex:none;color:var(--bp-ink);
  font-family:var(--bp-body);font-weight:400;font-size:1.6rem;line-height:.9;
  transition:transform var(--bp-dur) var(--bp-ease)}
.bp-faqstack details[open] summary::after{transform:rotate(45deg)}
.bp-faqstack p{margin:22px 0 0;font-size:16px;line-height:1.7;color:var(--bp-dim)}
@media(max-width:640px){.bp-faqstack details{padding:26px 24px}
  .bp-faqstack summary{font-size:1.08rem;gap:16px}}

/* ---- 58. marketing page on the ground ------------------------------------
   Same model as an article (54): cards on plain ground, viewport minus a 10px
   gutter, radius 64. The difference is the measure - an article constrains its
   contents to a 716px reading column, a marketing page does not, because its
   contents are grids, pricing pairs and galleries that want the full card. */
.bp-pagewrap{max-width:none;margin:0;position:relative;padding:44px 10px 0}
.bp-stack>.bp-pagesec{padding:96px clamp(24px,6vw,96px)}
/* the legacy sections keep their vertical rhythm and lose their own gutters,
   since the card already provides them */
.bp-pagesec>.bp-sec{padding-left:0;padding-right:0}
.bp-pagesec>.bp-sec:first-child{padding-top:0}
.bp-pagesec>.bp-sec:last-child{padding-bottom:0}
/* a tinted section inside a white card would read as a card in a card */
.bp-pagesec>.bp-sec--tint{background:none}
.bp-pagesec>.bp-hero{padding:0 0 24px}
.bp-pagesec>.bp-clients{padding-bottom:0}
@media(max-width:820px){
  .bp-pagewrap{padding:16px 16px 0}
  .bp-stack>.bp-pagesec{padding:52px 26px}
}

/* ---- 59. sections that sit on the ground, not in a card ------------------
   Not everything is a card. A heading with a row of cards under it reads far
   better than the same thing wrapped in another card - the reference does this
   throughout. The generous vertical padding is the point: the space between
   sections IS the design, not leftover margin. */
.bp-groundsec{max-width:1420px;margin:0 auto;padding:150px clamp(24px,6vw,96px)}
.bp-groundsec--tight{padding-top:96px;padding-bottom:96px}
.bp-groundhead{max-width:720px;margin:0 auto 72px;text-align:center}
.bp-groundhead .bp-eyebrow{margin-bottom:18px}
.bp-groundhead h2{font-size:clamp(1.9rem,4.2vw,3rem);line-height:1.04;margin:0 0 20px}
.bp-groundhead .bp-lede{margin:0 auto;max-width:56ch}
.bp-hero--ground{background:none;box-shadow:none;padding:96px clamp(24px,6vw,96px) 40px}
.bp-stack--narrow{max-width:1040px;margin-left:auto;margin-right:auto}
@media(max-width:820px){
  .bp-groundsec{padding:88px 24px}
  .bp-groundhead{margin-bottom:48px}
  .bp-hero--ground{padding:56px 24px 24px}
}

/* ---- 45. two-up panel row — the asymmetric beat ---------------------------
   compose:  <div class="bp-2up">                       ← direct child of .bp-stack
               <section class="bp-pagesec">…</section>  ← wide  (1.35fr)
               <section class="bp-pagesec">…</section>  ← narrow (1fr)
             </div>
   The row itself is NOT a panel — it cancels the .bp-stack>* panel styling and
   hands it to its two children instead, so you get two white panels side by side
   on the grey rather than one panel split down the middle.
   align-self:start is the whole point: each panel is only as tall as its content,
   which is what makes the pair read as asymmetric rather than as a two-column grid.
   --flip puts the narrow panel first.                                        */
.bp-2up{display:grid;grid-template-columns:1.35fr 1fr;gap:16px;
  background:none;box-shadow:none;padding:0;border-radius:0}
.bp-2up--flip{grid-template-columns:1fr 1.35fr}
.bp-2up--even{grid-template-columns:1fr 1fr}
.bp-2up>*{background:var(--bp-white);border-radius:var(--bp-r-panel);
  box-shadow:var(--bp-lift-2);padding:80px clamp(24px,4vw,64px);align-self:start}
@media(max-width:900px){
  .bp-2up,.bp-2up--flip,.bp-2up--even{grid-template-columns:1fr}
  .bp-2up>*{padding:56px 24px}
}

/* ---- 46. the fold card -------------------------------------------------
   Above the fold is ONE white panel, tall, with the copy in its upper-left and
   the space to the right left empty on purpose. Composed as a .bp-stack child
   so it inherits the panel treatment; --card only changes the inside.
   compose: <div class="bp-stack"><section class="bp-pagesec bp-foldcard">      */
.bp-foldcard{display:flex;align-items:flex-start;
  min-height:clamp(440px,72vh,720px);padding-top:clamp(64px,9vh,120px)}
.bp-hero--card{background:none;box-shadow:none;overflow:visible;padding:0;width:100%}
.bp-hero--card .bp-hero__inner{max-width:none}
.bp-hero--card .bp-hero__title{max-width:15ch}
.bp-hero--card .bp-hero__sub{max-width:44ch}
.bp-hero--card .bp-proof{margin-top:44px;justify-content:flex-start}

/* ---- 47. the icon marquee on the ground --------------------------------
   Sits on the grey between the fold card and the first section, running the
   full width and cut off at both edges, so it reads as passing through. */
.bp-iconstrip{padding:34px 0 40px}
.bp-iconstrip .bp-strip::after{background:linear-gradient(90deg,var(--bp-paper) 0%,
  rgba(241,241,240,.01) 10%,rgba(241,241,240,.01) 90%,var(--bp-paper) 100%)}
.bp-iconstrip .bp-strip__track{gap:26px;animation-duration:56s}
.bp-iconstrip img{width:88px;height:88px;border-radius:22px;flex:none;display:block;
  box-shadow:var(--bp-lift-1)}

/* ---- 48. four cards across, on the ground ------------------------------
   Not inside a panel — four separate white cards sitting on the grey, so the
   ground shows between them. Falls to 2x2, then one column.
   compose: <section class="bp-groundsec"> <h2> <div class="bp-cards4">        */
.bp-cards4{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px;
  align-items:stretch;margin-top:44px}
.bp-cards4 > *{background:var(--bp-white);border-radius:var(--bp-r-card);
  box-shadow:var(--bp-lift-2);padding:34px 30px 32px;
  display:flex;flex-direction:column;gap:14px}
.bp-cards4 .bp-find__n{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:1.5rem;line-height:1;
  color:var(--bp-orange);font-variant-numeric:tabular-nums}
.bp-cards4 h3{font-size:1.06rem;line-height:1.22;letter-spacing:-.018em}
.bp-cards4 p{font-size:14.5px;line-height:1.6;color:var(--bp-dim)}
.bp-cards4 a{margin-top:auto;padding-top:8px;font-size:13px;font-weight:600;
  color:var(--bp-ink);display:inline-flex;gap:7px;align-items:center;
  transition:gap var(--bp-dur) var(--bp-ease)}
.bp-cards4 a:hover{gap:12px}
.bp-cards4 a span{color:var(--bp-orange)}
@media(max-width:1080px){.bp-cards4{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:640px){
  .bp-cards4{grid-template-columns:1fr}
  .bp-iconstrip img{width:64px;height:64px;border-radius:16px}
  .bp-foldcard{padding-top:8px}
}

/* ---- 49. the ground rules stay on the ground ----------------------------
   The vertical guides are a texture on the grey, never a line across a card.
   Any surface that sits on the ground gets its own layer above them. */
.bp-groundsec,.bp-iconstrip{position:relative;z-index:2}
.bp-faqstack details,
.bp-cards4 > *,
.bp-stack > *{position:relative;z-index:2}

/* ---- 50. the menu panel -------------------------------------------------
   The pill stays short — mark, one CTA, the burger. Everything else lives in
   the panel that drops out of it, over a blurred page so nothing competes.
   scripts.js creates .bp-navscrim and toggles .open on it alongside the panel. */
.bp-navscrim{position:fixed;inset:0;z-index:50;opacity:0;pointer-events:none;
  background:rgba(10,10,10,.22);
  -webkit-backdrop-filter:blur(16px) saturate(.85);backdrop-filter:blur(16px) saturate(.85);
  transition:opacity .34s var(--bp-ease)}
.bp-navscrim.open{opacity:1;pointer-events:auto}

.nav-mobile.open{width:min(430px,calc(100vw - 24px));padding:54px 40px 40px;
  border-radius:34px;gap:0;top:82px}
.nav-mobile a{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.03em;
  font-size:clamp(1.7rem,5vw,2.3rem);line-height:1.24;
  color:rgba(255,255,255,.42);padding:2px 0;
  transition:color var(--bp-dur) var(--bp-ease)}
.nav-mobile a:hover,
.nav-mobile a[aria-current="page"]{color:#fff}

.nav-mobile__meta{margin-top:38px;padding-top:26px;
  border-top:1px solid rgba(255,255,255,.12);
  display:flex;flex-direction:column;gap:8px;align-items:center}
.nav-mobile__meta p{font-size:13px;color:rgba(255,255,255,.5);letter-spacing:.01em}
.nav-mobile__mail{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:1.05rem !important;
  color:#fff !important;letter-spacing:-.02em}
.nav-mobile__mail:hover{color:var(--bp-orange) !important}

/* burger becomes a close mark while the panel is open */
.nav-hamburger{z-index:61;position:relative}
.nav-hamburger span{transition:transform var(--bp-dur) var(--bp-ease),
  opacity .16s linear}
.nav-hamburger.open{background:rgba(255,255,255,.28)}
.nav-hamburger.open span:nth-child(1){transform:translateY(5.5px) rotate(45deg)}
.nav-hamburger.open span:nth-child(2){opacity:0}
.nav-hamburger.open span:nth-child(3){transform:translateY(-5.5px) rotate(-45deg)}

@media (prefers-reduced-motion: reduce){
  .bp-navscrim,.nav-hamburger span{transition:none}
}
@media(max-width:520px){
  .nav-mobile.open{padding:44px 28px 32px}
  .nav-mobile__meta{margin-top:28px}
}

/* ---- 51. the fold card runs to the edges --------------------------------
   A few pixels of ground on every side, nothing more, so the card reads as the
   surface of the page rather than a block sitting on it. The nav lives inside
   that card and stays sticky as the page moves under it. */
.bp-pagewrap{padding:10px 10px 0}
.bp-foldcard{padding-top:0;flex-direction:column}
.bp-foldcard .bp-navwrap{position:sticky;top:14px;margin:0 0 clamp(56px,10vh,120px);
  align-self:stretch}
.bp-foldcard .bp-hero--card{padding-bottom:clamp(24px,5vh,64px)}
/* the dot field is the card's own texture; it must sit under the content */
.bp-foldcard.bp-dotzone{overflow:hidden;border-radius:var(--bp-r-panel)}
.bp-foldcard .bp-dots,.bp-foldcard .bp-dots-hi{border-radius:inherit}

/* ---- 52. icon strip: variety, not a focal point -------------------------
   The strip should read as "many apps" at a glance and then get out of the way.
   Held back on opacity and saturation rather than greyed out, so the colours
   still differ from one to the next — the variety is the message.
   The track carries four passes of the set (two identical halves) so the loop
   never shows its end, even on a very wide screen. */
.bp-iconstrip .bp-strip__track{min-width:200%}
.bp-iconstrip img{opacity:.6;filter:saturate(.72);
  transition:opacity var(--bp-dur) var(--bp-ease),filter var(--bp-dur) var(--bp-ease)}
.bp-iconstrip:hover img{opacity:.78;filter:saturate(.9)}
.bp-iconstrip img:hover{opacity:1;filter:none}

/* ---- 53. one h2 size, everywhere ----------------------------------------
   "Why isn't your app growing?" sat on a bare <h2> with no rule and fell back
   to the browser default (~24px), while .bp-sec h2 ran to 3.05rem — the two
   headings of the same rank were rendering at twice the difference. One clamp
   now governs every section heading, at the midpoint of the old two. */
.bp-h2,
.bp-sec h2,
.bp-groundsec > h2,
.bp-groundhead h2,
.bp-faqsec__head h2{
  font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.026em;
  font-size:clamp(1.75rem,3.4vw,2.55rem);line-height:1.05;text-wrap:balance;
  margin:0 0 16px}
.bp-groundsec > h2{margin-bottom:0}

/* ---- 54. wide screens ---------------------------------------------------
   At 27" the content was a column hugging the left of a very wide card. More
   side padding and a wider measure, so the card is used rather than crossed. */
.bp-stack>.bp-pagesec{padding:96px clamp(24px,6.5vw,180px)}
.bp-groundsec{max-width:1680px;padding:120px clamp(24px,6.5vw,180px)}

/* ---- 55. the nav floats over the fold card, and sticks page-wide --------
   It has to live OUTSIDE the card: a sticky element only sticks inside its own
   containing block, so nesting it in the fold card meant it scrolled away the
   moment that card ended. Out here it sticks for the whole page, and a negative
   margin drops it onto the card so it still reads as sitting inside it. */
.bp-navwrap{position:sticky;top:12px;z-index:40;margin:0 0 -54px}
.bp-foldcard{padding-top:88px}
.bp-foldcard .bp-hero--card{padding-bottom:clamp(12px,3vh,36px)}
@media(max-width:820px){
  .bp-navwrap{margin-bottom:-48px}
  .bp-foldcard{padding-top:74px}
}

/* ---- 56. a measure, and a fixed type scale ------------------------------
   At 27" the content was spreading the full width of the card and reading as a
   line to be crossed rather than a column to be read. Everything now sits on a
   shared centred measure — left-aligned inside it, centred on the page.
   Sizes are fixed rather than fluid past the breakpoint: 71 / 48 / 18 / 16. */
:root{--bp-measure:1120px}

.bp-stack>.bp-pagesec>.bp-sec,
.bp-groundsec>*,
.bp-foldcard .bp-hero--card,
.bp-faqsec__head,
.bp-faqstack{max-width:var(--bp-measure);margin-left:auto;margin-right:auto}
.bp-stack>.bp-pagesec{padding-left:clamp(24px,5vw,72px);padding-right:clamp(24px,5vw,72px)}
.bp-groundsec{max-width:none;padding-left:clamp(24px,5vw,72px);padding-right:clamp(24px,5vw,72px)}

/* H1 — 71px */
.bp-h1,.bp-hero__title{font-size:clamp(2.5rem,6vw,4.4375rem);line-height:1.04;
  letter-spacing:-.03em;max-width:17ch}
/* H2 — 48px, one size for every section heading */
.bp-h2,
.bp-sec h2,
.bp-groundsec > h2,
.bp-groundhead h2,
.bp-faqsec__head h2{font-size:clamp(1.9rem,3.6vw,3rem);line-height:1.06;
  letter-spacing:-.026em;margin:0 0 18px}
/* H3 — the card and step titles */
.bp-h3,.bp-sec h3,.bp-cards4 h3,.bp-steps h3{font-size:1.25rem;line-height:1.24;
  letter-spacing:-.02em}
/* body — 18px lead, 16px inside cards and lists */
.bp-hero__sub,.bp-lede{font-size:1.125rem;line-height:1.6;max-width:58ch}
.bp-sec p,.bp-steps p,.bp-bio__body p,.bp-incl li{font-size:1rem;line-height:1.65}
.bp-cards4 p,.bp-faqstack p{font-size:1rem;line-height:1.65}

@media(max-width:820px){
  .bp-stack>.bp-pagesec{padding-left:26px;padding-right:26px}
  .bp-groundsec{padding-left:24px;padding-right:24px}
  .bp-h3,.bp-sec h3,.bp-cards4 h3,.bp-steps h3{font-size:1.14rem}
}

/* ---- 57. the page has a frame -------------------------------------------
   Not edge-to-edge on a large display: the whole page caps and centres, so the
   grey shows as a deliberate margin either side. Below that width it still
   fills, which is why it looked full-bleed on a laptop and adrift at 27".      */
.bp-pagewrap{margin:0 auto}

/* text stays on the reading measure; the card row uses the full frame, because
   four columns squeezed into a 1120px measure is 260px each and reads cramped */
.bp-groundsec>.bp-cards4{max-width:none}
.bp-cards4{gap:20px}
@media(min-width:1200px){ .bp-cards4 > *{padding:38px 32px 34px} }

/* ---- 58. the pill sits in the card and stays put ------------------------
   sticky could not do both: nested in the card it stopped sticking when the
   card ended, and lifted out it no longer read as part of it. fixed has no
   containing-block dependency, so the pill is pinned to the viewport while the
   card's top padding makes it sit inside the card at rest.
   The strip is click-through; only the pill itself takes pointer events. */
.bp-navwrap{position:fixed;top:14px;left:0;right:0;z-index:40;margin:0;
  display:flex;justify-content:center;pointer-events:none}
.bp-navwrap > *{pointer-events:auto}
.bp-foldcard{padding-top:104px}
@media(max-width:820px){
  .bp-navwrap{top:10px}
  .bp-foldcard{padding-top:84px}
}

/* ---- 59. one content width, on the card and on the ground ---------------
   The diagnosis row sat on the frame while the framework sat on the reading
   measure, so two adjacent sections started and ended at different x. Both now
   share one width and one gutter, so every left edge on the page lines up.
   Prose keeps its own ch cap, so a wider container never means a longer line. */
:root{--bp-measure:1290px}
.bp-stack>.bp-pagesec>.bp-sec,
.bp-groundsec>*,
.bp-groundsec>.bp-cards4,
.bp-foldcard .bp-hero--card,
.bp-faqsec__head,
.bp-faqstack{max-width:var(--bp-measure);margin-left:auto;margin-right:auto}
.bp-groundsec{padding-left:clamp(24px,5vw,72px);padding-right:clamp(24px,5vw,72px)}
.bp-sec p:not(.bp-lede):not(.bp-hero__sub){max-width:62ch}

/* ---- 60. the bio sits on the ground -------------------------------------
   No card behind it: the portrait and the prose are the objects, and the grey
   is what separates the section from the framework card above and the pricing
   card below. Without a panel the section needs its own vertical rhythm. */
.bp-groundsec--tight{padding-top:96px;padding-bottom:96px}
.bp-groundsec .bp-bio{margin-top:34px}
@media(max-width:820px){.bp-groundsec--tight{padding-top:64px;padding-bottom:64px}}

/* ---- 62. the pill sits on the ground, the card starts under it ----------
   Simplest version and the one that behaves: the pill is fixed over the grey,
   the page starts below it. No overlap to maintain, nothing to break on scroll.
   The fold card is sized by its content — no min-height, so there is no dead
   space under the CTA. */
.bp-pagewrap{padding-top:78px}
.bp-navwrap{top:16px}
.bp-foldcard{padding-top:clamp(52px,7vh,84px);
  padding-bottom:clamp(52px,7vh,84px)}
.bp-foldcard .bp-hero--card{padding-bottom:0}
.bp-foldcard .bp-hero__row{margin-bottom:0}
@media(max-width:820px){
  .bp-pagewrap{padding-top:66px}
  .bp-foldcard{padding-top:44px;padding-bottom:44px}
}

/* ---- 63. one box per section, so every edge lines up --------------------
   Centring each child independently meant the heading and the card row each
   found their own centre and started at different x. The section now has ONE
   inner box and the children fill it, which is why the edges agree. */
.bp-groundsec,.bp-stack>.bp-pagesec{max-width:calc(var(--bp-measure) + 2 * clamp(24px,5vw,72px));
  margin-left:auto;margin-right:auto}
.bp-groundsec>*,
.bp-stack>.bp-pagesec>.bp-sec,
.bp-groundsec>.bp-cards4,
.bp-foldcard .bp-hero--card,
.bp-faqsec__head,.bp-faqstack{max-width:none;margin-left:0;margin-right:0}
.bp-faqsec{max-width:calc(var(--bp-measure) + 2 * clamp(24px,5vw,72px))}

/* ---- 64. pricing, plain ------------------------------------------------
   The old cards carried an orb, a label, a tinted panel, a second button style
   and bold inside every bullet. Six devices doing the job of a rule and a list.
   compose: <div class="bp-plans"><div class="bp-plan"> … */
.bp-plans{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px;margin-top:40px}
.bp-plan{background:var(--bp-white);border-radius:var(--bp-r-card);
  box-shadow:var(--bp-lift-2);padding:40px 36px 34px;
  display:flex;flex-direction:column}
.bp-plan h3{font-size:1.5rem;letter-spacing:-.024em;margin:0}
.bp-plan__sub{font-size:.95rem;color:var(--bp-dim);margin:8px 0 0}
.bp-plan__amt{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:2.9rem;letter-spacing:-.035em;
  line-height:1;font-variant-numeric:tabular-nums;margin:26px 0 0}
.bp-plan__amt span{font-family:var(--bp-body);font-weight:500;font-size:.9rem;
  letter-spacing:0;color:var(--bp-faint);margin-left:9px}
.bp-plan__terms{font-size:.9rem;color:var(--bp-dim);margin:10px 0 0}
.bp-plan__who{font-size:.85rem;color:var(--bp-faint);font-style:italic;margin:16px 0 0}
.bp-plan__lead{font-size:1rem;color:var(--bp-ink);font-weight:600;margin:14px 0 0}
.bp-plan__rule{border:0;border-top:1px solid var(--bp-hair);margin:26px 0 0}
.bp-plan__list{list-style:none;margin:22px 0 0;padding:0;
  display:flex;flex-direction:column;gap:13px}
.bp-plan__list li{display:grid;grid-template-columns:auto 1fr;gap:14px;
  font-size:.95rem;line-height:1.55;color:var(--bp-dim)}
.bp-plan__list li::before{content:"\2014";color:var(--bp-faint)}
.bp-plan__foot{font-size:.8rem;line-height:1.55;color:var(--bp-faint);
  margin:26px 0 0}
.bp-plan__cta{margin-top:24px;text-align:center;padding:15px 24px;
  border-radius:var(--bp-r-pill);font-size:.95rem;font-weight:600;
  background:var(--bp-white);color:var(--bp-ink);
  box-shadow:inset 0 0 0 1px rgba(10,10,10,.14);
  transition:box-shadow var(--bp-dur) var(--bp-ease),background var(--bp-dur) var(--bp-ease)}
.bp-plan__cta:hover{box-shadow:inset 0 0 0 1px rgba(10,10,10,.3)}
.bp-plan--hi .bp-plan__cta{background:var(--bp-ink);color:#fff;box-shadow:none}
.bp-plan--hi .bp-plan__cta:hover{background:#000}
/* the foot sits on the baseline of both cards regardless of list length */
.bp-plan__list{flex:1}
@media(max-width:820px){
  .bp-plans{grid-template-columns:1fr}
  .bp-plan{padding:32px 26px 28px}
}

/* ---- 65. the framework deck: two rows, not four cards -------------------
   Four sticky cards meant four overlapping shadows piling into a dark smear,
   and each card was far taller than its two lines of copy deserved. Two rows
   of two: the second row closes over the first, one overlap instead of three,
   and the cards are sized to their content.
   Only the ROW is sticky — the cards inside it are ordinary. */
.bp-deck{display:flex;flex-direction:column;gap:20px;margin-top:40px}
.bp-deck__row{position:sticky;top:calc(104px + var(--i) * 22px);
  z-index:calc(var(--i) + 1);
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px}
.bp-deckcard{border-radius:var(--bp-r-card);padding:34px 32px 36px;
  display:flex;flex-direction:column;gap:11px;
  box-shadow:var(--bp-lift-2)}
.bp-deckcard__n{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:.85rem;letter-spacing:.02em;
  font-variant-numeric:tabular-nums;opacity:.5;margin:0}
.bp-deckcard h3{font-size:1.32rem;line-height:1.16;letter-spacing:-.022em;margin:0}
.bp-deckcard p{font-size:1rem;line-height:1.58;max-width:46ch;margin:0}

.bp-deckcard--white{background:var(--bp-white);color:var(--bp-ink)}
.bp-deckcard--white p{color:var(--bp-dim)}
.bp-deckcard--ink{background:var(--bp-ink);color:#fff}
.bp-deckcard--ink p{color:rgba(255,255,255,.72)}
.bp-deckcard--ink b{color:#fff}
.bp-deckcard--orange{background:var(--bp-orange);color:#fff}
.bp-deckcard--orange p{color:rgba(255,255,255,.88)}
.bp-deckcard--orange b{color:#fff}

@media (prefers-reduced-motion: reduce){ .bp-deck__row{position:static} }
@media(max-width:820px){
  .bp-deck__row{position:static;grid-template-columns:1fr;gap:16px}
  .bp-deck{gap:16px}
  .bp-deckcard{padding:28px 24px 30px}
}

/* ---- 66. widen the shared column ----------------------------------------
   Aligning every section on one box was right, but I aligned them on the
   NARROWER of the two. The column now runs as wide as the frame allows, so the
   diagnosis row, the deck and the pricing are all wide — and still aligned. */
:root{--bp-measure:1356px}

/* and give the deck cards back the padding and type I trimmed: two-up already
   halved their width, shrinking the inside as well was a second cut */
.bp-deckcard{padding:40px 38px 42px;gap:13px}
.bp-deckcard h3{font-size:1.45rem;line-height:1.14}
.bp-deckcard p{font-size:1.0625rem;line-height:1.6;max-width:none}
.bp-deckcard__n{font-size:.9rem}
@media(max-width:820px){ .bp-deckcard{padding:28px 24px 30px} }

/* ---- 67. the frame, measured off the reference --------------------------
   Measured on aigenix at a 2560px viewport: the page card is 1920 wide with a
   320px ground margin either side, and its content column runs ~1420 inside
   that. Ours was a 1520 card with a 1356 column — a narrower card AND a wider
   column inside it, which is why the cards read as filling a small page.
   Both numbers now match the reference. */
.bp-pagewrap{max-width:1920px}
:root{--bp-measure:1420px}

/* ---- 68. panels fill the frame; only their contents are inset -----------
   Block 63 capped the SECTION, which capped the white card itself — so every
   time the column widened the card shrank with it. The panel now spans the
   whole 1920 frame, and one inner box holds its children on the measure.
   Same max-width and same auto margins on every child, so edges still agree. */
.bp-stack>.bp-pagesec,.bp-groundsec,.bp-faqsec{max-width:none}
.bp-stack>.bp-pagesec>.bp-sec,
.bp-groundsec>*,
.bp-foldcard .bp-hero--card,
.bp-faqsec__head,
.bp-faqstack{max-width:var(--bp-measure);margin-left:auto;margin-right:auto}
:root{--bp-measure:1600px}

/* ---- 69. ONE gutter, every section ---------------------------------------
   The drift came from two systems running at once: panels were inset by their
   padding AND by a centred max-width, ground sections only by their padding.
   Different arithmetic, different left edge, every section.
   Now there is exactly one number. Content width = frame - 2 * gutter, the same
   whether the section is a white panel or sits on the grey. No inner max-width
   anywhere, so nothing can find its own centre.
   The FAQ keeps its own narrower measure — that component was signed off. */
:root{--bp-gutter:clamp(24px,4.2vw,150px)}

.bp-stack>.bp-pagesec,
.bp-groundsec{max-width:none;
  padding-left:var(--bp-gutter);padding-right:var(--bp-gutter)}

.bp-stack>.bp-pagesec>.bp-sec,
.bp-groundsec>*,
.bp-foldcard .bp-hero--card{max-width:none}

@media(max-width:820px){ :root{--bp-gutter:24px} }

/* ---- 70. the question cards sit at 45% of the screen --------------------
   Deliberately narrower than every other section: a question and its answer
   read better short, and the width is the only thing marking the FAQ as a
   different kind of block. 45vw with a floor, so it never collapses on a laptop
   and never runs past the viewport on a phone. */
.bp-faqsec{max-width:none;
  width:min(100% - 48px, max(560px, 45vw));
  margin-left:auto;margin-right:auto;
  padding-left:0;padding-right:0}

/* ---- 71. let the hero use the card --------------------------------------
   The fold card was already spanning the frame; the HEADLINE was capped at 15ch
   and the sub at 44ch, so the copy sat in the left third of a wide white card
   and the whole thing read as narrow. The card was never the problem. */
.bp-foldcard{padding-left:var(--bp-gutter);padding-right:var(--bp-gutter)}
.bp-hero--card{width:100%;max-width:none}
.bp-hero--card .bp-hero__inner{max-width:none;width:100%}
.bp-hero--card .bp-hero__title{max-width:16ch}
.bp-hero--card .bp-hero__sub{max-width:62ch}

/* ---- 72. pricing on the ground, the loop as the primary CTA -------------
   No panel behind the two plans — they are the cards, and the grey separates
   them from the bio above and the FAQ below. The Loop takes the orange CTA so
   the page has exactly one primary action in the pricing section. */
#pricing.bp-groundsec{padding-top:104px;padding-bottom:104px}
#pricing .bp-plans{margin-top:44px}
.bp-plan--hi .bp-plan__cta{background:var(--bp-orange);color:#fff;box-shadow:none}
.bp-plan--hi .bp-plan__cta:hover{background:var(--bp-orange);filter:brightness(1.06)}
@media(max-width:820px){ #pricing.bp-groundsec{padding-top:64px;padding-bottom:64px} }

/* ==========================================================================
   73. THE CANONICAL SCALE — everything above this line that disagrees is dead.
   One place to read the type scale and the card rules from. Written last so it
   wins, and written as one block so the next person does not have to diff
   seventy-two of them to find out what the size of an h3 is.
   ========================================================================== */

/* --- type ---------------------------------------------------------------- */
.bp-h1,.bp-hero__title      {font-size:clamp(2.5rem,5.4vw,4.4375rem);line-height:1.04;letter-spacing:-.03em}
.bp-h2,.bp-sec h2,
.bp-groundsec>h2,
.bp-groundhead h2,
.bp-faqsec__head h2         {font-size:clamp(1.9rem,3.6vw,3rem);line-height:1.06;letter-spacing:-.026em}
.bp-h3,.bp-sec h3,
.bp-cards4 h3,.bp-deckcard h3,
.bp-plan h3                 {font-size:1.5rem;line-height:1.18;letter-spacing:-.022em}
.bp-hero__sub,.bp-lede      {font-size:1.125rem;line-height:1.6}
.bp-sec p,.bp-cards4 p,.bp-deckcard p,
.bp-plan__list li,.bp-incl li,
.bp-faqstack p,.bp-bio__body p{font-size:1rem;line-height:1.65}
.bp-plan__terms,.bp-plan__sub{font-size:.9375rem}
.bp-plan__who,.bp-plan__foot,
.bp-note                     {font-size:.8125rem;line-height:1.6}

/* --- the reading caps: prose never runs the width of a wide card --------- */
.bp-hero--card .bp-hero__title{max-width:16ch}
.bp-hero--card .bp-hero__sub  {max-width:46ch}
.bp-lede                      {max-width:58ch}
.bp-sec p:not(.bp-lede):not(.bp-hero__sub){max-width:62ch}

/* --- cards --------------------------------------------------------------- */
.bp-cards4>*,.bp-deckcard,.bp-plan,.bp-faqstack details{
  border-radius:var(--bp-r-card);          /* 24px — panels use --bp-r-panel 64 */
  box-shadow:var(--bp-lift-2);
  padding:36px 32px}
.bp-cards4,.bp-deck,.bp-deck__row,.bp-plans{gap:20px}
@media(min-width:1200px){
  .bp-cards4>*,.bp-deckcard,.bp-plan{padding:40px 36px}
  .bp-faqstack details{padding:32px 36px}
}
@media(max-width:820px){
  .bp-cards4>*,.bp-deckcard,.bp-plan,.bp-faqstack details{padding:28px 24px}
  .bp-cards4,.bp-deck,.bp-plans{gap:16px}
}

/* ==========================================================================
   74. WIDTH — the last word. Supersedes every width rule above it.
   Three fixed numbers, no vw arithmetic. vw was the bug: a gutter that scaled
   with the viewport meant content hugged the edges on a 15" and floated on a
   27". A fixed column breathes at every size, which is the whole reason the
   reference sites look calm.
       frame   1920  the white card. Aigenix's number.
       column  1150  the content inside it. Tapas's number.
       gutter    72  the minimum breathing room before the column takes over.
   ========================================================================== */
:root{--bp-frame:1920px; --bp-col:1150px; --bp-gutter:clamp(20px,5vw,72px)}

.bp-pagewrap{max-width:var(--bp-frame);margin:0 auto;padding:78px 10px 0}

/* every section, panel or ground, uses the same gutter */
.bp-stack>.bp-pagesec,
.bp-groundsec{max-width:none;
  padding-left:var(--bp-gutter);padding-right:var(--bp-gutter)}

/* and one column inside it — the SAME max-width and auto margins on every
   child, which is what keeps their left edges on one line */
.bp-stack>.bp-pagesec>.bp-sec,
.bp-groundsec>*,
.bp-foldcard .bp-hero--card{
  max-width:var(--bp-col);margin-left:auto;margin-right:auto}

/* the FAQ is deliberately narrower still */
.bp-faqsec{max-width:none;width:min(100% - 40px, max(560px, 42vw));
  margin-left:auto;margin-right:auto;padding-left:0;padding-right:0}

@media(max-width:820px){
  :root{--bp-gutter:24px}
  .bp-pagewrap{padding-top:66px}
}

/* ==========================================================================
   75. ALIGNMENT — the corrective. Measured, not guessed.
   At 1440 the content left edges were 283 / 82 / 145 / 418. Four values for
   what should be one column. Every one of them was a specificity collision
   between my own blocks:
     .bp-groundsec > h2      margin shorthand (0,1,1) beat  .bp-groundsec > * (0,1,0)
     .bp-groundsec > .bp-cards4  max-width:none (0,2,0) beat the same rule
     .bp-hero--card .bp-hero__title  auto margins centred the hero
     .bp-sec p (0,1,1) beat .bp-lede (0,1,0), so the lead rendered at 16px
   The selectors below are written at the specificity needed to actually win.
   ========================================================================== */

/* one column, every section, every child that carries content */
.bp-groundsec > h2,
.bp-groundsec > p,
.bp-groundsec > div,
.bp-groundsec > ul,
.bp-groundsec > .bp-cards4,
.bp-groundsec > .bp-plans,
.bp-groundsec > .bp-bio,
.bp-stack > .bp-pagesec > .bp-sec{
  max-width:var(--bp-col);
  margin-left:auto;margin-right:auto}
.bp-groundsec > h2{margin-bottom:18px}

/* the hero is LEFT aligned inside that column, never centred */
.bp-foldcard .bp-hero--card{max-width:var(--bp-col);margin-left:auto;margin-right:auto;
  text-align:left}
.bp-hero--card .bp-hero__inner{margin-left:0;margin-right:0;text-align:left;max-width:none}
.bp-hero--card .bp-hero__title{margin-left:0;margin-right:0;max-width:16ch}
.bp-hero--card .bp-hero__sub{margin-left:0;margin-right:0;max-width:46ch}
.bp-hero--card .bp-hero__row{justify-content:flex-start}

/* the lead is 18px — .bp-sec p was winning at 16 */
.bp-sec p.bp-lede,.bp-groundsec p.bp-lede,p.bp-hero__sub{font-size:1.125rem;line-height:1.6}

/* ==========================================================================
   76. THE FOLD CARD, AND VERTICAL RHYTHM
   Two findings from measuring at 1440:
   (a) .bp-foldcard was display:flex + align-items:flex-start, so .bp-hero--card
       shrank to its content (798px) and centred — the hero sat at L=321 while
       every other section sat at L=145. A flex container shrinking its child
       was the cause, not any margin.
   (b) Section padding was 120 / 96 / 104 / 150-60, with panels at 104. Four
       different vertical rhythms chosen at four different moments.
       One token now. Panels breathe slightly more than the ground because they
       have an edge to clear; that is the only intentional difference.
   ========================================================================== */
:root{--bp-v:120px; --bp-v-panel:132px}

.bp-foldcard{align-items:stretch}
.bp-foldcard .bp-hero--card{width:100%}

.bp-groundsec,
.bp-groundsec--tight,
#pricing.bp-groundsec{padding-top:var(--bp-v);padding-bottom:var(--bp-v)}
.bp-stack>*{padding-top:var(--bp-v-panel);padding-bottom:var(--bp-v-panel)}
.bp-foldcard{padding-top:clamp(52px,7vh,84px);padding-bottom:clamp(52px,7vh,84px)}
.bp-faqsec{padding-top:var(--bp-v);padding-bottom:var(--bp-v)}
.bp-iconstrip{padding-top:36px;padding-bottom:36px}

@media(max-width:820px){
  :root{--bp-v:72px; --bp-v-panel:76px}
  .bp-foldcard{padding-top:44px;padding-bottom:44px}
}

/* ==========================================================================
   77. THE ONE THAT WAS BREAKING EVERYTHING
   .bp-foldcard measured 942px wide with margin-left/right:auto and 239px of
   ground either side, inside a 1420px stack — the white card had been
   shrink-wrapped the whole time.
   Cause: block 63 set `margin-left:auto;margin-right:auto` on
   .bp-stack > .bp-pagesec together with a max-width. Later blocks removed the
   max-width but never the margins, and AUTO MARGINS ON A FLEX ITEM make it
   shrink to content and centre. The card was never obeying the frame.
   Panels are flex items: they fill, they do not centre. The column inside
   them does the centring.
   ========================================================================== */
.bp-stack > *{margin-left:0;margin-right:0;width:100%;align-self:stretch}

/* ==========================================================================
   78. THE FOOTER WORDMARK, AND MORE AIR
   (a) .bp-bigmark was sized in vw with white-space:nowrap and overflow:hidden,
       so past the frame cap the type kept growing while the container stopped —
       "Brewed in Pixe|". vw is measured against the VIEWPORT; the wordmark lives
       in a container that stops at 1920. Sized in cqi it is measured against the
       container it actually sits in, so it fits by construction at any width.
   (b) Section rhythm 120 -> 160. The page was consistent but tight.
   ========================================================================== */
.bp-foot__inner{container-type:inline-size}
.bp-bigmark{font-size:min(11rem, 11.4cqi);overflow:visible}
@supports not (font-size: 1cqi){
  .bp-bigmark{font-size:clamp(3rem,10.4vw,9.4rem)}
}

:root{--bp-v:160px; --bp-v-panel:172px}
@media(max-width:820px){ :root{--bp-v:84px; --bp-v-panel:88px} }

/* ==========================================================================
   79. HEADINGS LOOK THE SAME, AND THE PLAN FLAG
   <em> in a heading was rendering italic, so two headings on the page had a
   different voice from the rest. It marks the orange word, nothing else.
   ========================================================================== */
h1 em,h2 em,h3 em,
.bp-hero__title em,.bp-sec h2 em,.bp-groundsec h2 em,
.bp-close h2 em{font-style:normal;font-weight:inherit;color:var(--bp-orange)}

/* the popular flag, the one thing that separates the two plans at a glance */
.bp-plan{position:relative}
.bp-plan__flag{position:absolute;top:-13px;left:36px;
  background:var(--bp-ink);color:#fff;border-radius:var(--bp-r-pill);
  font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);
  font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;
  padding:7px 15px;white-space:nowrap;box-shadow:var(--bp-lift-1)}
.bp-plans{padding-top:13px}
@media(max-width:820px){ .bp-plan__flag{left:24px} }

/* the strip now lives inside the fold card: it spans the card, not the page */
.bp-foldcard .bp-iconstrip{width:100%;max-width:none;
  margin-left:calc(var(--bp-gutter) * -1);margin-right:calc(var(--bp-gutter) * -1);
  width:calc(100% + var(--bp-gutter) * 2);
  padding-top:44px;padding-bottom:0}
.bp-foldcard .bp-iconstrip .bp-strip::after{
  background:linear-gradient(90deg,var(--bp-white) 0%,rgba(255,255,255,.01) 10%,
    rgba(255,255,255,.01) 90%,var(--bp-white) 100%)}

/* ==========================================================================
   80. THE NAV PILL, 33% SHORTER
   Height was 52px — driven by the 40px burger plus 6px of pill padding either
   side. Target 35px, so every vertical dimension scales by the same 0.67 and
   the pill keeps its proportions rather than just getting squashed.
       burger  40 -> 27      pill padding  6 -> 4
       CTA     9/17 -> 6/13  round         32 -> 22
   The gap between the mark and the CTA goes 22 -> 33 (+50%), split across the
   mark's right margin and the CTA's left margin as before.
   ========================================================================== */
.bp-pill{padding:4px 4px 4px 18px;gap:2px}
.bp-pill__mark{font-size:13px;margin-right:22px}
.bp-pill__cta{padding:6px 13px;font-size:11px;margin-left:11px}
.bp-pill__lk{font-size:11.5px;padding:5px 9px}
.bp-pill__round{width:22px;height:22px;font-size:9px;margin-left:2px}
.nav-hamburger{width:27px;height:27px;gap:3px;margin-left:4px}
.nav-hamburger span{width:12px;height:1.5px}
/* the close mark has to follow the new bar spacing: bars now sit at ±4.5px */
.nav-hamburger.open span:nth-child(1){transform:translateY(4.5px) rotate(45deg)}
.nav-hamburger.open span:nth-child(3){transform:translateY(-4.5px) rotate(-45deg)}
/* the CTA became the tallest child (30px) once the burger came down to 27, so
   it, not the burger, was setting the pill height. Pinned to match. */
.bp-pill__cta{line-height:15px;padding:6px 13px;margin-left:10px}
.bp-pill__mark{margin-right:21px}

/* ==========================================================================
   81. THE FOLD FILLS THE SCREEN
   Still content-driven: min-height is a FLOOR, not a fixed height — longer copy
   pushes the card taller, it is never clipped or scrolled inside.
   The floor is the viewport minus the space above the card (the fixed pill and
   the page's top padding) and a small margin at the bottom, so the strip's
   lower edge sits just at the fold and the page reads as continuing.
   dvh, not vh: on mobile vh is the tallest possible viewport, so a 100vh hero
   is always taller than the screen while the browser chrome is showing.
   ========================================================================== */
.bp-foldcard{
  min-height:calc(100vh - 118px);
  min-height:calc(100dvh - 118px);
  padding-top:clamp(56px,9vh,132px);
  padding-bottom:clamp(56px,9vh,132px);
  justify-content:center}
@media(max-width:820px){
  .bp-foldcard{min-height:calc(100dvh - 96px);
    padding-top:clamp(40px,6vh,72px);padding-bottom:clamp(40px,6vh,72px)}
}
/* .bp-stack > .bp-pagesec sets `padding: 96px …` as a shorthand at (0,2,0),
   which beat .bp-foldcard (0,1,0) — the fold's vertical padding was a constant
   96px at every window height, so the fill never adapted. Matched specificity. */
.bp-stack > .bp-pagesec.bp-foldcard{
  padding-top:clamp(56px,9vh,132px);
  padding-bottom:clamp(56px,9vh,132px);
  padding-left:var(--bp-gutter);padding-right:var(--bp-gutter)}
@media(max-width:820px){
  .bp-stack > .bp-pagesec.bp-foldcard{
    padding-top:clamp(40px,6vh,72px);padding-bottom:clamp(40px,6vh,72px)}
}

/* ==========================================================================
   82. THE PILL FLOATS, THE PAGE STARTS AT THE TOP
   The pill was already fixed, but the page reserved 78px above the fold card
   for it — so the card started below the pill instead of under it. The reserve
   is gone: the card begins at the top gutter and the pill floats over it.
   Markup follows suit — .bp-navwrap is a sibling of .bp-pagewrap, not a child,
   because it is not part of the page's flow at all.
   The fold's top padding (56px minimum) is what keeps the headline clear of the
   pill, which bottoms out at 49px.
   ========================================================================== */
.bp-pagewrap{padding-top:10px}
.bp-foldcard{
  min-height:calc(100vh - 44px);
  min-height:calc(100dvh - 44px)}
@media(max-width:820px){
  .bp-pagewrap{padding-top:8px}
  .bp-foldcard{min-height:calc(100dvh - 34px)}
}

/* ==========================================================================
   83. PILL: +2px BREATHING, TWO-LINE BURGER
   Padding 4 -> 6 top and bottom, so the pill goes 35 -> 39 without changing
   anything inside it. The burger drops its middle bar: two strokes read as a
   menu just as well and sit better against a shorter pill.
   With two 1.5px bars and a 5px gap the strokes centre at ±3.25px, which is
   what the close mark has to translate by so the X meets cleanly.
   ========================================================================== */
.bp-pill{padding:6px 6px 6px 18px}
.nav-hamburger{gap:5px}
.nav-hamburger span{width:13px;height:1.5px}
.nav-hamburger.open span:nth-child(1){transform:translateY(3.25px) rotate(45deg)}
.nav-hamburger.open span:nth-child(2){transform:translateY(-3.25px) rotate(-45deg);opacity:1}
/* strip 18px lower, card unchanged: the fold is centred, so simply adding top
   space would push the whole block up and net only ~9px of movement. The equal
   negative bottom margin keeps the content block the same height, so nothing
   re-centres and the card cannot grow. */
.bp-foldcard .bp-iconstrip{margin-top:18px;margin-bottom:-18px}

/* ==========================================================================
   84. THE ICONS, AT FULL CLARITY
   The hold-back (opacity .6 + saturate .72) plus a wide white edge-fade was
   washing them out. Full colour restored; the fade narrowed to the outer 4%
   so only the icon actually leaving the strip softens, and nothing in view
   is sitting under a white veil.
   ========================================================================== */
.bp-iconstrip img{opacity:1;filter:none}
.bp-iconstrip:hover img{opacity:1;filter:none}
.bp-iconstrip .bp-strip::after,
.bp-foldcard .bp-iconstrip .bp-strip::after{
  background:linear-gradient(90deg,var(--bp-white) 0%,rgba(255,255,255,0) 4%,
    rgba(255,255,255,0) 96%,var(--bp-white) 100%)}

/* ==========================================================================
   85. THE DIAGNOSIS IN BLACK, A WIDER SPOTLIGHT, MORE AIR ABOVE THE STRIP
   ========================================================================== */
/* the section reads in one colour — the numerals were the only orange left */
/* numerals: see block 87 — orange, low opacity, behind the copy */

/* the dot layers already span the card; it was the 200px spotlight that made
   the effect feel local. A wider, softer one follows the cursor across it. */
.bp-dots-hi{
  -webkit-mask-image:radial-gradient(460px circle at var(--bp-mx,50%) var(--bp-my,40%),#000 0%,rgba(0,0,0,.45) 42%,transparent 76%);
  mask-image:radial-gradient(460px circle at var(--bp-mx,50%) var(--bp-my,40%),#000 0%,rgba(0,0,0,.45) 42%,transparent 76%)}

/* more room above the strip, card height untouched: the equal negative bottom
   margin keeps the content block the same height so nothing re-centres. */
.bp-foldcard .bp-iconstrip{margin-top:52px;margin-bottom:-52px}

/* the dot layers were rendering as flex items in the fold card's column —
   position:relative, height 0, nothing to light. They must be out of flow. */
.bp-foldcard > .bp-dots,
.bp-foldcard > .bp-dots-hi{position:absolute;inset:0;height:auto;width:auto;
  z-index:0;pointer-events:none}
.bp-foldcard > .bp-hero,
.bp-foldcard > .bp-iconstrip{position:relative;z-index:2}

/* ==========================================================================
   86. ONE DOT FIELD, NOT TWO
   The fold card was carrying two independent dot systems:
     .bp-dots / .bp-dots-hi   the <i> layers   — 24px grid, 1.1px dots
     .bp-stack > *::before/after  pseudo-elements — 28px grid, 1px dots
   Two grids at 24 and 28px drift in and out of phase, which is the doubled,
   moiré pattern — not "some dots fixed on the background", but two fields
   printed over each other.
   The <i> layers stay: they cover the whole card and follow the cursor across
   it. The pseudo-element field is suppressed here and kept for the other stack
   cards, where it is the only field and its flank mask still earns its place.
   ========================================================================== */
.bp-foldcard::before,.bp-foldcard::after{display:none}

/* more overlay on the sides of the strip — 4% was too tight to read as a fade */
.bp-iconstrip .bp-strip::after,
.bp-foldcard .bp-iconstrip .bp-strip::after{
  background:linear-gradient(90deg,var(--bp-white) 0%,rgba(255,255,255,.55) 7%,
    rgba(255,255,255,0) 17%,rgba(255,255,255,0) 83%,
    rgba(255,255,255,.55) 93%,var(--bp-white) 100%)}

/* ==========================================================================
   87. BURGER LINES, AND THE NUMERALS AS PART OF THE CARD
   (a) The two bars were 1.5px tall in a 27px box with a 5px gap: total 8px,
       so the top bar started at 9.5px — a half-pixel — and rendered soft while
       the bottom one, at 16px, rendered crisp. Not a width difference, a
       sub-pixel one. 2px bars with a 5px gap total 9px, putting them at 9 and
       16: both whole pixels, both identical.
   (b) The numerals become part of the card rather than a label above the
       heading — large, orange, low enough in opacity that the copy reads over
       them cleanly.
   ========================================================================== */
.nav-hamburger span{width:14px;height:2px;border-radius:1px}
.nav-hamburger{gap:5px}
.nav-hamburger.open span:nth-child(1){transform:translateY(3.5px) rotate(45deg)}
.nav-hamburger.open span:nth-child(2){transform:translateY(-3.5px) rotate(-45deg);opacity:1}

.bp-cards4 > *{position:relative;overflow:hidden}
.bp-cards4 .bp-find__n{
  position:absolute;top:-6px;right:14px;margin:0;z-index:0;
  font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);
  font-size:5.5rem;line-height:1;letter-spacing:-.04em;
  color:var(--bp-orange);opacity:.17;pointer-events:none;user-select:none}
.bp-cards4 h3,.bp-cards4 p{position:relative;z-index:1}
.bp-cards4 h3{margin-top:0}
@media(max-width:820px){
  .bp-cards4 .bp-find__n{font-size:4.2rem;right:12px}
}

/* ==========================================================================
   88. THE DIAGNOSIS AS A HORIZONTAL ACCORDION
   One card open at a time, twice the width of the closed ones. Scrolling the
   section hands the open state along: 1 -> 2 -> 3 -> 4.
   Scroll-driven CSS, no listener. Each card runs the same keyframe on its own
   slice of the section's view timeline, so the handover is the scroll position
   itself and nothing can fall out of sync.
   Card 1 opens at rest: its base flex-grow is the open value, and its keyframe
   closes it rather than opening it.
   Fallback where view() is unsupported: four equal cards, all copy visible —
   the layout this section had before, which is complete on its own.
   ========================================================================== */
.bp-cards4{display:flex;gap:20px;align-items:stretch}
.bp-cards4 > *{flex:1 1 0;min-width:0;overflow:hidden}

/* ---- and the framework stops stacking ---------------------------------- */
.bp-deck__row{position:static}
.bp-deck{padding-bottom:0}

/* ---- and the framework stops stacking ---------------------------------- */
.bp-deck__row{position:static}
.bp-deck{padding-bottom:0}

/* the accordion state itself — scripts.js sets data-open on the row.
   Only the width and the body copy change; nothing reflows around it. */
@media (min-width:1080px){
  .bp-cards4[data-open] > *{
    transition:flex-grow .5s var(--bp-ease);
    flex-grow:1}
  .bp-cards4[data-open] > * > p:not(.bp-find__n){
    transition:opacity .32s var(--bp-ease);opacity:0}
  .bp-cards4[data-open="0"] > *:nth-child(1),
  .bp-cards4[data-open="1"] > *:nth-child(2),
  .bp-cards4[data-open="2"] > *:nth-child(3),
  .bp-cards4[data-open="3"] > *:nth-child(4){flex-grow:2.4}
  .bp-cards4[data-open="0"] > *:nth-child(1) > p:not(.bp-find__n),
  .bp-cards4[data-open="1"] > *:nth-child(2) > p:not(.bp-find__n),
  .bp-cards4[data-open="2"] > *:nth-child(3) > p:not(.bp-find__n),
  .bp-cards4[data-open="3"] > *:nth-child(4) > p:not(.bp-find__n){opacity:1}
  /* a closed card keeps its heading readable at the narrower width */
  .bp-cards4[data-open] > * h3{transition:font-size .5s var(--bp-ease)}
}
@media (prefers-reduced-motion: reduce){
  .bp-cards4[data-open] > *{flex-grow:1 !important}
  .bp-cards4[data-open] > * > p{opacity:1 !important}
}

/* ==========================================================================
   89. PRICING, SIMPLIFIED
   The cards carried a sub-line under the title and a bold lead above the rule
   on top of everything else — two extra voices before the buyer reached the
   list. The order is now the one that reads cleanest: name, price, terms, who
   it is for, the list, one closing line.
   Checkmarks rather than em-dashes: a dash reads as a spec sheet, a check reads
   as something you get.
   ========================================================================== */
.bp-plan h3{margin:0 0 18px}
.bp-plan__amt{margin:0}
.bp-plan__terms{margin:10px 0 0}
.bp-plan__who{margin:18px 0 0;font-style:normal;color:var(--bp-dim);font-size:.95rem;
  max-width:34ch}
.bp-plan__rule{margin:26px 0 0}
.bp-plan__list{margin:24px 0 0;gap:15px}
.bp-plan__list li{grid-template-columns:20px 1fr;gap:12px;color:var(--bp-ink)}
.bp-plan__list li::before{
  content:"";width:17px;height:17px;margin-top:2px;border-radius:50%;
  background:var(--bp-orange);
  -webkit-mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6L9 17l-5-5' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/></svg>") center/13px no-repeat;
  mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6L9 17l-5-5' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/></svg>") center/13px no-repeat}
.bp-plan__foot{margin:28px 0 0;color:var(--bp-dim);font-size:.875rem;
  padding-top:20px;border-top:1px solid var(--bp-hair)}

/* ==========================================================================
   90. THE DIAGNOSIS ACCORDION — CLICK, NOT SCROLL
   One card open, three collapsed to a rail wide enough to show their numeral.
   Clicking a rail opens it and closes whatever was open. Card 1 is open on
   arrival.
   Every card is the same height and the row never reflows: the height is set
   once on the row, so opening a card changes width only. That was the whole
   complaint — cards resizing vertically as the copy rewrapped.
   Below 1080px it falls back to four stacked cards, all readable.
   ========================================================================== */
.bp-cards4{display:flex;gap:20px;align-items:stretch}
.bp-cards4 > *{position:relative;overflow:hidden}

@media (min-width:1080px){
  .bp-cards4{min-height:330px}
  .bp-cards4 > *{
    flex:0 0 118px;min-width:0;cursor:pointer;
    transition:flex-basis .52s var(--bp-ease),flex-grow .52s var(--bp-ease);
    display:flex;flex-direction:column;justify-content:flex-start}
  .bp-cards4 > *.is-open{flex:1 1 auto;cursor:default}

  /* the copy only exists in the open card; the rails carry the numeral alone */
  .bp-cards4 > * h3,
  .bp-cards4 > * > p:not(.bp-find__n){
    opacity:0;transform:translateY(6px);
    transition:opacity .3s var(--bp-ease),transform .38s var(--bp-ease);
    white-space:normal}
  .bp-cards4 > *.is-open h3,
  .bp-cards4 > *.is-open > p:not(.bp-find__n){opacity:1;transform:none;
    transition-delay:.16s}
  /* a rail's text must not force it wider than the rail */
  .bp-cards4 > *:not(.is-open) h3,
  .bp-cards4 > *:not(.is-open) > p:not(.bp-find__n){
    position:absolute;left:36px;right:36px;pointer-events:none}

  /* the numeral: subtle, and the only thing a rail shows */
  .bp-cards4 .bp-find__n{
    position:absolute;top:14px;left:0;right:0;text-align:center;
    font-size:4.2rem;opacity:.16;
    transition:font-size .52s var(--bp-ease),opacity .3s var(--bp-ease),
      top .52s var(--bp-ease),left .52s var(--bp-ease),right .52s var(--bp-ease),
      text-align .52s}
  .bp-cards4 > *.is-open .bp-find__n{
    top:-6px;left:auto;right:22px;text-align:right;font-size:5.5rem;opacity:.17}

  .bp-cards4 > *:not(.is-open):hover{background:#fff}
  .bp-cards4 > *:not(.is-open):hover .bp-find__n{opacity:.3}
  .bp-cards4 > *:focus-visible{outline:2px solid var(--bp-orange);outline-offset:3px}
}
@media (prefers-reduced-motion: reduce){
  .bp-cards4 > *,.bp-cards4 > * h3,.bp-cards4 > * p,.bp-cards4 .bp-find__n{transition:none}
}

/* ==========================================================================
   91. PRICING CARDS: TEXTURE, A NAMED WARRANTY, A LIVE CTA
   (a) The same 24px dot field as the fold card — one grid size across the whole
       system, so two fields can never beat against each other.
   (b) The free-next-experiment line was a footnote. It is the strongest
       sentence in the section and the only outcome promise on the page, so it
       gets a panel and a name: a warranty, not a refund.
   (c) The flag moves right, where the space is; "for apps that…" moves below
       the CTA, where a qualifier belongs — it is the last thing you check, not
       the first.
   (d) Start the loop takes the hero CTA's glow and sweep: the page's two real
       decisions should look the same.
   ========================================================================== */
.bp-plan{position:relative;overflow:hidden;isolation:isolate}
.bp-plan::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:radial-gradient(circle,var(--bp-ink) 1.1px,transparent 1.1px);
  background-size:24px 24px;opacity:.05}

.bp-plan__flag{left:auto;right:32px}

.bp-promise{margin:26px 0 0;padding:18px 20px;border-radius:var(--bp-r-sm);
  background:var(--bp-paper);color:var(--bp-dim);
  font-size:.9rem;line-height:1.55}
.bp-promise--warranty{background:rgba(255,77,0,.07);color:var(--bp-ink);font-weight:500}
.bp-promise__label{display:block;font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);
  font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--bp-orange);margin-bottom:7px}

.bp-plan__cta{margin-top:22px}
.bp-plan__who{margin:16px 0 0;text-align:center;font-size:.82rem;
  color:var(--bp-faint);max-width:none}

/* the Loop's CTA is the same object as the hero's */
.bp-plan--hi .bp-plan__cta{
  background:var(--bp-orange);color:#fff;box-shadow:var(--bp-glow);
  background-image:linear-gradient(100deg,var(--bp-orange) 30%,rgba(255,140,60,.92) 50%,var(--bp-orange) 70%);
  background-size:250% 100%;animation:bp-sweep 2.8s linear infinite}
.bp-plan--hi .bp-plan__cta:hover{filter:brightness(1.05)}
@media (prefers-reduced-motion: reduce){
  .bp-plan--hi .bp-plan__cta{animation:none;background-image:none}
}

/* ==========================================================================
   92. PRICING, CLEANED UP
   The moves that make a pricing card read fast, in our own palette:
     · the tier badge sits INLINE with the name, not floating over the card
     · one bold sentence under the price instead of a paragraph and a qualifier
     · no rules — spacing separates, which is the house rule everywhere else
     · filled circular ticks, tight list, and the CTA pinned to the bottom so
       both cards end on the same line however long the list is
     · the secondary card takes the paper ground; only the primary is white and
       lifted. Two fills, not two identical cards with a flag on one.
   ========================================================================== */
.bp-plans{align-items:stretch}
.bp-plan{padding:44px 40px 40px;display:flex;flex-direction:column}
.bp-plan:not(.bp-plan--hi){background:var(--bp-paper);box-shadow:var(--bp-lift-1)}
.bp-plan--hi{background:var(--bp-white);box-shadow:var(--bp-lift-3)}
.bp-plan:not(.bp-plan--hi)::before{opacity:.045}

/* name + inline badge */
.bp-plan h3{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 22px}
.bp-plan__badge{font-family:var(--bp-body);font-weight:600;font-size:.7rem;
  letter-spacing:.04em;padding:6px 12px;border-radius:var(--bp-r-pill);
  background:var(--bp-ink);color:#fff;white-space:nowrap}
.bp-plan--hi .bp-plan__badge{background:var(--bp-orange)}

/* price */
.bp-plan__amt{font-size:3.1rem;margin:0}
.bp-plan__amt span{font-family:var(--bp-body);font-weight:600;font-size:.95rem;
  color:var(--bp-dim);margin-left:8px;letter-spacing:0}

/* the one line that says what this tier is for */
.bp-plan__statement{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);letter-spacing:-.018em;
  font-size:1.16rem;line-height:1.3;color:var(--bp-ink);
  margin:26px 0 0;max-width:22ch}

/* list */
.bp-plan__list{margin:30px 0 0;gap:16px}
.bp-plan__list li{grid-template-columns:22px 1fr;gap:14px;font-size:.95rem;
  color:var(--bp-ink);align-items:start}
.bp-plan__list li::before{
  content:"";width:20px;height:20px;margin-top:0;border-radius:50%;
  background:var(--bp-ink);
  -webkit-mask:none;mask:none;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M19 7.5L10 17l-5-5' fill='none' stroke='white' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-size:14px;background-position:center;background-repeat:no-repeat}
.bp-plan--hi .bp-plan__list li::before{background-color:var(--bp-orange)}

/* the promise sits just above the CTA, and the CTA is pinned to the bottom */
.bp-promise{margin:30px 0 0}
.bp-plan__cta{margin-top:auto;margin-bottom:0}
.bp-promise + .bp-plan__cta{margin-top:22px}
.bp-plan__list{flex:1 0 auto}

@media(max-width:820px){
  .bp-plan{padding:32px 26px 28px}
  .bp-plan__amt{font-size:2.5rem}
}
/* The tick was an inline SVG data URI and computed to a transparent background —
   unescaped angle brackets in a utf8 data URI are not reliably parsed. Drawn
   instead: ::before is the disc, ::after is two borders rotated 45°. No asset,
   no encoding to get wrong, and it takes the accent from the token. */
.bp-plan__list li{position:relative;padding-left:0}
.bp-plan__list li::before{
  content:"";width:20px;height:20px;border-radius:50%;flex:none;
  background-color:var(--bp-ink);background-image:none;
  -webkit-mask:none;mask:none}
.bp-plan--hi .bp-plan__list li::before{background-color:var(--bp-orange)}
.bp-plan__list li::after{
  content:"";position:absolute;left:6.5px;top:6px;width:4.5px;height:8.5px;
  border:solid #fff;border-width:0 2px 2px 0;transform:rotate(43deg);
  pointer-events:none}

/* ==========================================================================
   93. PRICING ICONOGRAPHY, AND THE FOOTER AS THE LAST CARD
   (a) The ticks were a 20px filled disc with a drawn stroke — heavy next to
       15px type, and the stroke sat low in the circle. Smaller disc, tick
       centred properly, and the disc takes the card's own accent.
   (b) The warranty gets a shield: it is a guarantee, and a shield says that
       faster than a label alone.
   (c) A Stripe line under the pair. The Single Experiment is a direct card
       payment, so saying who handles it is worth more here than on a page
       where everything is call-gated.
   (d) The footer stops being a 560px gradient wash and becomes what every
       other section is: a card. Rounded on top only, flush to the bottom of
       the page — the last card, where the stack lands.
   ========================================================================== */
.bp-plan__list li{grid-template-columns:19px 1fr;gap:13px}
.bp-plan__list li::before{width:19px;height:19px;margin-top:1px}
.bp-plan__list li::after{left:6.4px;top:6.1px;width:4px;height:7.6px;
  border-width:0 1.9px 1.9px 0;transform:rotate(44deg)}

.bp-promise--warranty{display:grid;grid-template-columns:auto 1fr;
  gap:6px 14px;align-items:start;padding:20px 22px}
.bp-promise__icon{grid-row:1/3;width:26px;height:26px;color:var(--bp-orange);
  margin-top:1px}
.bp-promise--warranty .bp-promise__label{margin-bottom:4px}

.bp-paynote{display:flex;align-items:center;justify-content:center;gap:9px;
  margin:30px 0 0;font-size:.8rem;color:var(--bp-faint);text-align:center}
.bp-paynote svg{width:15px;height:15px;flex:none}

/* ---- the footer, as the last card -------------------------------------- */
.bp-foot{margin-top:0;position:relative;
  width:calc(100% - 20px);max-width:var(--bp-frame);
  margin-left:auto;margin-right:auto;
  border-radius:var(--bp-r-panel) var(--bp-r-panel) 0 0;
  overflow:hidden}
.bp-foot::before{display:none}          /* the 560px gradient wash is gone */
.bp-foot__inner{padding:0 clamp(24px,5vw,72px)}
@media(max-width:820px){
  .bp-foot{width:calc(100% - 16px);border-radius:var(--bp-r-card) var(--bp-r-card) 0 0}
  .bp-foot__inner{padding:0 24px}
}
/* the ground rules ran 540px past the page to reach into the old gradient
   footer. With the footer a card, that overhang was the only thing extending
   the document below it — 36px of grey under a card meant to be flush. */
.bp-ground-rules{bottom:0}

/* ==========================================================================
   94. THE DIAGNOSIS AS A BENTO
   Four cards, four shapes: one tall, one wide, two square. The illustrations
   carry the weight the copy could not — there was never enough text here to
   justify four equal columns, which is why every version of that row felt thin.
   Line art only: 1.6px strokes in currentColor, no fills, no colour of their
   own. They inherit the page's ink, so they can never drift from the palette.
   compose: <div class="bp-bento"><div class="bp-bentocard"> …
   ========================================================================== */
.bp-bento{display:grid;gap:20px;margin-top:44px;
  grid-template-columns:repeat(3,minmax(0,1fr))}
.bp-bento > :nth-child(1){grid-row:1 / span 2}       /* the tall one */
.bp-bento > :nth-child(2){grid-column:2 / span 2}    /* the wide one */

.bp-bentocard{position:relative;overflow:hidden;
  background:var(--bp-white);border-radius:var(--bp-r-card);
  box-shadow:var(--bp-lift-2);padding:34px 32px 32px;
  display:flex;flex-direction:column}
.bp-bentocard::before{content:"";position:absolute;inset:0;z-index:0;
  pointer-events:none;
  background-image:radial-gradient(circle,var(--bp-ink) 1.1px,transparent 1.1px);
  background-size:24px 24px;opacity:.05}
.bp-bentocard > *{position:relative;z-index:1}

.bp-bentocard__n{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);
  position:absolute;top:22px;right:26px;margin:0;z-index:1;
  font-size:1.5rem;line-height:1;color:var(--bp-orange);opacity:.28}
.bp-bentocard h3{font-size:1.32rem;line-height:1.18;letter-spacing:-.02em;margin:0 0 10px}
.bp-bentocard p{font-size:1rem;line-height:1.6;color:var(--bp-dim);max-width:40ch;margin:0}

/* the art sits above the copy and takes the space the card has spare */
.bp-bentocard__art{flex:1;display:flex;align-items:center;justify-content:center;
  padding:8px 0 26px;min-height:0}
.bp-art{width:100%;height:100%;max-height:250px;color:var(--bp-ink);opacity:.82;
  overflow:visible}
.bp-bento > :nth-child(1) .bp-art{max-height:330px}
.bp-art--wide{max-height:170px}

/* motion: the paywall slot drifts between positions, and the ones who left
   keep leaving. Slow enough to be atmosphere, not a demo. */
@media (prefers-reduced-motion: no-preference){
  .bp-art__slot{animation:bp-slot 7s var(--bp-ease) infinite;
    animation-delay:calc(var(--i) * -1.6s)}
  @keyframes bp-slot{0%,100%{transform:translateY(0)}50%{transform:translateY(-9px)}}
  .bp-art__leave{animation:bp-leave 5.5s var(--bp-ease) infinite;
    animation-delay:calc(var(--i) * .55s)}
  @keyframes bp-leave{
    0%{transform:translate(0,0);opacity:1}
    70%{transform:translate(16px,-14px);opacity:0}
    100%{transform:translate(16px,-14px);opacity:0}}
}

@media(max-width:1080px){
  .bp-bento{grid-template-columns:repeat(2,minmax(0,1fr))}
  .bp-bento > :nth-child(1){grid-row:auto}
  .bp-bento > :nth-child(2){grid-column:1 / span 2}
  .bp-bento > :nth-child(1) .bp-art{max-height:220px}
}
@media(max-width:640px){
  .bp-bento{grid-template-columns:1fr}
  .bp-bento > :nth-child(2){grid-column:auto}
  .bp-bentocard{padding:28px 24px}
}

/* ==========================================================================
   95. BENTO POLISH
   Shorter right column, so the tall card (which spans both rows) stops
   forcing a long scroll. Numerals bigger, orange, and allowed to run off the
   card edge — the card's overflow:hidden crops them, which is the point.
   Every animation starts from a state that reads correctly if it never runs.
   ========================================================================== */
.bp-bentocard{padding:30px 30px 30px;
  transition:box-shadow .35s var(--bp-ease),transform .35s var(--bp-ease)}
.bp-bentocard:hover{box-shadow:var(--bp-lift-3);transform:translateY(-3px)}

/* the numeral: large, orange, cropped by the card edge */
.bp-bentocard__n{top:-16px;right:14px;font-size:5.2rem;opacity:.19;
  letter-spacing:-.045em}

/* shorter art keeps the whole grid shorter */
.bp-bentocard__art{padding:6px 0 22px}
.bp-art{max-height:200px}
.bp-art--wide{max-height:152px}
.bp-bento > :nth-child(1) .bp-art{max-height:none;height:100%}

@media (prefers-reduced-motion: no-preference){
  /* 1 — the skipped screens crush and vanish, then come back */
  .bp-art__crush{transform-box:fill-box;transform-origin:center;
    animation:bp-crush 7.5s var(--bp-ease) infinite;
    animation-delay:calc(var(--i) * .5s)}
  @keyframes bp-crush{
    0%,14%{opacity:.9;transform:scaleY(1)}
    34%,64%{opacity:.06;transform:scaleY(.12)}
    84%,100%{opacity:.9;transform:scaleY(1)}}

  /* 2 — the four places trade positions, slowly */
  .bp-art__slot{animation:bp-swap 9s var(--bp-ease) infinite;
    animation-delay:calc(var(--i) * -2.2s)}
  @keyframes bp-swap{
    0%,100%{transform:translate(0,0)}
    25%{transform:translate(0,-10px)}
    50%{transform:translate(0,0)}
    75%{transform:translate(0,8px)}}

  /* 3 — the routes draw themselves, then the verdicts land */
  .bp-art__path{stroke-dasharray:150;stroke-dashoffset:150;
    animation:bp-draw 8s var(--bp-ease) infinite;
    animation-delay:calc(var(--i) * .45s)}
  @keyframes bp-draw{0%{stroke-dashoffset:150}22%,86%{stroke-dashoffset:0}100%{stroke-dashoffset:150}}
  .bp-art__mark{opacity:0;transform-box:fill-box;transform-origin:center;
    animation:bp-land 8s var(--bp-ease) infinite;
    animation-delay:calc(var(--i) * .45s + .5s)}
  @keyframes bp-land{0%,14%{opacity:0;transform:scale(.6)}
    28%,84%{opacity:1;transform:scale(1)}100%{opacity:0;transform:scale(.6)}}

  /* 4 — the ones who got past the wall keep going */
  .bp-art__leave{animation:bp-leave 5.5s var(--bp-ease) infinite;
    animation-delay:calc(var(--i) * .6s)}
  @keyframes bp-leave{
    0%{transform:translate(0,0);opacity:1}
    72%,100%{transform:translate(18px,-15px);opacity:0}}
}
@media (prefers-reduced-motion: reduce){
  .bp-art__path{stroke-dasharray:none;stroke-dashoffset:0}
  .bp-art__mark,.bp-art__crush,.bp-art__slot,.bp-art__leave{opacity:1;transform:none}
}
/* .bp-bentocard p (0,1,1) was beating .bp-bentocard__n (0,1,0), so the numeral
   rendered as body copy — 16px and grey. And letting the tall card's art size
   to its own aspect ratio made it 900px, which stretched every row with it:
   card 1 spans both, so its height sets the grid. Both capped. */
.bp-bentocard p.bp-bentocard__n{
  font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);
  font-size:5.2rem;line-height:1;letter-spacing:-.045em;
  color:var(--bp-orange);opacity:.19;max-width:none}
.bp-bento > :nth-child(1) .bp-art{max-height:390px;height:auto}

/* ---- 96. bare close CTA + founder cursor tag ----------------------------- */
/* The close CTA sat on ink directly above the ink footer card, so the two read
   as one slab — and it already carries a white card inside it. --bare drops the
   ground and lets the section sit on the page, which also puts real air between
   the CTA and the footer. Beats .bp-stack>.bp-close (0,2,0) on order. */
.bp-stack>.bp-close--bare{background:transparent;
  padding-top:var(--bp-v);padding-bottom:var(--bp-v);
  padding-left:clamp(24px,6vw,96px);padding-right:clamp(24px,6vw,96px);
  /* The card chrome stays — only the fill is dropped. .bp-stack>* hands out
     background, radius, shadow and the dotted ::before as one bundle; here we
     want three of the four, so the frame reads without a slab of colour.
     What was wrong was never the chrome, it was that the stack ends where the
     footer begins, so this card's edge landed flush on the footer's edge.
     Two card edges need ground between them. That gap is now owned by the
     last-block rule in block 99, not by this variant. */
  }
.bp-close--bare{color:var(--bp-ink)}
.bp-close--bare h2{color:var(--bp-ink)}
.bp-close--bare p{color:var(--bp-dim)}

/* Figma-multiplayer cursor: the arrow leads, the label trails from its tip.
   Page-local modifier — .bp-bookcard__tag is shared by five pages. */
.bp-bookcard__tag--cursor{top:-30px;right:-26px;padding:6px 12px;
  border-radius:3px 13px 13px 13px;overflow:visible;
  animation:bp-cursorfloat 6s ease-in-out infinite}
.bp-bookcard__tag--cursor svg{position:absolute;top:-13px;left:-10px;
  width:15px;height:17px;fill:var(--bp-ink);
  stroke:var(--bp-white);stroke-width:1.4;stroke-linejoin:round;overflow:visible}
@keyframes bp-cursorfloat{
  0%,100%{transform:translate(0,0)}
  50%{transform:translate(-5px,-4px)}}
@media(prefers-reduced-motion:reduce){
  .bp-bookcard__tag--cursor{animation:none}}
@media(max-width:820px){
  .bp-stack>.bp-close--bare{padding-left:24px;padding-right:24px}}

/* ==========================================================================
   97. FRAMEWORK HOVER + PRICING CARD FIXES
   (a) The deck cards were the only inert cards left on the page — the bento
       and the plans both lift. Same gesture, so the page reads as one system.
   (b) The tick discs sat 2px high: a 19px disc against a 25.08px line box
       needs 3.04px above it, not 1px. --tick-y keeps the disc and the drawn
       tick locked to one number so they can't drift apart again.
   (c) The loop promise mirrors the warranty card's shape but in grey — the
       orange is spoken for by the CTA directly beneath it.
   (d) The paynote sat 30px under a lift-3 card, inside the shadow's falloff.
   ========================================================================== */

/* (a) framework hover */
.bp-deckcard{transition:box-shadow .22s ease,transform .22s ease}
.bp-deckcard:hover{transform:translateY(-4px);box-shadow:var(--bp-lift-3)}
.bp-deckcard__n{transition:opacity .22s ease,color .22s ease}
.bp-deckcard:hover .bp-deckcard__n{opacity:1}
.bp-deckcard--white:hover .bp-deckcard__n{color:var(--bp-orange)}
.bp-deckcard--ink:hover{box-shadow:0 18px 44px -12px rgba(0,0,0,.45)}
.bp-deckcard--orange:hover{box-shadow:0 18px 44px -12px rgba(255,77,0,.42)}
@media(prefers-reduced-motion:reduce){
  .bp-deckcard:hover{transform:none}}

/* (b) tick discs centred on their first line */
.bp-plan__list li{--tick-y:3px}
.bp-plan__list li::before{margin-top:var(--tick-y)}
.bp-plan__list li::after{top:calc(var(--tick-y) + 5.1px)}

/* (c) the loop promise as a card */
.bp-promise--loop{display:grid;grid-template-columns:auto 1fr;
  gap:6px 14px;align-items:start;padding:20px 22px;
  background:rgba(10,10,10,.045);color:var(--bp-ink);font-weight:500}
.bp-promise--loop .bp-promise__icon{grid-row:1/3;width:32px;height:32px;
  color:var(--bp-ink);opacity:.72;margin-top:1px}
.bp-promise--loop .bp-promise__label{margin-bottom:4px;color:var(--bp-dim)}

/* the warranty needs to be seen, so the shield goes up a size */
.bp-promise__icon{width:32px;height:32px}
.bp-promise--warranty .bp-promise__icon{opacity:.9}
.bp-promise--warranty,.bp-promise--loop{grid-template-columns:32px 1fr;gap:6px 15px}

/* (d) the paynote, clear of the highlighted card's shadow */
.bp-paynote{margin-top:48px;gap:8px;flex-wrap:wrap}
.bp-paynote svg.bp-paynote__stripe{width:17px;height:17px;border-radius:3.4px;flex:none}

/* ==========================================================================
   98. THE PROMISE MARKS BECOME MARKS, NOT ICONS
   At 32px the shield read as a bullet: something to skip past. Blown up to
   104px, ghosted, and clipped by the promise box's own rounded edge, it reads
   as a stamp on the card — the same move as the bento numerals cropping at the
   card edge. The words still carry the meaning; the mark carries the weight.
   ========================================================================== */
.bp-promise--warranty,.bp-promise--loop{
  display:block;position:relative;overflow:hidden;isolation:isolate;
  padding:20px 100px 20px 22px}
.bp-promise--warranty .bp-promise__icon,
.bp-promise--loop .bp-promise__icon{
  position:absolute;right:-18px;bottom:-24px;
  width:104px;height:104px;margin:0;z-index:-1;pointer-events:none}
.bp-promise--warranty .bp-promise__icon{color:var(--bp-orange);opacity:.22}
.bp-promise--loop .bp-promise__icon{color:var(--bp-ink);opacity:.16}
.bp-promise--warranty .bp-promise__label,
.bp-promise--loop .bp-promise__label{display:block;margin-bottom:4px}
@media(max-width:820px){
  .bp-promise--warranty,.bp-promise--loop{padding-right:76px}
  .bp-promise--warranty .bp-promise__icon,
  .bp-promise--loop .bp-promise__icon{width:84px;height:84px;right:-14px;bottom:-18px}}

/* ==========================================================================
   99. THE RHYTHM, APPLIED TO EVERY PAGE
   (a) .bp-stack > .bp-pagesec set `padding:96px …` as a SHORTHAND at (0,2,0),
       which outranks .bp-stack>*'s longhand --bp-v-panel at (0,1,0) no matter
       what order they appear in. Every panel on every page was therefore 96px
       instead of 172px. The reference page never showed it, because its only
       panel is the fold card, which has its own (0,3,0) override.
   (b) Same shorthand, same bug, on .bp-stack > .bp-close: 96px.
   (c) The gap before the footer belongs to whatever ends the page, not to one
       CTA variant. A card that ends the page needs 160px of ground beneath it;
       an open section does not, because its own bottom padding already is that
       160px. So the margin goes on the last stack, not on every close.
   ========================================================================== */
.bp-stack>.bp-pagesec{padding-top:var(--bp-v-panel);padding-bottom:var(--bp-v-panel)}
.bp-stack>.bp-close{padding-top:var(--bp-v);padding-bottom:var(--bp-v)}
.bp-pagewrap > .bp-stack:last-child{margin-bottom:var(--bp-v)}

@media(max-width:820px){
  .bp-stack>.bp-pagesec{padding-top:var(--bp-v-panel);padding-bottom:var(--bp-v-panel)}
  .bp-stack>.bp-close{padding-top:var(--bp-v);padding-bottom:var(--bp-v)}}

/* ==========================================================================
   100. MOBILE SIZING RULES
   Measured at 390×844 before writing any of this. The page had no horizontal
   overflow, but six things did not adapt — they simply kept their desktop
   value on a 322px card:

   (a) The four bento illustrations were 390 / 93 / 200 / 200px tall. On desktop
       that is the bento's whole point: one tall card, one wide, two square. In
       a single column every card is the same width, so those four heights are
       just four inconsistent drawings. ONE height on mobile.
   (b) The bento numeral stayed at 83px on a 322px card.
   (c) .bp-deckcard h3 was 24px against a 30px h2 — a card title nearly the
       size of the section heading it sits under.
   (d) Card padding was 30 / 28 / 32 / 26 / 24 depending on the component.
       Five values for one job. One value: 24px, the same as the gutter.
   (e) The promise card spent 76px of a 270px card on the ghosted mark, leaving
       172px for the sentence. The mark shrinks and tucks further out.
   (f) The fold card carried 298px of slack, because a viewport floor written
       for a laptop makes a phone scroll past empty space. Content-driven here.
   ========================================================================== */
@media(max-width:820px){

  /* (a) one drawing size, all four cards */
  .bp-art,
  .bp-art--wide,
  .bp-bento > :nth-child(1) .bp-art{max-height:150px;height:auto}

  /* (b)(c) display sizes step down with the cards they sit on */
  .bp-bentocard p.bp-bentocard__n{font-size:3.5rem;top:-10px;right:12px}
  .bp-deckcard h3{font-size:1.25rem;line-height:1.18}
  .bp-bentocard h3{font-size:1.25rem;line-height:1.18}

  /* (d) one card padding */
  .bp-bentocard,.bp-deckcard,.bp-plan,
  .bp-faqstack details,.bp-bookcard{padding:24px}
  .bp-plan{padding-bottom:26px}

  /* (e) the promise mark gets out of the sentence's way */
  .bp-promise--warranty,.bp-promise--loop{padding:18px 62px 18px 18px}
  .bp-promise--warranty .bp-promise__icon,
  .bp-promise--loop .bp-promise__icon{width:74px;height:74px;right:-16px;bottom:-18px}

  /* (f) the fold is content-driven on a phone */
  .bp-foldcard{min-height:0}

  /* tap targets: 23px summaries and 17px footer links are below the 44px floor */
  .bp-faqstack details{padding-top:14px;padding-bottom:14px}
  .bp-faqstack summary{padding-top:11px;padding-bottom:11px}
  .bp-foot a{padding-top:11px;padding-bottom:11px;margin-bottom:0}
  .bp-pill__mark{padding-top:11px;padding-bottom:11px;margin-top:-11px;margin-bottom:-11px}
}

/* ---- 100b. three follow-ups the first mobile pass exposed ---------------- */
@media(max-width:820px){
  /* A max-height only caps the tall drawings; the wide one still computed 97px
     from its own 430×152 viewBox, so the boxes were 150/97/150/150. Setting a
     real height makes all four boxes identical and lets each drawing scale to
     fit inside it (preserveAspectRatio defaults to meet). */
  .bp-art,
  .bp-art--wide,
  .bp-bento > :nth-child(1) .bp-art{height:130px;max-height:130px}

  /* The strip is pulled 52px down by a negative bottom margin. With the fold's
     viewport floor removed there is no slack left to absorb it, so it overran
     the card's bottom padding by 1px. */
  .bp-foldcard .bp-iconstrip{margin-top:30px;margin-bottom:0}

  /* The nav pill is deliberately compact — 39px tall. Rather than break it to
     reach the 44px tap floor, the hit area is extended past the paint. */
  .bp-pill__cta,.nav-hamburger{position:relative}
  .bp-pill__cta::after,.nav-hamburger::after{
    content:"";position:absolute;inset:-9px;border-radius:inherit}
}

/* The FAQ column is width-capped rather than padded, so it landed on a 20px
   inset while every other section sits on 24. Same inset as the rest. */
@media(max-width:820px){
  .bp-faqsec{width:min(100% - 48px, 100%)}
}

/* ---- 100c. the fold must clear the fixed nav -----------------------------
   The nav pill is fixed at top:16px and is 39px tall, so it owns the first
   55px of the viewport. The fold card starts at the 8px pagewrap inset, which
   left its 51px top padding only 4px of clearance — the hero title ran under
   the pill. Nothing revealed it while the card had a viewport floor, because
   the content was centred in all that slack. Now that the card is
   content-driven on mobile, the padding has to do the job the slack was doing.
   Measured: the pill runs 36 -> 75 from the viewport top. The card starts at
   the 8px pagewrap inset, so its top padding must be at least 75 + 16 - 8 = 83
   for the title to clear. 96, which is a number the system already uses.
   Written at (0,3,0) because .bp-stack > .bp-pagesec.bp-foldcard sets this
   property and a bare .bp-foldcard (0,1,0) loses to it. */
@media(max-width:820px){
  .bp-stack > .bp-pagesec.bp-foldcard{padding-top:96px}
}

/* ---- 100d. the fold clears the nav at desktop too ------------------------
   The nav wrapper is fixed at top:16px and 59px tall, with the 39px pill
   centred in it — so the nav owns the viewport down to y=75, not y=55.
   The fold card starts at the 10px pagewrap inset with 81px of top padding,
   which puts its first line at 91: sixteen pixels below the pill.
   Nothing showed it on the reference page, where the hero is centred in a lot
   of slack and sits far below the padding edge. index has stats, two CTAs and
   a strip, so its content fills the card and lands on that padding edge.
   Top and bottom are deliberately asymmetric here: only the top has a fixed
   element to clear. 10 + 96 - 75 = 31px of clearance. */
.bp-stack > .bp-pagesec.bp-foldcard{padding-top:96px}

/* ==========================================================================
   101. BENTO ART, DECK ORDER AND THE STACKED PRICING CARDS
   ========================================================================== */

/* (1) Card 1's drawing is a vertical stack, which is right while it is the tall
   tile. Stacked, the card is wide and short, so the same drawing scales to a
   44px-wide sliver — which is why the orange $ at the end of it had effectively
   disappeared. A horizontal twin on the same 70x100 / 104-pitch geometry as
   card 2, so every drawing in the bento is literally the same size. */
.bp-art--h{display:none}
@media(max-width:820px){
  .bp-art--v{display:none}
  .bp-art--h{display:block}
}

/* (2) The slots were floating up and down, which says "waiting", not "testing".
   They now trade places: "3" moves to position 1 and the $ to position 3, with
   a hold at each end so both arrangements are readable. Pitch is 104. */
@media(prefers-reduced-motion:no-preference){
  .bp-art__slot{animation:bp-swap 9s var(--bp-ease) infinite;animation-delay:0s}
  .bp-art__slot[style*="--i:0"]{--dx:104px}
  .bp-art__slot[style*="--i:1"]{--dx:208px}
  .bp-art__slot[style*="--i:2"]{--dx:-208px}
  .bp-art__slot[style*="--i:3"]{--dx:-104px}
  @keyframes bp-swap{
    0%,16%{transform:translateX(0)}
    36%,64%{transform:translateX(var(--dx))}
    84%,100%{transform:translateX(0)}}

  /* (3) card 4: one route stopped at the wall, one going around its base */
  .bp-art__stop{opacity:0;animation:bp-stop 7s var(--bp-ease) infinite}
  @keyframes bp-stop{0%,20%{opacity:0;r:2}
    28%{opacity:1;r:5}34%,80%{opacity:1;r:3.6}100%{opacity:0;r:2}}
  .bp-art__detour{stroke-dasharray:210;stroke-dashoffset:210;
    animation:bp-detour 7s var(--bp-ease) infinite}
  @keyframes bp-detour{0%,32%{stroke-dashoffset:210}
    62%,88%{stroke-dashoffset:0}100%{stroke-dashoffset:210}}
  .bp-art__won{opacity:0;transform-box:fill-box;transform-origin:center;
    animation:bp-won 7s var(--bp-ease) infinite}
  @keyframes bp-won{0%,60%{opacity:0;transform:scale(.6)}
    70%,90%{opacity:1;transform:scale(1)}100%{opacity:0;transform:scale(.6)}}
}
@media(prefers-reduced-motion:reduce){
  .bp-art__stop,.bp-art__won{opacity:1}
  .bp-art__detour{stroke-dasharray:none;stroke-dashoffset:0}
}

/* (5) Stacked, the deck ran ink · white · white · orange — two whites together
   in the middle. Swapping the last row's two cards gives ink · white · orange
   · white, so no two neighbours share a ground. Desktop keeps the 2x2 reading,
   where the diagonal is what matters. */
@media(max-width:820px){
  .bp-deck__row:last-child > .bp-deckcard--white{background:var(--bp-orange);color:#fff}
  .bp-deck__row:last-child > .bp-deckcard--white p{color:rgba(255,255,255,.88)}
  .bp-deck__row:last-child > .bp-deckcard--white b{color:#fff}
  .bp-deck__row:last-child > .bp-deckcard--white:hover{
    box-shadow:0 18px 44px -12px rgba(255,77,0,.42)}
  .bp-deck__row:last-child > .bp-deckcard--white:hover .bp-deckcard__n{color:#fff}
  .bp-deck__row:last-child > .bp-deckcard--orange{background:var(--bp-white);color:var(--bp-ink)}
  .bp-deck__row:last-child > .bp-deckcard--orange p{color:var(--bp-dim)}
  .bp-deck__row:last-child > .bp-deckcard--orange b{color:var(--bp-ink)}
  .bp-deck__row:last-child > .bp-deckcard--orange:hover{box-shadow:var(--bp-lift-3)}
  .bp-deck__row:last-child > .bp-deckcard--orange:hover .bp-deckcard__n{color:var(--bp-orange)}
}

/* (6) Two problems, one cause. The quiet plan is --bp-paper (#F1F1F0) and the
   page ground is ALSO --bp-paper, so its card edge only reads while it sits
   beside a white one. Stacked, it dissolves and the price looks like loose text
   on the page. It gets a real ground and a real shadow on mobile.
   And the Loop leads on mobile: the recommended plan should be the first thing
   read, not the thing found after scrolling past the other one. */
@media(max-width:820px){
  .bp-plan:not(.bp-plan--hi){background:var(--bp-white);box-shadow:var(--bp-lift-2)}
  .bp-plan--hi{order:-1}
}

/* ==========================================================================
   102. THE MESSAGE FORM — .bp-form ON A LIGHT GROUND
   .bp-form was written to sit inside .bp-close, so every colour in it assumes
   an ink ground: white labels, translucent-white inputs, white-on-dark hints.
   The contact page now has two actions, and the second one is deliberately the
   quieter of the two — a white panel, not a second ink slab competing with the
   audit. Same component, inverted ink. Also adds the textarea, which the
   original form never needed.
   ========================================================================== */
.bp-msg{display:grid;grid-template-columns:1fr 1fr;gap:56px;align-items:start}
.bp-msg__head h2{margin:0 0 18px}
.bp-msg__head p{margin:0;max-width:38ch}
@media(max-width:820px){.bp-msg{grid-template-columns:1fr;gap:32px}}

.bp-form--light .bp-form__f>label{color:var(--bp-ink)}
.bp-form--light input[type="text"],
.bp-form--light input[type="email"],
.bp-form--light input[type="url"],
.bp-form--light textarea{
  width:100%;box-sizing:border-box;background:var(--bp-paper);color:var(--bp-ink);
  border:0;border-radius:var(--bp-r-sm);padding:14px 16px;
  font-family:var(--bp-body);font-size:15px;line-height:1.5}
.bp-form--light input::placeholder,
.bp-form--light textarea::placeholder{color:var(--bp-faint)}
.bp-form--light input:focus,
.bp-form--light textarea:focus{outline:none;box-shadow:0 0 0 2px var(--bp-orange)}
.bp-form--light textarea{resize:vertical;min-height:118px}
.bp-form--light .bp-form__hint{color:var(--bp-dim)}
.bp-form--light button:focus-visible{outline:2px solid var(--bp-ink);outline-offset:3px}

/* "required" reads better as a quiet tag than an asterisk nobody decodes */
.bp-form__req{font-family:var(--bp-body);font-weight:600;font-size:10px;
  letter-spacing:var(--bp-lbl-track);text-transform:uppercase;
  color:var(--bp-orange);margin-left:8px}

/* ==========================================================================
   103. CARD EDGE TO CARD EDGE, EVERYWHERE — NOT JUST BEFORE THE FOOTER
   The rule was already written down: two open sections sit 320 apart, and a
   card edge takes 160 because the edge does half the work. But it was only
   ever WIRED UP for the last block before the footer. Everywhere else, two
   panels landing next to each other had an edge gap of exactly 0 — they only
   looked separated because an open .bp-groundsec happened to sit between them.
   Remove that groundsec, as the contact page just did, and two cards butt
   together and read as one long card with a pinch in it.
   A card's own padding is inside it and separates nothing.
   ========================================================================== */
.bp-pagewrap > .bp-stack + .bp-stack{margin-top:var(--bp-v)}

/* ---- 102b. the message block earns its column ---------------------------
   The left column held a heading and one paragraph against a four-field form,
   so most of it was empty. The paragraph goes (the heading already says what
   the form is for) and the photo takes the space instead. And name + email
   share a row: two short fields stacked is two rows of mostly white space. */
.bp-msg__photo{display:block;width:100%;height:auto;margin-top:28px;
  aspect-ratio:4/5;object-fit:cover;object-position:50% 22%;
  border-radius:var(--bp-r-card);box-shadow:var(--bp-lift-2)}
.bp-form__row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
@media(max-width:820px){
  .bp-form__row{grid-template-columns:1fr;gap:18px}
  /* the source is already 4:5, so this crops nothing — a 3:2 band would slice
     a full-body portrait into a strip. 322px wide is 402 tall, which is content
     in a single column, not dead space. */
  .bp-msg__photo{margin-top:22px}
}

/* ---- 104. the audit books a call instead of submitting a form ------------
   The right-hand column of #roast was a four-field form. It is now a short
   lead-in and one button, so it needs to sit centred against the "what you
   get" list rather than filling the column top-down. */
.bp-book{display:flex;flex-direction:column;justify-content:center;
  align-items:flex-start;gap:20px;height:100%}
.bp-book__lead{color:rgba(255,255,255,.72);margin:0;max-width:34ch;font-size:1rem}
.bp-book__cta{align-self:stretch;text-align:center}
.bp-book__note{margin:0;font-size:12.5px;color:rgba(255,255,255,.5);align-self:center}
@media(max-width:820px){.bp-book{align-items:stretch}}

/* ==========================================================================
   105. TESTIMONIAL SLIDER — .bp-says
   Scroll-snap does the sliding; JS only drives the dots and the arrows, so it
   still works with JS off (it becomes a swipeable row). Each slide carries the
   icon of the app the quote came from — a person plus the thing they shipped
   is more evidence than a name alone. Where there is no app, a monogram.
   ========================================================================== */
.bp-says{position:relative}
/* A clipped viewport with a transformed track, not a scroll container.
   The scroll-snap version could not be driven reliably: something in the
   cascade left the track reporting a 322px client box while its scrollWidth
   was 816, so every computed step was wrong and scrollIntoView moved an
   ancestor instead. A transform depends on none of that — the pitch is
   measured once from the painted geometry and applied directly. */
.bp-says__view{overflow:hidden;padding:4px 2px 10px;margin:0 -2px}
.bp-says__track{display:flex;gap:20px;
  transition:transform .45s cubic-bezier(.22,.61,.36,1);will-change:transform}
.bp-says__slide{flex:0 0 100%;box-sizing:border-box;margin:0;/* <figure> ships
  with a 40px UA side margin. Unreset, it added 80px to every slide's footprint:
  the track's scrollWidth read 816 against a 322 client box, the measured pitch
  came out 414 instead of 338, and two "50%" slides overflowed their viewport.
  Every symptom chased in this component traced back to this one line. */
  background:var(--bp-white);border-radius:var(--bp-r-card);
  box-shadow:var(--bp-lift-2);padding:38px 40px;
  display:flex;flex-direction:column;gap:22px}
@media(min-width:900px){.bp-says__slide{flex-basis:calc(50% - 10px)}}
.bp-says__q{margin:0;font-size:1.0625rem;line-height:1.62;color:var(--bp-ink)}
.bp-says__q b{font-weight:600;color:var(--bp-ink);
  box-shadow:inset 0 -.55em 0 rgba(255,77,0,.16)}
.bp-says__by{display:flex;align-items:center;gap:14px;margin-top:auto}
.bp-says__ico{width:44px;height:44px;border-radius:12px;flex:none;object-fit:cover;
  box-shadow:var(--bp-lift-1)}
.bp-says__mono{width:44px;height:44px;border-radius:12px;flex:none;display:grid;
  place-items:center;background:var(--bp-ink);color:#fff;
  font-family:var(--bp-body);font-weight:600;font-size:13px;letter-spacing:.02em}
.bp-says__who{display:block;font-weight:600;font-size:.95rem;color:var(--bp-ink)}
.bp-says__role{display:block;font-size:.8125rem;color:var(--bp-dim);margin-top:2px}

.bp-says__nav{display:flex;align-items:center;gap:10px;margin-top:22px}
.bp-says__dots{display:flex;gap:7px;margin-right:auto}
.bp-says__dot{width:7px;height:7px;border-radius:50%;border:0;padding:0;
  background:var(--bp-ink);opacity:.18;cursor:pointer;
  transition:opacity .2s ease,transform .2s ease}
.bp-says__dot[aria-current="true"]{opacity:1;background:var(--bp-orange);transform:scale(1.25)}
.bp-says__arw{width:38px;height:38px;border-radius:50%;border:0;cursor:pointer;
  background:var(--bp-white);box-shadow:var(--bp-lift-2);color:var(--bp-ink);
  display:grid;place-items:center;font-size:15px;line-height:1;
  transition:box-shadow .2s ease,transform .2s ease}
.bp-says__arw:hover{box-shadow:var(--bp-lift-3);transform:translateY(-2px)}
.bp-says__arw[disabled]{opacity:.32;cursor:default;transform:none;box-shadow:var(--bp-lift-1)}
@media(max-width:820px){
  .bp-says__slide{padding:24px}
  .bp-says__track{gap:16px}
  .bp-says__arw{width:44px;height:44px}
}
@media(prefers-reduced-motion:reduce){.bp-says__track{transition:none}}

/* ---- 106. the contact hero holds the form -------------------------------
   Contact had a headline, then a CTA, then a section explaining the audit,
   then a form: four screens to do two things. The form moves into the fold
   beside the headline, and the audit section goes entirely — the CTA books
   the call directly, so there was nothing left to read on the way. */
.bp-hero--split{display:grid;grid-template-columns:1.18fr .82fr;gap:clamp(32px,5vw,64px);
  align-items:center;width:100%}
.bp-hero--split .bp-hero__inner{max-width:none}
.bp-hero__form{margin:0}
.bp-hero__form .bp-form__f{gap:7px}
.bp-hero__form button{margin-top:6px}
.bp-form__foot{margin:12px 0 0;font-size:12.5px;color:var(--bp-dim)}
.bp-form__foot span{color:var(--bp-orange);font-weight:600}
.bp-form__req{font-size:1rem;letter-spacing:0;text-transform:none;margin-left:4px}
@media(max-width:900px){
  .bp-hero--split{grid-template-columns:1fr;gap:34px}
}

/* The add-on row when its checkout link is not configured yet: visibly present
   so the option reads, but not operable, because a toggle that changes the
   price without changing the checkout undercharges on every use. */
.bp-switchrow.is-unavailable{opacity:.5}
.bp-switchrow.is-unavailable .bp-switch{cursor:not-allowed}
.bp-switchrow.ipad-on .bp-switchrow__txt{font-weight:600;color:var(--bp-ink)}

/* ---- 107. the coffee bubble ---------------------------------------------
   A small round portrait beside the "my coffee cup is always ready" line in
   the contact hero, tilted a few degrees toward the form so it reads as
   looking at it rather than at the reader. Inert until .bp-coffee exists in
   the markup. */
.bp-hero__note{display:flex;align-items:center;gap:14px}
.bp-coffee{width:64px;height:64px;flex:none;border-radius:50%;object-fit:cover;
  box-shadow:var(--bp-lift-2);
  transform:rotate(-4deg);transition:transform .3s ease}
.bp-coffee:hover{transform:rotate(0deg) scale(1.04)}
@media(max-width:820px){.bp-coffee{width:54px;height:54px}}
@media(prefers-reduced-motion:reduce){.bp-coffee{transition:none}}

/* The contact hero now carries a question, an invitation and the terms of the
   call, so it needs a middle voice between the title and the body: the
   invitation reads at lede size in ink, the explanation stays dim. */
.bp-hero__lead{font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);
  font-size:1.35rem;line-height:1.3;letter-spacing:-.02em;
  color:var(--bp-ink);margin:18px 0 0}
@media(max-width:820px){.bp-hero__lead{font-size:1.2rem}}


/* ==========================================================================
   109. ROI CALCULATOR — .bp-roi
   The old one was two number inputs and three grey result tiles: a form, not
   a calculator. A slider is the honest control for "roughly how big is your
   revenue", and it invites a drag where a number field invites nothing. Ink
   panel so it reads as an instrument, and the one number that matters is the
   only orange thing on the page at that moment.
   ========================================================================== */
.bp-roi{display:grid;grid-template-columns:1.35fr .65fr;gap:4px;
  border-radius:var(--bp-r-card);overflow:hidden;box-shadow:var(--bp-lift-3)}
.bp-roi__panel{background:var(--bp-ink);color:#fff;padding:38px 40px 34px;
  display:flex;flex-direction:column;gap:0}
.bp-roi__eyebrow{font-family:var(--bp-body);font-weight:600;font-size:11px;
  letter-spacing:var(--bp-lbl-track);text-transform:uppercase;
  color:rgba(255,255,255,.45);margin:0 0 22px}
.bp-roi__lead{display:flex;flex-wrap:wrap;align-items:baseline;gap:14px;
  font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);
  font-size:1.6rem;line-height:1.15;letter-spacing:-.025em;color:rgba(255,255,255,.62)}
.bp-roi__num{color:#fff;font-size:2.4rem;letter-spacing:-.04em;
  font-variant-numeric:tabular-nums;
  border-bottom:2px solid rgba(255,255,255,.22);padding-bottom:2px}

/* the slider: one rule set, both engines */
.bp-range{-webkit-appearance:none;appearance:none;width:100%;height:34px;
  margin:26px 0 0;background:transparent;cursor:grab}
.bp-range:active{cursor:grabbing}
.bp-range::-webkit-slider-runnable-track{height:10px;border-radius:100px;
  background:linear-gradient(90deg,var(--bp-orange) 0 var(--fill,20%),
    rgba(255,255,255,.14) var(--fill,20%) 100%)}
.bp-range::-moz-range-track{height:10px;border-radius:100px;background:rgba(255,255,255,.14)}
.bp-range::-moz-range-progress{height:10px;border-radius:100px;background:var(--bp-orange)}
.bp-range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;
  width:28px;height:28px;border-radius:50%;background:#fff;margin-top:-9px;
  box-shadow:0 2px 10px rgba(0,0,0,.45);border:0;transition:transform .15s ease}
.bp-range::-moz-range-thumb{width:28px;height:28px;border-radius:50%;background:#fff;
  border:0;box-shadow:0 2px 10px rgba(0,0,0,.45)}
.bp-range:hover::-webkit-slider-thumb{transform:scale(1.08)}
.bp-range:focus-visible{outline:none}
.bp-range:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 4px rgba(255,77,0,.55)}
.bp-roi__scale{display:flex;justify-content:space-between;margin-top:10px;
  font-size:12px;color:rgba(255,255,255,.38);font-variant-numeric:tabular-nums}

.bp-roi__aside{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  margin-top:26px;padding-top:22px;border-top:1px solid rgba(255,255,255,.12)}
.bp-roi__aside label{font-size:13.5px;color:rgba(255,255,255,.62);
  display:flex;align-items:baseline;gap:8px}
.bp-roi__aside em{font-style:normal;font-size:11px;letter-spacing:var(--bp-lbl-track);
  text-transform:uppercase;color:rgba(255,255,255,.32)}
.bp-roi__aside input{width:130px;background:rgba(255,255,255,.09);color:#fff;border:0;
  border-radius:var(--bp-r-sm);padding:10px 13px;font-family:var(--bp-body);font-size:14px;
  font-variant-numeric:tabular-nums}
.bp-roi__aside input::placeholder{color:rgba(255,255,255,.3)}
.bp-roi__aside input:focus{outline:none;box-shadow:0 0 0 2px var(--bp-orange)}
.bp-roi__note{margin:22px 0 0;font-size:12.5px;line-height:1.6;color:rgba(255,255,255,.42)}
.bp-roi__note strong{color:rgba(255,255,255,.8);font-weight:600}

.bp-roi__out{background:var(--bp-white);padding:38px 34px;
  display:flex;flex-direction:column;justify-content:center;gap:6px}
.bp-roi__k{margin:0;font-family:var(--bp-body);font-weight:600;font-size:11px;
  letter-spacing:var(--bp-lbl-track);text-transform:uppercase;color:var(--bp-faint)}
.bp-roi__v{margin:2px 0 0;font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);
  font-size:clamp(2.6rem,4.4vw,3.4rem);line-height:1;letter-spacing:-.045em;
  color:var(--bp-orange);font-variant-numeric:tabular-nums}
.bp-roi__mini{display:flex;flex-direction:column;gap:12px;margin-top:26px;
  padding-top:20px;border-top:1px solid rgba(10,10,10,.09)}
.bp-roi__mini div{display:flex;justify-content:space-between;align-items:baseline;gap:14px}
.bp-roi__mini span{font-size:13px;color:var(--bp-dim)}
.bp-roi__mini b{font-family:var(--bp-display);font-weight:800;font-size:1.05rem;
  color:var(--bp-ink);font-variant-numeric:tabular-nums}
@media(max-width:900px){
  .bp-roi{grid-template-columns:1fr}
  .bp-roi__panel{padding:28px 24px 26px}
  .bp-roi__out{padding:28px 24px}
  .bp-roi__num{font-size:2rem}
}

/* ---- 109b. the calculator lives in the hero -----------------------------
   The hero had room and the calculator was the reason to scroll, so it moves
   up beside the headline. Reworked for comprehension: the slider says what it
   is measuring in a sentence, one paragraph states the assumption behind the
   numbers, and the outputs are a definition list so each figure is bound to
   its label rather than floating near it. aria-live announces the result when
   the slider moves; aria-valuetext gives the thumb a spoken value.        */
.bp-hero--roi{gap:clamp(40px,6vw,92px)}
.bp-roi--hero{display:flex;flex-direction:column;gap:0;
  background:var(--bp-white);color:var(--bp-ink);border-radius:var(--bp-r-card);
  padding:30px 32px 26px;box-shadow:var(--bp-lift-2);margin:0}
.bp-roi--hero .bp-roi__eyebrow{margin:0 0 18px;color:var(--bp-orange)}
.bp-roi--hero .bp-roi__lead{font-size:1.15rem;gap:9px;color:var(--bp-dim)}
.bp-roi--hero .bp-roi__num{font-size:1.9rem;color:var(--bp-ink);
  border-bottom-color:rgba(255,77,0,.35)}
/* the track is light here, so the thumb has to be the dark element */
.bp-roi--hero .bp-range::-webkit-slider-runnable-track{
  background:linear-gradient(90deg,var(--bp-orange) 0 var(--fill,20%),
    rgba(10,10,10,.10) var(--fill,20%) 100%)}
.bp-roi--hero .bp-range::-moz-range-track{background:rgba(10,10,10,.10)}
.bp-roi--hero .bp-range::-webkit-slider-thumb{background:var(--bp-ink);
  box-shadow:0 2px 10px rgba(10,10,10,.3)}
.bp-roi--hero .bp-range::-moz-range-thumb{background:var(--bp-ink);
  box-shadow:0 2px 10px rgba(10,10,10,.3)}
.bp-roi--hero .bp-range:focus-visible::-webkit-slider-thumb{
  box-shadow:0 0 0 4px rgba(255,77,0,.45)}
.bp-roi--hero .bp-roi__scale{color:var(--bp-faint)}
.bp-roi__how{margin:20px 0 0;font-size:13.5px;line-height:1.6;color:var(--bp-dim)}
.bp-roi__how strong{color:var(--bp-ink);font-weight:600}
.bp-roi--hero .bp-roi__out{background:transparent;padding:22px 0 0;margin-top:22px;
  border-top:1px solid rgba(10,10,10,.10);
  display:flex;flex-wrap:wrap;gap:24px 40px}
.bp-roi--hero .bp-roi__out > div{display:flex;flex-direction:column;gap:4px}
.bp-roi--hero dt{font-family:var(--bp-body);font-weight:600;font-size:11px;
  letter-spacing:var(--bp-lbl-track);text-transform:uppercase;color:var(--bp-faint)}
.bp-roi--hero dd{margin:0;font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);font-size:1.5rem;line-height:1.1;
  letter-spacing:-.03em;color:var(--bp-ink);font-variant-numeric:tabular-nums}
.bp-roi--hero dd.bp-roi__v{font-size:2.6rem;color:var(--bp-orange);margin:0}
.bp-roi--hero .bp-roi__note{margin-top:18px;font-size:12px;color:var(--bp-faint)}
@media(max-width:900px){
  .bp-roi--hero{padding:24px 22px 22px}
  .bp-roi--hero dd.bp-roi__v{font-size:2.2rem}
}

/* ---- cases: the work is the content, so it gets the room ---------------- */
.bp-cases--wide{display:flex;flex-direction:column;gap:clamp(40px,5vw,72px)}
.bp-cases--wide .bp-case{background:var(--bp-white);border-radius:var(--bp-r-card);
  box-shadow:var(--bp-lift-2);padding:26px 26px 22px;display:flex;flex-direction:column;gap:20px}
/* stacked, not side by side: an App Store screenshot set is a wide strip of
   phone screens, and half a column made them too small to actually read */
.bp-cases--wide .bp-case__ba{display:grid;grid-template-columns:1fr;gap:16px}

.bp-cases--wide .bp-case__shot{margin:0;position:relative}
.bp-cases--wide .bp-case__shot img{width:100%;height:auto;display:block;
  border-radius:14px;box-shadow:var(--bp-lift-1)}
.bp-cases--wide .bp-case__tag{position:absolute;top:12px;left:12px;z-index:2;
  font-family:var(--bp-body);font-weight:600;font-size:11px;
  letter-spacing:var(--bp-lbl-track);text-transform:uppercase;
  padding:6px 12px;border-radius:100px;background:var(--bp-ink);color:#fff;
  box-shadow:var(--bp-lift-1)}
.bp-cases--wide .bp-case__shot--before .bp-case__tag{background:rgba(255,255,255,.94);color:var(--bp-ink)}
.bp-cases--wide .bp-case__shot--before img{opacity:1}
.bp-cases--wide .bp-case__result{margin:0;font-family:var(--bp-display);font-weight:800;
  font-variation-settings:"wdth" var(--bp-wdth);
  font-size:1.9rem;letter-spacing:-.03em;color:var(--bp-orange)}
.bp-cases--wide .bp-case__meta{display:flex;align-items:center;gap:14px;margin:0}
.bp-cases--wide .bp-case__icon{width:44px;height:44px;border-radius:12px;flex:none}
.bp-cases--wide .bp-case__name{font-weight:600;font-size:1rem;color:var(--bp-ink)}
.bp-cases--wide .bp-case__cat{font-size:13px;color:var(--bp-dim);margin-top:2px}
@media(max-width:760px){
  .bp-cases--wide .bp-case{padding:14px 14px 16px}
}

/* one plan, so it should not stretch to a two-column grid's width */
.bp-plans--one{grid-template-columns:minmax(0,620px);justify-content:center}
.bp-how{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;position:static}
@media(max-width:820px){.bp-how{grid-template-columns:1fr}}

/* ==========================================================================
   110. 404 — the numerals ARE the portfolio
   Forty-four tiles laid on a 17x7 bitmap spell 404, and every tile is an app
   whose listing or paywall was actually rebuilt. Icons scattered loosely say
   nothing; icons that resolve into the error code make the dead end the most
   memorable page on the site. Decorative, so the grid is aria-hidden and the
   h1 carries the meaning for anything not looking at it.
   ========================================================================== */
.bp-404__glyph{display:grid;grid-template-columns:repeat(50,1fr);
  grid-template-rows:repeat(18,1fr);gap:clamp(1px,.2vw,3px);
  width:100%;max-width:none;margin:40px 0 8px}
.bp-404__tile{width:100%;height:auto;aspect-ratio:1;border-radius:24%;
  object-fit:cover;box-shadow:0 1px 3px rgba(10,10,10,.16);
  animation:bp-404-float 7s var(--bp-ease) infinite;
  animation-delay:calc(var(--i) * -.14s);
  transition:transform .25s ease,box-shadow .25s ease}
.bp-404__tile:hover{transform:scale(2.6);box-shadow:var(--bp-lift-2);z-index:2;border-radius:20%}
@keyframes bp-404-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}
@media(prefers-reduced-motion:reduce){.bp-404__tile{animation:none}}
.bp-404__links{display:flex;flex-wrap:wrap;gap:12px;margin-top:34px;align-items:center}
.bp-404__credit{margin:16px 0 0;font-size:12px;color:var(--bp-faint)}
.bp-404__credit a{color:var(--bp-dim);text-decoration:underline;text-underline-offset:2px}
.bp-404__credit a:hover{color:var(--bp-orange)}
@media(max-width:820px){
  .bp-404__glyph{margin-top:26px;gap:1px}
  .bp-404__tile{border-radius:22%;box-shadow:none}
}
