/* ═══════════════════════════════════════════════════════════════════════════
 * ONLYFLOW — the marketing site.
 *
 * The palette is not chosen, it is DERIVED: every value is 255-n applied per
 * channel to OnlyFans' own verified brand blue (#00AEEF, counted from pixels,
 * not from memory). OnlyFans is where the money is made — bright, white, soft,
 * facing the fan. OnlyFlow is where it is settled — hot, black, hard, facing
 * the business. Their cool gray inverts to a WARM taupe; nobody picked that,
 * the arithmetic handed it over.
 *
 * ⭐ THE ONE HARD RULE: signal (#FF5110) means MONEY or THE NEXT ACTION.
 *    Nothing else. Not headings, not icons, not borders, not "emphasis".
 *    The moment it decorates, it stops meaning anything.
 * ⭐ Color proportion ≈ 80/15/5 — ground / type / signal.
 * ⭐ There is no red and no green in this system. A failure is described in
 *    words, not painted.
 * ═══════════════════════════════════════════════════════════════════════════ */
:root{
  --ground:#000000;      /* 255-255 */
  --raise:#0B0B0B;       /* 255-244 */
  --rule:#222222;        /* 255-221 */
  --body:#E1E1E1;        /* 255-30  */
  --muted:#75695C;       /* the warm taupe the maths produced */
  --signal:#FF5110;      /* 255-0, 255-174, 255-239 */
  --signal-press:#FF7330;
  --shadow:#3A1B0B;      /* the cut's dark half */
  --them:#00AEEF;        /* theirs, used once, deliberately */

  /* ── motion: one easing language. `--ease` is a long, settled decel — money
     arriving, not a UI popping. `--ease-soft` is for things that only fade. */
  --ease:cubic-bezier(.22,1,.36,1);
  --ease-soft:cubic-bezier(.33,1,.68,1);
  --dur:820ms;

  /* ── how the page grows past a laptop. One origin, 1400px, for every ramp. ── */
  --max:clamp(1180px, calc(1180px + (100vw - 1400px) * 0.42), 1780px);
  --gut:clamp(20px,5vw,64px);

  /* One grotesque, two roles. Money is ALWAYS mono and ALWAYS tabular. */
  --sans:-apple-system,BlinkMacSystemFont,"Helvetica Neue","Segoe UI",Helvetica,Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
}
/* ═══════════════════════════════════════════════════════════════════════════
 * ⭐⭐ LARGE SCREENS — THE PAGE IS DESIGNED FOR THEM, NOT CENTERED ON THEM.
 *
 * 🩸 MEASURED, ACROSS SEVEN VIEWPORTS. `--max` was a flat 1180px and there was no
 * media query above 820px anywhere in this file, so:
 *
 *     1280px   content 1180px   92% of the screen
 *     1920px   content 1180px   61%      370px of empty black each side
 *     2560px   content 1180px   46%      690px each side
 *     3440px   content 1180px   34%     1130px each side
 *
 * and `body` was 17px at EVERY width from 390 to 3440. On an ultrawide that is a phone
 * layout floating in the middle of a very large black rectangle. Operator: "when say i
 * have a bigger monitor then say normal people the website fills to fit my screen".
 *
 * ⭐ THE HEADLINES COME FOR FREE, and that is why this is only a few lines. `.col .display`
 * is `clamp(38px, 12.4cqw, 88px)` — a CONTAINER query, not a viewport one — so every
 * display size is already a proportion of the column it sits in. Widen the container and
 * the type scales with it, in the ratio the design was drawn at.
 *
 * ‼️ WHAT DOES NOT SCALE IS READING MEASURE. `.lede` is capped in `ch` and prose columns
 * stay where they are: a 1,600px line of body text is unreadable however large the screen
 * is. The container grows; the line length does not.
 *
 * ‼️ AND IT IS STEPPED, NOT CONTINUOUS. A pure `vw` container means no two people ever see
 * the same layout and nothing can be checked against a reference. Three steps can each be
 * measured, and `tools/verify/vpscale.mjs` measures all of them.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* ⭐ CONTINUOUS, NOT STEPPED — AND `fluid.mjs` IS WHY.
 *
 * The first version of this was four media queries at 1500/1800/2300/3000px. It filled the
 * screen correctly and `tools/verify/fluid.mjs` failed it immediately:
 *
 *     terms.html 1480→1500px  font 17px → 18.02px
 *     (6%, 5% more than the window moved, after 1160px of stillness)
 *
 * which is exactly right. A 6% jump in body type from one pixel of window movement is a
 * visible pop, and "fills every viewport" has to mean EVERY viewport, not four of them.
 *
 * ‼️ THE RAMP IS WRITTEN IN LENGTHS, NOT IN A UNITLESS SCALE. CSS cannot turn a length into
 * a plain number — `calc((100vw - 1400px) / 1px)` is invalid — so there is no `--scale`
 * multiplier to be had. Each value carries its own ramp instead, all with the same origin
 * (1400px, where the design stops being drawn) and the same shape.
 *
 * Below 1400px every one of these resolves to its minimum, because the middle term goes
 * negative and `clamp` returns the floor. Nothing about a laptop or a phone moves. */
*,*::before,*::after{box-sizing:border-box}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
html{background:var(--ground)}
body{
  margin:0;background:transparent;color:var(--body);
  /* ‼️ THE RAMP STARTS AT 1400px AND NOT BEFORE. Body copy must not creep up on a laptop:
     17px is the design size and stays exactly 17px until the container itself starts to
     grow. Below 1400px the middle term is negative and clamp returns the floor. */
  font-family:var(--sans);font-size:clamp(17px, calc(17px + (100vw - 1400px) * 0.0028), 22px);line-height:1.6;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
/* Every digit on this site aligns on the decimal. Comparing numbers is the
   only thing anyone actually does here. */
[class*="fig"],table,.mono,.money{font-variant-numeric:tabular-nums}
img,svg{max-width:100%;height:auto;display:block}
a{color:inherit}
/* ── type scale ──────────────────────────────────────────────────────────── */
/* ‼️ A display heading is sized against ITS CONTAINER, not the viewport.
   Sizing by 8.2vw while the box was capped at 11ch rendered 104px type into a
   506px column — "conversation." is 601px wide, so it clipped on EVERY page.
   `cqw` reads the column; `break-word` is the net so a long word can never
   overflow even if a container is missing. */
.col{container-type:inline-size}
.display{
  font-size:clamp(38px, 7.4vw, clamp(88px, calc(88px + (100vw - 1400px) * 0.014), 118px));font-weight:800;line-height:0.94;
  letter-spacing:-0.045em;color:#fff;margin:0;text-wrap:balance;
  overflow-wrap:break-word;
}
.col .display{font-size:clamp(38px, 12.4cqw, clamp(88px, calc(88px + (100vw - 1400px) * 0.014), 118px))}
h2{
  font-size:clamp(28px, 4.4vw, clamp(52px, calc(52px + (100vw - 1400px) * 0.009), 72px));font-weight:800;line-height:1.04;
  letter-spacing:-0.038em;color:#fff;margin:0 0 18px;text-wrap:balance;
}
h3{font-size:20px;font-weight:800;letter-spacing:-0.02em;color:#fff;margin:0 0 8px}
p{margin:0 0 16px;max-width:64ch}
.lede{font-size:clamp(18px, 2.1vw, clamp(23px, calc(23px + (100vw - 1400px) * 0.0024), 28px));line-height:1.5;color:var(--body);max-width:40ch}
.dim{color:var(--muted)}
b,strong{color:#fff;font-weight:700}
/* 11px mono, uppercase, wide — the label voice throughout the system */
.label{
  font-family:var(--mono);font-size:11px;letter-spacing:0.24em;
  text-transform:uppercase;color:var(--muted);margin:0 0 14px;
}
.money{font-family:var(--mono);font-weight:700;color:#fff;letter-spacing:-0.02em;
  overflow-wrap:break-word}
/* ── layout ──────────────────────────────────────────────────────────────── */
.wrap{max-width:var(--max);margin:0 auto;padding:0 var(--gut)}
section{padding:clamp(72px,11vw,150px) 0;position:relative}
.rule{height:1px;background:var(--rule);border:0;margin:0}
/* ── THE CUT — one shape does the app icon, the favicon, the wordmark
   separator and the live gauge. A diagonal already has direction, and unlike
   a chevron it can hold a fill level. ─────────────────────────────────────── */
.cut{display:inline-block;vertical-align:-0.14em}
.cut rect{fill:var(--shadow)}
.cut path{fill:var(--signal)}
/* ── wordmark: ONLY◤FLOW ─────────────────────────────────────────────────── */
.wm{
  font-weight:800;letter-spacing:-0.045em;color:#fff;
  display:inline-flex;align-items:center;gap:0.1em;text-decoration:none;
  /* 19px at 640 and below, rising to 21px at 1000 — the two ends the breakpoint used
     to jump between, with every width in between now on the line joining them. */
  font-size:clamp(19px, 0.5556vw + 15.44px, 21px);
}
.wm .cut{margin:0 0.06em}
/* ── THE CUT MAKES ITSELF ─────────────────────────────────────────────────
   The mark IS a diagonal — a payout arriving whole and being divided. It is the
   one motion the whole system is built from, and until now it was the only place
   that motion never happened. On load the slab is whole, then the cut opens
   through it, once. It plays on arrival and never again; a logo that keeps
   animating is a logo you stop reading.

   ‼️ Guarded on `.js` like every other rest state. Without JS the mark is simply
   finished, which is what it looked like before this existed. */
.js .wm .cut path{clip-path:polygon(0 0,0 0,0 100%,0 100%);
  transition:clip-path 900ms var(--ease) 260ms}
.js.lit .wm .cut path{clip-path:polygon(0 0,100% 0,100% 100%,0 100%)}
@media (prefers-reduced-motion:reduce){.js .wm .cut path{clip-path:none;transition:none}}
/* ── header ──────────────────────────────────────────────────────────────── */
header{
  position:sticky;top:0;z-index:50;background:rgba(0,0,0,0.86);
  backdrop-filter:saturate(140%) blur(14px);border-bottom:1px solid var(--rule);
}
header .wrap{display:flex;align-items:center;justify-content:space-between;
  gap:20px;height:66px}
nav{display:flex;align-items:center;gap:clamp(14px,2.4vw,30px)}
nav a{
  font-size:14px;color:var(--muted);text-decoration:none;font-weight:600;
  letter-spacing:-0.01em;transition:color .16s;
}
nav a:hover,nav a:focus-visible{color:#fff}
nav a[aria-current="page"]{color:#fff}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE MENU — one hamburger, every width.
 *
 * Operator, 2026-08-22: "the home page and the how it works page i need the
 * hambruger icon for desktop mobile and tablet". Not a mobile fallback that a
 * wide screen hides: the same control at 320px and at 2560px.
 *
 * ⭐ IT IS A <details>, NOT A SCRIPT. Open, close, focus, Enter and Space all come
 * from the browser, so the menu works with JavaScript blocked, on an old phone, and
 * in a reader — which is the population most likely to be on a locked-down device.
 * The script adds Escape and click-outside and nothing else.
 *
 * ⭐ "GET STARTED" STAYS OUTSIDE IT. The one signal-colored control on the page is
 * the next action; burying it behind a tap to make the header tidier trades the
 * thing the page is for against a small amount of symmetry.
 * ═══════════════════════════════════════════════════════════════════════════ */
header .wrap{position:relative}
.hdr-right{display:flex;align-items:center;gap:clamp(10px,1.6vw,18px)}
.menu{position:relative}
.menu summary{
  list-style:none;display:inline-flex;align-items:center;justify-content:center;
  width:42px;height:38px;cursor:pointer;border:1px solid var(--rule);
  background:transparent;transition:border-color .16s,background .16s;
}
.menu summary::-webkit-details-marker{display:none}
.menu summary::marker{content:''}
.menu summary:hover,.menu summary:focus-visible{border-color:var(--muted);background:var(--raise)}
/* three bars, drawn from one element so there is nothing to misalign */
.bars{position:relative;display:block;width:18px;height:2px;background:var(--body);
  transition:background .18s var(--ease),transform .22s var(--ease)}
.bars::before,.bars::after{content:'';position:absolute;left:0;width:18px;height:2px;
  background:var(--body);transition:transform .24s var(--ease),opacity .16s linear}
.bars::before{top:-6px}
.bars::after{top:6px}
/* open: the middle bar goes, the outer two cross. The icon says what it does. */
.menu[open] .bars{background:transparent}
.menu[open] .bars::before{transform:translateY(6px) rotate(45deg)}
.menu[open] .bars::after{transform:translateY(-6px) rotate(-45deg)}
/* ═══════════════════════════════════════════════════════════════════════════
 * 🩸 THE MENU WAS EIGHT IDENTICAL LINKS IN A DARK BOX.
 *
 * Operator: "this whole area needs a rework i cant belivlie this got pushed this is th
 * emot disgutsting ui ux ever ... make the hamburger menu beaitful".
 *
 * They were right, and the fault was not the styling — it was that the menu carried NO
 * INFORMATION. Eight destinations, evenly weighted, in the order they happened to be
 * written, each one a bare noun. "Compliance" and "Answers" and "Refer" tell somebody
 * nothing about which one to press, so the menu made every visitor guess and the widest
 * page on the site opened onto a list.
 *
 * ⭐ THREE GROUPS, AND EACH ENTRY SAYS WHAT IS BEHIND IT. The groups are the actual
 * question a visitor is asking in order — what is it, can I trust it, what do I get —
 * and the second line is the answer the link would otherwise make them click to find.
 * That is what turns a list into a menu.
 *
 * ⭐ THE ACCENT MARKS ONE THING: where you already are. Everything else is body and
 * muted, so the eye lands on the page you are on and then reads down.
 * ═══════════════════════════════════════════════════════════════════════════ */
.menu-panel{
  position:absolute;top:calc(100% + 11px);right:0;z-index:60;
  display:flex;flex-direction:column;align-items:stretch;gap:0;
  width:min(360px,calc(100vw - 32px));padding:8px 0 10px;
  background:#0B0B0B;border:1px solid var(--rule);
  box-shadow:0 30px 80px rgba(0,0,0,.8);
}
/* the group label — the site's own mono, quiet, and never a link */
.menu-k{
  margin:14px 0 2px;padding:0 20px;font-family:var(--mono);font-size:9.5px;
  letter-spacing:.22em;text-transform:uppercase;color:var(--muted);
}
.menu-panel > .menu-k:first-child{margin-top:6px}
.menu-panel a{
  display:block;padding:9px 20px 10px;color:var(--body);
  border-left:2px solid transparent;
  transition:background .14s,color .14s,border-color .14s;
}
.menu-panel a b{
  display:block;font-size:15px;font-weight:700;letter-spacing:-.012em;color:#fff;
  line-height:1.3;
}
.menu-panel a span{
  display:block;margin-top:2px;font-size:12.5px;line-height:1.4;color:var(--muted);
  /* ‼️ THE DESCRIPTION WRAPS. `white-space:nowrap` was on the old links to keep the panel
     narrow; with a second line that would push the panel past the viewport. */
  white-space:normal;
}
.menu-panel a:hover,.menu-panel a:focus-visible{background:#141414}
.menu-panel a:hover span,.menu-panel a:focus-visible span{color:var(--body)}
.menu-panel a[aria-current="page"]{border-left-color:var(--signal);background:#121212}
.menu-panel a[aria-current="page"] b{color:var(--signal)}
.js .menu[open] .menu-panel{animation:menu-in 200ms var(--ease) both}
@keyframes menu-in{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
/* on a narrow screen it spans the gutters instead of hanging off one corner */
/* ON A NARROW SCREEN IT IS A SHEET, EDGE TO EDGE, not a card floating in the corner.
   🩸 The first attempt inset it by a gutter on each side and the right edge hung 20px
   OFF THE SCREEN — measured in a browser at 390px: x=20, width=390, right edge 410. So
   the side borders come off too: a bordered box clipped by the screen edge reads as
   broken, and a sheet with a bottom rule reads as intended. */
@media (max-width:560px){.menu{position:static}
.menu-panel{left:0;right:0;min-width:0;border-left:0;border-right:0}}
@media (prefers-reduced-motion:reduce){.bars,.bars::before,.bars::after{transition:none}
.js .menu[open] .menu-panel{animation:none}}
/* ═══════════════════════════════════════════════════════════════════════════
 * ⭐⭐ THE DESKTOP BAR — 2026-09-06. THE LINKS ARE ON THE HEADER, NOT BEHIND IT.
 *
 * 🩸 This REVERSES the 2026-08-22 instruction one block up ("i need the hambruger
 * icon for desktop mobile and tablet"). Operator, 2026-09-06, with a 1997px
 * screenshot: "On desktop the navbar needs to be fixed. It is currently a 3 line
 * drop down menu with the items contained in it, as if it's mobile but this is how
 * it is on desktop. They need to be on the navbar." Read the two together before
 * changing this again — the hamburger at every width was DELIBERATE and it is being
 * deliberately undone, not fixed by accident.
 *
 * ⭐ ONE CONTROL PER WIDTH, NEVER BOTH. Below 900px the bar is gone and the
 * hamburger is the nav, exactly as it was. At 900px and up the hamburger is gone and
 * the bar is the nav. A header carrying both is a header that has not decided, and a
 * visitor who can reach the same four links two ways reads the second way as a bug.
 *
 * ⭐ 900px IS WHERE THE ROW STOPS FITTING, not a round number borrowed from a
 * framework. Measured: wordmark 128 + four links 254 + their gaps 72 + Sign in 47 +
 * Get started 112 = 613px of content, and at 900px the gutters leave 810px. The
 * gutter ramp (`--gut`, 5vw) takes MORE of the screen as it narrows, so the margin
 * closes from both ends at once — 900 keeps roughly 200px of air at the tightest
 * point rather than the 30px a 768 breakpoint would have left.
 *
 * ⭐ WHERE YOU ARE IS MARKED THE WAY THE PANEL ALREADY MARKS IT. The open menu
 * paints a 2px signal border down the left of the current page; the bar paints the
 * same 2px signal rule under it, sitting ON the header's bottom border rather than
 * floating above it. Same gesture, rotated — the system reuses shapes, it does not
 * invent a second vocabulary for the same fact. Nothing else here is signal: the
 * links are muted, they go white on hover, and the only orange control in the header
 * is still the one that means the next action.
 *
 * ‼️ THE LINKS ARE DUPLICATED IN THE DOM — once here, once inside the <details>.
 * That is a real cost and it is paid on purpose: reflowing the SAME <details> into a
 * row means overriding a UA rule that hides a closed details' children, which older
 * WebKit does not let you override, and the failure mode there is a desktop header
 * with NO navigation at all. `.dev/verify-hdr-nav.mjs` fails the build if the two
 * lists ever disagree, on any page, so the duplication cannot drift in silence.
 * ═══════════════════════════════════════════════════════════════════════════ */
.hdr-nav{display:none}
.hdr-signin{display:none}

@media (min-width:900px){
  /* the hamburger is not "hidden on desktop" — at this width it is not the nav */
  .menu{display:none}

  /* ⭐ `margin-left:auto` and NOT a wrapper div. The header is
     `justify-content:space-between` with the wordmark and the action cluster as its
     two ends; an auto margin on the middle child beats space-between, and putting it
     on the LEFT collapses all the slack there — so the wordmark holds the far left on
     its own and the four links sit hard against Sign in and Get started. Operator,
     2026-09-06: "have those four items on the left placed to the left of the sign in
     and get started buttons". No markup nesting, and it still unwinds to exactly the
     old two-child header the moment `display:none` comes back below 900px.

     ⭐ `margin-right` IS THE SEPARATION AND IT IS NOT DECORATION. Reading right to
     left the header now runs orange button, Sign in, then four muted links with
     nothing but whitespace between the groups. At the header's own 20px gap the last
     link would sit closer to Sign in than Sign in sits to Get started, which reads as
     five items in one row rather than navigation next to actions. This puts the
     biggest gap in the row at that seam — the only thing separating them, so it has
     to be the largest. */
  .hdr-nav{
    display:flex;align-self:stretch;align-items:stretch;
    margin-left:auto;margin-right:clamp(10px,1.6vw,24px);
    gap:clamp(6px,1.4vw,16px);
  }
  /* full-height hit targets: the whole 66px band is the link, so the current-page
     rule can sit on the header's own border instead of hovering near it */
  .hdr-nav a{
    position:relative;display:inline-flex;align-items:center;padding:0 8px;
    font-size:14px;font-weight:600;letter-spacing:-.01em;color:var(--muted);
    text-decoration:none;transition:color .16s;white-space:nowrap;
  }
  .hdr-nav a:hover,.hdr-nav a:focus-visible{color:#fff}
  /* ‼️ THE RING GOES INSIDE. Global focus is outline-offset:3px, and on a link that is
     the full 66px of the header that pushes the top edge of the ring off the top of the
     viewport — a focus indicator clipped by the window is the one state where "nearly
     visible" is worth nothing. The 8px of horizontal padding is what gives a NEGATIVE
     offset somewhere to sit without biting into the first and last letter. */
  .hdr-nav a:focus-visible{outline-offset:-4px}
  .hdr-nav a[aria-current="page"]{color:#fff}
  .hdr-nav a[aria-current="page"]::after{
    /* inset by the padding so the rule is the width of the WORD, not of the hit
       target — the mark says which page, and a rule wider than its label reads as a
       button that failed to draw its box. */
    content:'';position:absolute;left:8px;right:8px;bottom:-1px;height:2px;
    background:var(--signal);
  }
  /* Sign in is an ACTION, so it sits in the action cluster — but it is the quiet one.
     Body white against the muted links, and it never competes with the orange. */
  .hdr-signin{
    display:inline-flex;align-items:center;
    font-size:14px;font-weight:600;letter-spacing:-.01em;color:var(--body);
    text-decoration:none;transition:color .16s;white-space:nowrap;
  }
  .hdr-signin:hover,.hdr-signin:focus-visible{color:#fff}
}
/* The only signal-colored control on the page: it is the NEXT ACTION. */
.cta{
  display:inline-flex;align-items:center;gap:10px;
  background:var(--signal);color:#000;font-weight:800;letter-spacing:-0.015em;
  padding:13px 22px;border-radius:0;text-decoration:none;font-size:15px;
  border:0;cursor:pointer;transition:background .16s;
}
.cta:hover,.cta:focus-visible{background:var(--signal-press)}
.cta.sm{padding:9px 16px;font-size:14px}
.cta.ghost{background:transparent;color:#fff;border:1px solid var(--rule)}
.cta.ghost:hover{border-color:var(--signal);background:transparent}
/* ── THE CUT, ON THE BUTTON ───────────────────────────────────────────────
   The mark is a diagonal opening through a solid slab. The primary action is
   the only other place on the site where a solid orange slab exists, so the
   same gesture belongs on it: on hover the cut sweeps through, up and to the
   right, once. It is the brand's single motion, reused rather than invented.

   ‼️ On the ghost button there is no slab to cut, so it does not get one —
   a gesture that means "dividing a payment" is not decoration to sprinkle. */
.cta{position:relative;overflow:hidden;isolation:isolate}
.cta::before{content:'';position:absolute;inset:0;z-index:-1;background:var(--shadow);
  clip-path:polygon(-30% 100%, -12% 100%, 30% 0, 12% 0);
  transform:translateX(-40%);opacity:0;
  transition:transform 620ms var(--ease),opacity 260ms linear}
.cta:hover::before,.cta:focus-visible::before{transform:translateX(420%);opacity:.55}
.cta.ghost::before{display:none}
@media (prefers-reduced-motion:reduce){.cta::before{display:none}}
:focus-visible{outline:2px solid var(--signal);outline-offset:3px}
/* ═══ HERO ═══ asymmetric. The claim sits left; the gauge occupies the right
   and is the only thing that moves on the whole page. ─────────────────────── */
.hero{padding-top:clamp(56px,9vw,110px);padding-bottom:clamp(56px,9vw,110px);overflow:hidden}
/* ⭐ THE CREDENTIALS CARD, no longer a grid child of the how-it-works hero — it moved
   down to sit with the argument it belongs to. `.nolog` carries `margin-left:auto`
   because in the hero it hugged the right of its column; here the column IS the page,
   so that pushes it into the middle of nothing. It lines up with the paragraph above
   it instead, which is what it is evidence for. */
/* ═══════════════════════════════════════════════════════════════════════════════
   🩸 `.link` WAS USED ON EVERY BLOG POST AND DEFINED IN NO STYLESHEET THE SITE LOADS.
   Two text links in the closing panel of all twelve posts — "See how it works" and
   "What it costs" — rendered as body copy with no color and no rule under them, beside
   a "Get started" that had the same problem. Both were invisible to the markup guard,
   which read only the ten top-level pages and never descended into `site/blog/`.

   ⭐ THE SAME RULE THE PRODUCT USES (app/src/brand.mjs), so a reader moving between the
   blog and the app sees one vocabulary. The accent is the site's signal orange, and
   these links ARE the next action, which is what that color is reserved for.
   ═══════════════════════════════════════════════════════════════════════════════ */
.link{color:var(--signal);border-bottom:1px solid var(--signal);font-size:14px;
  text-decoration:none;padding-bottom:1px}
.link:hover,.link:focus-visible{color:#fff;border-bottom-color:#fff}
.nolog-wrap{margin-top:clamp(18px,2.4vw,26px)}
.nolog-wrap .nolog{margin-left:0}
.hero-grid{display:grid;grid-template-columns:minmax(0,1.28fr) minmax(0,1fr);
  gap:clamp(28px,5vw,72px);align-items:center}
.hero .display em{font-style:normal;color:var(--signal)}
.hero .lede{margin-top:22px}
.hero-actions{display:flex;flex-wrap:wrap;gap:12px;margin-top:30px}
/* ⛔ THE GAUGE AND THE RUN WERE REMOVED HERE, 2026-08-21.
   Both were complete components that NO page rendered, and both were still
   named in every page's IntersectionObserver — dead CSS keeping dead JS alive.
   ‼️ The gauge in particular must not live in the MARKETING stylesheet: the
   brand book is explicit that it is in-product only, because a mark that
   reports a number it cannot know is worse than one that says nothing.
   The product's own sequence component is `.rung`, in the product stylesheet. */
/* ═══ THE LEDGER ═══ the problem, set like a bank statement ────────────────── */
.ledger{background:var(--raise);border-top:1px solid var(--rule);
  border-bottom:1px solid var(--rule)}
.ledger-rows{margin-top:34px;border-top:1px solid var(--rule)}
.lrow{display:grid;grid-template-columns:auto 1fr auto;gap:clamp(12px,3vw,32px);
  align-items:baseline;padding:17px 0;border-bottom:1px solid var(--rule)}
.lrow .t{font-family:var(--mono);font-size:12px;color:var(--muted)}
.lrow .d{color:var(--body)}
.lrow .v{font-family:var(--mono);font-size:14px;color:var(--muted);
  text-align:right}
.lrow.tot{border-bottom:3px double var(--rule);border-top:1px solid var(--rule)}
.lrow.tot .d,.lrow.tot .v{color:#fff;font-weight:700}
/* ═══ DIRECTIONS ═══ two mirrored flows ───────────────────────────────────── */
.dirs{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--rule);
  margin-top:40px;border:1px solid var(--rule)}
.dir{background:var(--ground);padding:clamp(22px,3.4vw,38px)}
.dir h3{display:flex;align-items:center;gap:10px}
.flowline{margin:20px 0 0;font-family:var(--mono);font-size:13px;line-height:2.1;
  color:var(--body)}
.flowline span{color:var(--muted)}
.flowline b{color:#fff}
.flowline .amt{color:var(--signal)}
/* ═══ THE PROMISE ═══ full-bleed signal. This is the 5%. ──────────────────── */
.promise{background:var(--signal);color:#000}
.promise h2,.promise b,.promise strong{color:#000}
.promise .lede{color:#000;max-width:52ch;opacity:.86}
.promise .big{font-size:clamp(30px, 5.4vw, clamp(64px, calc(64px + (100vw - 1400px) * 0.011), 84px));font-weight:800;letter-spacing:-0.04em;
  line-height:1.02;margin:0;color:#000;text-wrap:balance}
.promise-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(24px,4vw,60px);
  align-items:end;margin-top:34px}
/* ═══ PRICE TABLE ═══ */
/* wide content scrolls INSIDE its own box — the page body never moves sideways */
.tscroll{overflow-x:auto;-webkit-overflow-scrolling:touch;margin-top:30px}
.ptable{width:100%;min-width:440px;border-collapse:collapse;font-size:15px}
.ptable th{font-family:var(--mono);font-size:11px;letter-spacing:0.18em;
  text-transform:uppercase;color:var(--muted);font-weight:400;text-align:left;
  padding:0 14px 12px 0;border-bottom:1px solid var(--rule)}
.ptable td{padding:15px 14px 15px 0;border-bottom:1px solid var(--rule);
  vertical-align:top}
.ptable td.n,.ptable th.n{text-align:right;font-family:var(--mono);padding-right:22px}
.ptable td.n:last-child,.ptable th.n:last-child{padding-right:0}
.ptable th{white-space:nowrap}
.ptable tr.tot td{border-bottom:3px double var(--rule);border-top:1px solid var(--rule);
  color:#fff;font-weight:700}
.ptable .sub{display:block;color:var(--muted);font-size:13px;margin-top:3px}
/* ═══ CLOCKS ═══ horizontal stepper ───────────────────────────────────────── */
/* ═══════════════════════════════════════════════════════════════════════════
 * THE FLOW — four moments, and a pulse that only arrives at the last one.
 *
 * 🩸 THIS WAS `.clocks`: four dark rectangles in a row, one slightly lighter, holding the
 * most important sequence on the page. Operator: "this is just creepy ... add somehtign
 * similiar t compliace ina mch better visual".
 *
 * ⭐ THE COMPLIANCE WALL IS THE REFERENCE, and what works about it is that it NEVER STOPS.
 * A light travels its grid for ever, so the page is making its argument whenever anybody
 * happens to look — rather than once, on scroll, to whoever was watching.
 *
 * ⭐ HERE THE MOTION IS THE ARGUMENT. The pulse crosses 01, 02 and 03 without stopping and
 * LANDS on 04, because the first three are time passing and only the fourth is money. A
 * viewer who reads nothing still sees which one counts.
 *
 * ‼️ CSS ONLY. No script, so it runs with JavaScript blocked; and every step is plain
 * readable text if nothing animates at all.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* ‼️ NO TOP PADDING. The grid's own `background:var(--rule)` is what draws the hairlines
   BETWEEN cells, so padding above the first row shows that grey as a solid empty bar
   across the whole component — measured at 34px of dead strip. The pulse rides on the
   border itself and needs no room of its own. */
.flow{
  list-style:none;margin:clamp(30px,4vw,44px) 0 0;padding:0;
  display:grid;grid-template-columns:repeat(4,1fr);gap:1px;
  background:var(--rule);border:1px solid var(--rule);position:relative;
}
/* ‼️ THE PULSE IS A BACKGROUND, NOT AN ELEMENT. A moving element would need a width the
   grid does not know; a gradient the width of one column, translated across the whole
   rail, lands on each node by arithmetic rather than by a magic number. */
.flow::after{
  content:'';position:absolute;left:0;top:-2px;height:3px;width:25%;pointer-events:none;
  background:linear-gradient(90deg,transparent,var(--signal) 46%,#fff 50%,
    var(--signal) 54%,transparent);
  animation:flow-pulse 5.2s cubic-bezier(.42,0,.30,1) infinite;
  will-change:transform;
}
@keyframes flow-pulse{
  /* crosses the first three without pausing … */
  0%   { transform:translateX(0);    opacity:0 }
  6%   { opacity:1 }
  62%  { transform:translateX(300%); opacity:1 }
  /* … and stays on the fourth, which is the whole point */
  86%  { transform:translateX(300%); opacity:1 }
  100% { transform:translateX(300%); opacity:0 }
}
.flow-step{
  background:var(--ground);padding:clamp(20px,2.3vw,26px) clamp(16px,1.8vw,21px);
  position:relative;
}
.flow-n{
  display:block;font-family:var(--mono);font-size:11px;letter-spacing:.2em;
  color:var(--muted);
}
.flow-n em{
  display:block;margin-top:5px;font-style:normal;font-size:10px;letter-spacing:.16em;
  color:#4E4E4E;
}
.flow-step h3{margin:13px 0 6px;font-size:clamp(16px,1.5vw,18px);letter-spacing:-.015em}
.flow-step p{font-size:14px;margin:0;color:var(--muted);max-width:none}
/* the one that is money: lit, and it stays lit */
.flow-step.is-money{background:var(--raise)}
.flow-step.is-money .flow-n{color:var(--signal)}
.flow-step.is-money .flow-n em{color:var(--signal);opacity:.72}
.flow-step.is-money p{color:var(--body)}
/* ⭐ a standing mark on the money step, so the sequence still reads when the pulse is
   elsewhere in its loop or when motion is switched off entirely */
.flow-step.is-money::before{
  content:'';position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--signal);
}
@media (max-width:820px){.flow{grid-template-columns:repeat(2,1fr)}
/* ‼️ THE PULSE IS ARITHMETIC, so a different column count needs a different distance —
     two columns means it travels 100%, not 300%. Left unadjusted it would run off. */
.flow::after{width:50%;animation-name:flow-pulse-2}
@keyframes flow-pulse-2{
    0%{transform:translateX(0);opacity:0} 6%{opacity:1}
    62%{transform:translateX(100%);opacity:1}
    86%{transform:translateX(100%);opacity:1}
    100%{transform:translateX(100%);opacity:0}
  }}
@media (max-width:520px){.flow{grid-template-columns:1fr}
/* one column: the rail has nowhere to travel, so it simply is not there */
.flow::after{display:none}}
@media (prefers-reduced-motion:reduce){.flow::after{animation:none;transform:translateX(300%);opacity:1}}
/* ═══ GUARDS ═══ dense mono grid ──────────────────────────────────────────── */
/* 🩸 The hairlines used to come from the CONTAINER's background showing through
 * 1px gaps. With `auto-fill` the last row rarely fills, so the EMPTY TRACKS showed
 * that background too — a bare grey rectangle at the end of the grid that reads as
 * a rendering fault. Twenty-eight items over any column count will almost always
 * leave a gap, so this was visible at nearly every width.
 *
 * ⭐ The rule now belongs to each CELL, as a 1px ring. Adjacent rings meet inside
 * the 1px gap so the seam still reads as one hairline, and a track with no cell in
 * it draws nothing at all. */
/* 🩸 `auto-fill` RESOLVED TO THREE AND FIVE COLUMNS FOR TWENTY-EIGHT ITEMS, so the
   last row was short and the 1px grid gaps drew a hole in the wall. The wall being
   solid IS the argument of this section — a gap in it is the opposite of the claim.
   28 = 4 × 7, so the column count is chosen from its divisors and never guessed.
   tools/verify/gridgaps.mjs measures this at nine viewports. */
.guards{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:1px;background:transparent;border:1px solid var(--rule);margin-top:36px}
@media (max-width:1000px){.guards{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* 🩸 SAME HOLE AS `.wall`, ON THE OTHER PAGE THAT PRINTS THE SAME LIST. 29 is prime,
   so four columns leave three empty tracks on the last row and two leave one — and an
   empty grid cell on this background renders as a grey box, which the operator has
   already sent a screenshot of once. The list moved to /compliance and got the fix
   there; how-it-works keeps its own copy and did not. `gridgaps.mjs` found both.
   ‼️ LAST-CHILD, NOT :nth-child(29) — the count comes from INV.GUARD_CODES and the
   thirtieth guard would silently reopen the hole. */
.guards div:last-child{grid-column:1/-1}
.guards div{background:var(--ground);padding:12px 14px;font-family:var(--mono);
  font-size:11.5px;color:var(--muted);letter-spacing:0.01em;
  box-shadow:0 0 0 1px var(--rule)}
/* ⭐ On a phone `minmax(196px,1fr)` gives ONE column, so twenty-eight refusals
   became twenty-eight full-width rows — a list you scroll past instead of a wall
   you take in. The count IS the argument here, so keep two columns and shrink
   the type to fit the longest code (INV-DOWNSTREAM-COVERAGE, 24 characters). */
@media (max-width:560px){.guards{grid-template-columns:repeat(2,minmax(0,1fr))}
/* ‼️ THE TYPE SCALES, THE PADDING STEPS. 11.5px → 9px at exactly 560 was a 28% jump
     in twenty-nine chips at once — the loudest lurch on the site. The endpoints are the
     same as the breakpoint's were: 9px at 320 where the longest code
     (INV-DOWNSTREAM-COVERAGE, 24 characters) has to fit two to a row, 11.5px at 560
     where it meets the size outside this block. */
.guards div{padding:9px 8px;font-size:clamp(9px, 1.0417vw + 5.667px, 11.5px);
    letter-spacing:0;overflow-wrap:anywhere}}
/* ═══ STATUS ═══ */
/* 🩸 THREE CARDS IN auto-fit GAVE TWO COLUMNS at mid widths, leaving one alone on
   its own row looking like a card that failed to load. Three is prime: it is three
   across or one down, never two. */
.status{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(18px,2.6vw,30px);margin-top:36px}
@media (max-width:900px){.status{grid-template-columns:1fr}}
.scard{border:1px solid var(--rule);padding:24px;background:var(--raise)}
.scard .k{font-family:var(--mono);font-size:11px;letter-spacing:0.2em;
  text-transform:uppercase;color:var(--muted);margin-bottom:12px}
.scard p{font-size:14.5px;margin:0;color:var(--body)}
.scard p+p{margin-top:10px}
/* ═══ FOOTER ═══ */
footer{border-top:1px solid var(--rule);padding:52px 0 64px;color:var(--muted);
  font-size:14px}
.foot-grid{display:flex;flex-wrap:wrap;gap:28px;justify-content:space-between;
  align-items:flex-start}
footer a{color:var(--muted);text-decoration:none}
footer a:hover{color:#fff}
.foot-links{display:flex;gap:22px;flex-wrap:wrap}
/* ── responsive ──────────────────────────────────────────────────────────── */
@media (max-width:900px){.hero-grid,.promise-grid{grid-template-columns:1fr}
/* ‼️ THE SPLIT HAS TO COME BACK INSIDE THE GUTTER. `.stage` is margin-left:auto so
   * it hugs the right edge of its column — which is the whole page once the grid
   * collapses, so at 390px it ran off both sides and "THEY KEEP" sat over the bleed.
   * `.split-grid` on the home page has carried this rule since the phone mock landed;
   * how-it-works grew a stage on 2026-08-23 and needed the same one. */
/* ‼️ AND IT HAS TO LEAVE ROOM FOR ITS OWN TRANSFORM. The two slabs translate ±32px
   * on X in the settled state, so a stage sized to the full column runs 32px past the
   * gutter on both sides — which is what put "THEY KEEP" over the bleed at 390px. The
   * home page hides this with `.split-hero{overflow:hidden}`; clipping is the wrong
   * tool on a page whose hero has no such box, so the box is simply sized for what it
   * contains. */
.hero-grid .stage{margin-left:auto;margin-right:auto;max-width:min(430px,calc(100% - 76px))}
.dirs{grid-template-columns:1fr}}
@media (max-width:640px){.lrow{grid-template-columns:1fr auto;row-gap:2px}
.lrow .t{grid-column:1/-1}
/* The nav wrapped inside a fixed-height bar and the links stacked into two
     cramped lines. Give the header two honest rows instead of pretending it fits.
     ‼️ `header .wrap > nav`, not `nav` — the menu panel is a <nav> too, and these
     rules were written for a row of links in the bar. Unscoped, they put a border
     and a margin on the dropdown as well. */
header .wrap{height:auto;flex-direction:column;align-items:stretch;gap:0;padding-top:12px}
/* ‼️ THE WORDMARK STEPPED 21px → 19px AT EXACTLY 640. It is the first thing on every
     page, so the whole header appeared to twitch as the window crossed one pixel. The
     size is continuous now and lives outside this block; the rest of the rules here are
     LAYOUT — a column direction, a border, a gap — which may step, because a
     rearrangement is a decision and a letterform changing size is not. */
header .wrap > nav{width:100%;gap:0;justify-content:space-between;align-items:center;
      margin-top:11px;border-top:1px solid var(--rule);padding:9px 0 3px}
header .wrap > nav a{font-size:13.5px;white-space:nowrap}
header .wrap > nav .hide-sm{display:inline}
header .wrap > nav .cta.sm{padding:8px 13px}
/* ⭐ A HEADER WITH THE MENU IN IT STAYS ONE ROW. The two-row treatment above
     exists because seven links do not fit; behind a hamburger there is nothing to
     fit, so it keeps the bar it has at every other width. */
header.hdr-menu .wrap{height:62px;flex-direction:row;align-items:center;
      justify-content:space-between;gap:12px;padding-top:0}
header.hdr-menu .cta.sm{padding:9px 14px;font-size:13.5px}
.display{font-size:clamp(38px,10vw,60px)}}
/* A payment product does not need to move. Honor the setting completely. */
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE HERO — THE SPLIT, MADE PHYSICAL
 * The mark is the product: one payout divided between the people owed it. Here the
 * payout is one solid slab, the diagonal cuts it, and the halves separate with real
 * depth. No new shape is invented — the logo finally does the thing it depicts.
 * ‼️ NOT the gauge. The book is explicit: gauge is in-product only, never marketing.
 * ═══════════════════════════════════════════════════════════════════════════ */
.split-hero{padding:clamp(48px,7vw,96px) 0 clamp(52px,7vw,104px);overflow:hidden;
  perspective:1500px;perspective-origin:60% 45%}
.split-grid{display:grid;grid-template-columns:minmax(0,1.06fr) minmax(0,.94fr);
  gap:clamp(28px,5vw,72px);align-items:center}
/* ‼️ 2026-08-21 — THIS GRID HAD NO BREAKPOINT AT ALL. On a real iPhone the two
 * columns held at 390px, so the phone mockup sat ON TOP of the headline: "One
 * messa… Paid ev… month…" with the device covering the rest.
 *
 * ⭐ The layout sweep passed it. It looks for overflow, clipping and horizontal
 *   scroll — and `.split-hero{overflow:hidden}` meant the sweep treated the
 *   phone as "contained, therefore not lost". TWO ELEMENTS SITTING ON TOP OF
 *   EACH OTHER IS NONE OF THE THINGS IT MEASURED. → an overlap detector now runs.
 *
 * The phone STAYS on mobile — it is the argument, not decoration. It stacks
 * under the copy, centered, at a size that fits the narrowest phone we support. */
/* ‼️ a CLASS, not an inline style. This was `style="display:flex;justify-content:
   flex-end"` on the element, which no media query can override — inline wins. */
.hero-aside{display:flex;justify-content:flex-end}
@media (max-width:820px){.split-grid{grid-template-columns:1fr;gap:clamp(30px,7vw,44px)}
.hero-aside{justify-content:center}
.split-grid .stage{margin-left:auto;margin-right:auto}
/* ═══════════════════════════════════════════════════════════════════════════
     🩸 THIS WAS TWO RULES — `min(272px,72vw)` with a second breakpoint at 380px
     dropping to `min(238px,76vw)` — and the two do not meet. At 380px the first gives
     273px and the second gives 238px, so the mock GREW BY A SEVENTH between 380 and
     400, and `.phone` is `container-type:inline-size`, so every `cqw` size inside it
     jumped with it: the status bar, the names, the message bubbles, the amount.

     ⭐ ONE CONTINUOUS EXPRESSION. clamp(210px, 70vw, 272px) is 224px at 320, 266px at
     380, and reaches its 272px ceiling at 389 — the same sizes at both ends, moving
     the whole way. tools/verify/fluid.mjs found the step by walking the width 20px at
     a time; eleven sampled viewports cannot see it.
     ═══════════════════════════════════════════════════════════════════════════ */
/* ‼️ AND THE TWO RANGES HAVE TO MEET AT 820. Above it `.phone` is
   * `clamp(250px,27vw,304px)`, which is 250px at 820 — so a ceiling of 272 here dropped
   * the mock 8% as the window crossed one pixel, in the other direction from the step
   * this rule was written to remove. 250 is where the side-by-side layout starts, so
   * that is where the stacked one ends. */
.split-grid .phone{width:clamp(210px,70vw,250px)}}
/* ── THE SPLIT ────────────────────────────────────────────────────────────
   One payout arrives whole, then the cut opens and the two halves separate.
   The halves must BOTH read: an unlit slab on a black ground is invisible,
   and then the picture is one orange triangle instead of a division. */
.stage{position:relative;width:100%;max-width:430px;aspect-ratio:1;margin-left:auto;
  transform-style:preserve-3d;
  transform:rotateX(var(--rx,13deg)) rotateY(var(--ry,-15deg));
  transition:transform 600ms var(--ease-soft)}
.slab{position:absolute;inset:0;transition:transform var(--dur) var(--ease),
  box-shadow var(--dur) var(--ease)}
/* they keep the larger half — lifted off the ground so it is a SOLID, not a hole */
/* ‼️ Their half has to read as a SOLID. At #0C0C0C its lower edge dissolved into the
   #000 ground and the picture became one orange triangle beside a void — the split
   stopped being a split. Its darkest stop now sits clearly above the page. */
.slab-creator{clip-path:polygon(0 0,100% 0,0 100%);
  background:linear-gradient(148deg,#3A3A3A 0%,#2A2A2A 52%,#1E1E1E 100%);
  box-shadow:inset 1px 1px 0 rgba(255,255,255,.16)}
/* the agency's cut carries the signal, because it is the money that MOVES */
.slab-yours{clip-path:polygon(100% 0,100% 100%,0 100%);
  background:linear-gradient(320deg,var(--signal) 0%,#FF6A22 55%,#FF8038 100%);
  box-shadow:inset -1px -1px 0 rgba(0,0,0,.22)}
.stage.on .slab-creator{transform:translate3d(-32px,-32px,24px);
  box-shadow:inset 1px 1px 0 rgba(255,255,255,.16),-40px -34px 70px rgba(0,0,0,.9)}
.stage.on .slab-yours{transform:translate3d(32px,32px,72px);
  box-shadow:inset -1px -1px 0 rgba(0,0,0,.22),40px 34px 80px rgba(255,81,16,.20),
             30px 30px 66px rgba(0,0,0,.85)}
/* the cut itself — a hairline that draws down the diagonal as they part */
.cut-line{position:absolute;inset:0;transform:translateZ(66px);pointer-events:none;
  background:linear-gradient(to bottom right,transparent calc(50% - .8px),
    rgba(255,255,255,.55) 50%,transparent calc(50% + .8px));
  opacity:0;transition:opacity 420ms var(--ease-soft) 120ms}
.stage.on .cut-line{opacity:1}
/* ‼️ In a preserve-3d context the slabs sit at z=64px. A label at z=0 is BEHIND
   them — depth decides visibility here, not stacking order. */
.slab-tag{position:absolute;font-family:var(--mono);font-size:10px;letter-spacing:.2em;
  text-transform:uppercase;white-space:nowrap;transform:translateZ(96px);
  opacity:0;transition:opacity 460ms var(--ease-soft)}
.stage.on .slab-tag{opacity:1}
.stage.on .tag-creator{transition-delay:460ms}
.stage.on .tag-yours{transition-delay:600ms}
.tag-creator{top:9%;left:5%;color:#9C9C9C}
.tag-yours{bottom:11%;right:5%;color:rgba(0,0,0,.62)}
.slab-amt{font-family:var(--mono);font-weight:700;letter-spacing:-.02em;display:block;
  font-size:clamp(15px,1.6vw,21px);margin-top:5px}
.tag-creator .slab-amt{color:#fff}
.tag-yours .slab-amt{color:#000}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE CHASE — the inside of his phone.
 *
 * PATHOS: the timestamps run Monday to Sunday. A week of asking, "Delivered"
 *   under the last one, and no reply. The silence does the work, not the words.
 * ETHOS: the notification lands at 11:31 — one minute after "u there" at 11:30.
 *   They never answered. The money arrived anyway. That is the whole product.
 * LOGOS: the copy beside it explains why it can fire at all — against a deposit
 *   already observed, from a contract both parties signed.
 *
 * ⭐ SIGNAL DISCIPLINE: every bubble on this screen is gray. The ONLY orange
 *   thing on the phone is the money. Signal means money — nothing else.
 * ═══════════════════════════════════════════════════════════════════════════ */
.chase{background:var(--raise);border-top:1px solid var(--rule);border-bottom:1px solid var(--rule)}
/* 🩸 `align-items:start` TOP-ALIGNED A 300px COLUMN OF TEXT AGAINST A 660px PHONE,
   so the words stopped a third of the way down and the phone hung into 350px of
   dead space. Operator: "the phone isnt even with the text". Centered, the two
   columns read as one object. */
.chase-grid{display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:clamp(28px,5vw,72px);align-items:center;justify-items:stretch;margin-top:30px}
.chase-grid>*:last-child{justify-self:center}
/* ‼️ 2026-08-21 — the SECOND grid on this site with no breakpoint at all. At
 * 320px the copy ran under the phone. Same fix as .split-grid: the phone stays,
 * because it is the argument; it stacks under the words that set it up. */
@media (max-width:820px){.chase-grid{grid-template-columns:1fr;gap:clamp(28px,7vw,40px);justify-items:stretch}
/* same continuous expression as the hero's copy above, and for the same reason */
.chase-grid .phone{width:clamp(210px,70vw,250px);margin:0 auto}}
.phone{width:clamp(250px,27vw,304px);flex:none;container-type:inline-size}
/* the body: titanium rail, then the black bezel, then the screen */
.phone-body{position:relative;width:100%;aspect-ratio:393/852;
  border-radius:clamp(34px,4.4vw,52px);padding:clamp(7px,.9vw,10px);
  background:linear-gradient(155deg,#5A5A5E 0%,#2A2A2C 18%,#48484C 42%,#232325 68%,#4E4E52 100%);
  box-shadow:0 28px 70px rgba(0,0,0,.85),0 2px 0 rgba(255,255,255,.10) inset,
             0 0 0 1px rgba(0,0,0,.6)}
.phone-screen{position:relative;width:100%;height:100%;overflow:hidden;
  border-radius:clamp(28px,3.7vw,43px);background:#0C0C0E;
  display:flex;flex-direction:column}
/* ── status bar + Dynamic Island ─────────────────────────────────────────── */
.statusbar{position:relative;z-index:4;display:flex;justify-content:space-between;
  align-items:center;padding:clamp(9px,1.2vw,13px) clamp(15px,2vw,22px) 4px;
  font-size:clamp(10.5px,4.1cqw,12.5px);font-weight:700;color:#fff;letter-spacing:.01em}
.statusbar .sb-r{display:flex;align-items:center;gap:clamp(3px,1.3cqw,4px)}
.statusbar svg{display:block}
/* ‼️ 2026-08-21 — THE ISLAND WAS CUTTING INTO THE CELLULAR BARS on a real phone.
 * The island is a PERCENTAGE of the screen and the status icons were fixed pixel
 * widths from their SVG attributes, so every time the device got smaller the gap
 * between them closed. At the mobile phone width they touched.
 * ⭐ Scale the icons with the device too — `.phone` is a container, so cqw makes
 *   the whole status bar one system instead of two that only agree at one size. */
.statusbar .sb-r svg{width:auto;height:clamp(7.5px,3.6cqw,11px)}
.island{position:absolute;top:clamp(8px,1.1vw,12px);left:50%;transform:translateX(-50%);
  width:32%;height:clamp(20px,2.5vw,29px);background:#000;border-radius:99px;z-index:5;
  box-shadow:0 0 0 .5px rgba(255,255,255,.05)}
/* ── the conversation header ─────────────────────────────────────────────── */
.thread-head{display:flex;flex-direction:column;align-items:center;gap:4px;
  padding:clamp(10px,1.4vw,16px) 0 clamp(8px,1.1vw,12px);
  border-bottom:.5px solid #1F1F22;background:#141417}
.avatar{width:clamp(30px,3.6vw,42px);height:clamp(30px,3.6vw,42px);border-radius:50%;
  background:linear-gradient(150deg,#3A3A3C,#242426);color:#8E8E93;
  display:flex;align-items:center;justify-content:center;
  font-size:clamp(12px,5cqw,16px);font-weight:600}
.thread-head .nm{font-size:clamp(11px,4.3cqw,13px);color:#EBEBF5}
/* ── his messages. Outgoing, so they sit right. ──────────────────────────── */
.msgs{flex:1;display:flex;flex-direction:column;justify-content:flex-end;gap:clamp(5px,.7vw,8px);
  padding:0 clamp(10px,1.3vw,15px) clamp(12px,1.6vw,18px);
  transition:opacity 520ms var(--ease) 2900ms}
.bub{align-self:flex-end;max-width:78%;background:#242426;color:#EDEDEF;
  border-radius:17px 17px 4px 17px;padding:clamp(6px,.85vw,9px) clamp(9px,1.2vw,13px);
  font-size:clamp(11.5px,4.5cqw,13.5px);line-height:1.32;
  opacity:0;transform:translateY(9px) scale(.94);transform-origin:100% 100%}
.phone.on .bub{animation:bub-in 380ms var(--ease) forwards}
.phone.on .bub:nth-of-type(1){animation-delay:260ms}
.phone.on .bub:nth-of-type(2){animation-delay:640ms}
.phone.on .bub:nth-of-type(3){animation-delay:1020ms}
.phone.on .bub:nth-of-type(4){animation-delay:1400ms}
@keyframes bub-in{to{opacity:1;transform:none}}
/* ⭐ index's phone is deliberately one-sided — every bubble outgoing, then silence.
   refer's phone is a real exchange, so it needs the other person. Left, darker,
   tail mirrored. Nothing else changes; the chase page never uses this class. */
.bub.in{align-self:flex-start;background:#18181A;
  border-radius:17px 17px 17px 4px;transform-origin:0 100%}
.bub .t{display:block;font-family:var(--mono);font-size:clamp(9px,3.3cqw,10px);
  letter-spacing:.1em;color:#8E8E93;margin-top:3px}
/* "Delivered" and then nothing. That is the whole feeling. */
.delivered{align-self:flex-end;font-size:clamp(9px,3.4cqw,10.5px);color:#8E8E93;
  margin:1px 3px 0;opacity:0;transition:opacity 320ms linear 1820ms}
.phone.on .delivered{opacity:1}
/* ── the notification. The one orange thing on this screen. ──────────────── */
/* ‼️ top must clear the island (top 12px + height 29px at the widest) or the
   banner covers the clock and the phone stops reading as a phone */
.notif{position:absolute;z-index:6;top:clamp(31px,3.9vw,46px);
  left:clamp(7px,.9vw,10px);right:clamp(7px,.9vw,10px);
  display:flex;align-items:center;gap:clamp(7px,.95vw,10px);
  padding:clamp(8px,1.05vw,12px) clamp(9px,1.2vw,13px);
  border-radius:clamp(15px,1.9vw,22px);background:var(--signal);color:#000;
  box-shadow:0 14px 34px rgba(0,0,0,.72),0 0 0 .5px rgba(0,0,0,.25);
  transform:translateY(-165%);opacity:0;
  transition:transform 720ms cubic-bezier(.17,.89,.32,1.02) 2500ms,
             opacity 240ms linear 2500ms}
.phone.on .notif{transform:none;opacity:1}
.notif-ico{flex:none;width:clamp(20px,2.5vw,29px);height:clamp(20px,2.5vw,29px);
  border-radius:26%;background:#000;display:flex;align-items:center;justify-content:center}
.notif-ico svg{width:52%;height:52%;fill:var(--signal)}
.notif-b{display:block;min-width:0;flex:1}
.notif-hd{display:flex;justify-content:space-between;align-items:baseline;gap:6px;width:100%;
  font-size:clamp(9px,3.4cqw,10.5px);font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:rgba(0,0,0,.66)}
.notif-amt{display:block;font-family:var(--mono);font-weight:700;letter-spacing:-.025em;
  font-size:clamp(16.5px,6.6cqw,21px);line-height:1.12;margin-top:1px;
  font-variant-numeric:tabular-nums}
.notif-sub{display:block;font-size:clamp(9.5px,3.6cqw,11px);color:rgba(0,0,0,.72);
  line-height:1.25;margin-top:2px}
/* once the money is in, the begging stops mattering — dim the whole thread at
   once rather than each bubble, so the recede reads as a single gesture */
.phone.on .msgs{opacity:.34}
/* ⭐ but only where the thread IS the begging. On the referral page the thread is
   the introduction that earned the money — the headline is literally "One
   message" — so it recedes without becoming unreadable. */
.phone.on[data-thread=two-way] .msgs{opacity:.62}
@media (prefers-reduced-motion:reduce){.bub{opacity:1;transform:none;animation:none}
.delivered{opacity:1}
.notif{transform:none;opacity:1;transition:none}
.phone.on .msgs{opacity:.34;transition:none}}
/* ═══════════════════════════════════════════════════════════════════════════
 * PRICING — the fee, drawn to scale.
 *
 * Every payments company writes "just 0.9%" and every operator reads it as
 * "some amount I will resent later". So we stop writing the number and draw
 * it: the bar is the money that moved, the sliver is us. At 900px wide our
 * cut is 8 real pixels. Nothing persuades like an honest measurement.
 * ═══════════════════════════════════════════════════════════════════════════ */
.sliver{margin-top:30px}
.sliver-bar{position:relative;display:flex;height:78px;border:1px solid var(--rule);
  background:linear-gradient(180deg,#161616,#0D0D0D);overflow:hidden}
.sliver-moved{flex:1 1 auto;position:relative}
.sliver-us{flex:0 0 .9%;min-width:5px;background:var(--signal);position:relative;
  transform:scaleX(0);transform-origin:right;transition:transform 760ms var(--ease) 260ms}
.sliver.on .sliver-us{transform:none}
.sliver-scan{position:absolute;inset:0;background:linear-gradient(90deg,
  transparent,rgba(255,255,255,.055) 50%,transparent);transform:translateX(-101%);
  transition:transform 1100ms var(--ease) 120ms}
.sliver.on .sliver-scan{transform:translateX(101%)}
.sliver-legend{display:flex;justify-content:space-between;gap:16px;margin-top:12px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;
  color:var(--muted)}
.sliver-legend b{display:block;font-size:19px;letter-spacing:-.02em;margin-top:5px;
  color:#fff;text-transform:none}
.sliver-legend .us b{color:var(--signal)}
.sliver-legend .us{text-align:right}
.sliver-note{margin-top:14px;color:var(--muted);max-width:56ch;font-size:15px}
/* ── the calculator: their numbers, not ours ─────────────────────────────── */
.calc{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
  gap:clamp(26px,4.5vw,58px);align-items:start;margin-top:32px}
.calc-controls{display:flex;flex-direction:column;gap:26px}
.ctl label{display:flex;justify-content:space-between;align-items:baseline;gap:12px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;
  color:var(--muted);margin-bottom:11px}
.ctl label output{font-size:20px;letter-spacing:-.02em;color:#fff;text-transform:none;
  font-variant-numeric:tabular-nums}
.ctl input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:2px;
  background:var(--rule);outline:none;margin:0;cursor:pointer}
.ctl input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;
  width:15px;height:26px;background:var(--signal);border:0;cursor:grab;
  transition:transform 130ms var(--ease-soft)}
.ctl input[type=range]::-webkit-slider-thumb:active{cursor:grabbing;transform:scaleY(1.14)}
.ctl input[type=range]::-moz-range-thumb{width:15px;height:26px;background:var(--signal);
  border:0;border-radius:0;cursor:grab}
.ctl input[type=range]:focus-visible{outline:2px solid var(--signal);outline-offset:8px}
.seg{display:flex;border:1px solid var(--rule)}
.seg button{flex:1;background:transparent;border:0;color:var(--muted);cursor:pointer;
  font:inherit;font-size:14px;padding:12px 10px;transition:background 160ms,color 160ms}
.seg button[aria-pressed=true]{background:var(--signal);color:#000;font-weight:700}
.seg button:focus-visible{outline:2px solid var(--signal);outline-offset:2px}
.calc-out{border:1px solid var(--rule);background:var(--raise);padding:clamp(20px,3vw,32px)}
/* the split, drawn with the mark's own diagonal */
.calc-split{position:relative;height:104px;display:flex;overflow:hidden;
  border:1px solid var(--rule);background:#0D0D0D}
.calc-creator,.calc-yours{position:relative;transition:flex-basis 520ms var(--ease)}
.calc-creator{background:linear-gradient(180deg,#1E1E1E,#141414)}
.calc-yours{background:linear-gradient(180deg,var(--signal),#E8460C)}
.calc-split span{position:absolute;left:12px;bottom:9px;font-family:var(--mono);
  font-size:9.5px;letter-spacing:.17em;text-transform:uppercase;white-space:nowrap}
.calc-creator span{color:#9C9C9C}
.calc-yours span{color:rgba(0,0,0,.66)}
/* ‼️ 2026-08-21 — the label lived INSIDE its own segment, so on a phone the
 * 30% segment clipped it to "YOU — $36,0". A label sized independently of the
 * thing that contains it will always truncate at some split; the split is the
 * variable this whole control exists to change.
 * ⭐ On a phone the labels move BELOW the bar, anchored to their segment's outer
 *   edge. The proportions still read, and no split can cut a label off. */
@media (max-width:560px){.calc-split{overflow:visible;height:72px;margin-bottom:30px}
.calc-split span{top:calc(100% + 9px);bottom:auto;white-space:nowrap;font-size:11px}
.calc-creator span{left:0;color:var(--muted)}
.calc-yours span{left:auto;right:0;color:var(--signal)}}
.calc-rows{margin-top:22px}
.crow{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  padding:11px 0;border-bottom:1px solid var(--rule)}
.crow .k{color:var(--body);font-size:15px}
.crow .k em{font-style:normal;color:var(--muted);display:block;font-size:13px;margin-top:2px}
.crow .v{font-family:var(--mono);font-weight:700;font-size:17px;color:#fff;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.crow.tot{border-bottom:3px double var(--rule);border-top:1px solid var(--rule);margin-top:6px}
.crow.tot .v{color:var(--signal);font-size:clamp(20px,2.4vw,26px)}
.crow.sub .v,.crow.sub .k{color:var(--muted);font-weight:400}
.calc-eff{margin-top:18px;padding:15px 17px;background:var(--ground);
  border-left:3px solid var(--signal)}
.calc-eff .k{font-family:var(--mono);font-size:10.5px;letter-spacing:.19em;
  text-transform:uppercase;color:var(--muted)}
.calc-eff .v{font-family:var(--mono);font-weight:700;font-size:clamp(26px,3.4vw,38px);
  color:#fff;letter-spacing:-.02em;display:block;margin-top:6px;font-variant-numeric:tabular-nums}
.calc-eff p{margin:8px 0 0;font-size:14px;color:var(--muted);max-width:48ch}
@media (max-width:900px){.calc{grid-template-columns:1fr}
.sliver-bar{height:62px}}
@media (max-width:420px){.sliver-legend{font-size:9.5px;letter-spacing:.14em}
.sliver-legend b{font-size:16px}}
/* ── CREATORS: the inverse of the pricing sliver. Nothing is taken out. ──── */
.whole{margin-top:30px;max-width:520px}
.whole-bar{position:relative;height:96px;border:1px solid var(--rule);
  background:linear-gradient(180deg,#1C1C1C,#101010);overflow:hidden;display:flex}
.whole-bar .keep{flex:1;position:relative}
/* the slice that other products would take — drawn, then closed to nothing */
.whole-cut{position:absolute;top:0;bottom:0;right:0;width:18%;
  background:repeating-linear-gradient(135deg,rgba(255,81,16,.30) 0 6px,transparent 6px 12px);
  border-left:1px dashed rgba(255,81,16,.55);
  transform-origin:right;transition:transform 1000ms var(--ease) 1100ms,opacity 380ms linear 1850ms}
.whole.on .whole-cut{transform:scaleX(0);opacity:0}
.whole-lbl{position:absolute;left:14px;bottom:10px;font-family:var(--mono);font-size:10px;
  letter-spacing:.19em;text-transform:uppercase;color:#9C9C9C}
.whole-lbl b{display:block;font-size:22px;letter-spacing:-.02em;color:#fff;
  margin-top:5px;text-transform:none}
.whole-strike{position:absolute;right:14px;bottom:10px;text-align:right;
  font-family:var(--mono);font-size:10px;letter-spacing:.19em;text-transform:uppercase;
  color:var(--signal);opacity:1;transition:opacity 300ms linear 980ms}
/* the label leaves as the slice begins to close — holding it until after leaves a
   caption floating over a bar it no longer describes */
.whole.on .whole-strike{opacity:0}
.whole-after{margin-top:14px;font-size:15px;color:var(--muted);max-width:52ch;
  opacity:0;transform:translateY(8px);
  transition:opacity 460ms var(--ease) 2050ms,transform 460ms var(--ease) 2050ms}
.whole.on .whole-after{opacity:1;transform:none}
.whole-after b{color:#fff}
@media (prefers-reduced-motion:reduce){.whole-strike{opacity:0}
.whole-after{opacity:1;transform:none}
.sliver-us{transform:none}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE CREW — who this is actually for.
 *
 * The operator's own line: "we're here to put the money in the pockets of the
 * lads that work their asses off for these girls." That is the mission, and it
 * is the one place on this site where the argument is not economic. So the
 * design does the opposite of everywhere else — no figures, no ledger, just
 * the roles, named, arriving one at a time like a list being read out.
 * ═══════════════════════════════════════════════════════════════════════════ */
.crew{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(28px,5vw,72px);align-items:center;margin-top:34px}
.crew-list{display:flex;flex-direction:column;gap:0}
.crole{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;padding:15px 0;
  border-bottom:1px solid var(--rule);opacity:0;transform:translateY(10px);
  transition:opacity 560ms var(--ease),transform 560ms var(--ease)}
.crew.on .crole{opacity:1;transform:none}
/* ⭐ REVERSED, AND THAT IS THE SECTION. The list runs most-senior first, and the
   caption on the band above it is "paid last, and only after asking". So the
   bottom role arrives FIRST and the top one arrives LAST — reading order and
   payment order are opposites, which is the whole complaint being described.
   ‼️ Do not "tidy" these back into ascending order. */
.crew.on .crole:nth-child(4){transition-delay:80ms}
.crew.on .crole:nth-child(3){transition-delay:240ms}
.crew.on .crole:nth-child(2){transition-delay:400ms}
.crew.on .crole:nth-child(1){transition-delay:560ms}
.crole .who{font-size:clamp(18px,2.3vw,27px);font-weight:800;color:#fff;
  letter-spacing:-.03em;line-height:1.1;min-width:0;overflow-wrap:break-word}
.crole .did{color:var(--muted);font-size:14.5px;flex:1 1 210px;min-width:0}
.crew-said{align-self:start}
.crew-said p{max-width:44ch}
.crew-said .kicker{font-size:clamp(19px,2.2vw,25px);font-weight:800;color:#fff;
  letter-spacing:-.03em;line-height:1.18;margin:0 0 16px;text-wrap:balance}
.crew-said .last{border-left:3px solid var(--signal);padding:13px 0 13px 16px;
  margin-top:20px;color:var(--body)}
.crew-said .last b{color:#fff}
@media (max-width:900px){.crew{grid-template-columns:1fr}}
/* below 560px the role and what they did stop competing for one line */
@media (max-width:560px){.crole{display:block}
.crole .did{display:block;margin-top:5px}}
@media (prefers-reduced-motion:reduce){.crole{opacity:1;transform:none}}
/* ── A pricing table you have to drag sideways on a phone is a table people do
      not read. Below 560px the rows stop being a grid and become blocks: the
      line describes itself, the figures sit under it. No min-width, no scroller,
      nothing to discover by swiping. The <thead> is moved off-screen rather than
      display:none so a screen reader still announces the column names. ─────── */
@media (max-width:560px){.tscroll{overflow-x:visible}
.ptable{min-width:0;font-size:14.5px}
.ptable thead{position:absolute;width:1px;height:1px;overflow:hidden;
    clip-path:inset(50%);white-space:nowrap}
.ptable tr{display:block;border-bottom:1px solid var(--rule);padding:15px 0}
.ptable tbody tr:last-child{border-bottom:0}
.ptable td{display:block;border:0;padding:0;text-align:left}
.ptable td:first-child{margin-bottom:9px}
.ptable td.n,.ptable th.n{text-align:left;padding:0 20px 0 0;display:inline-block}
.ptable td.n:last-child{padding-right:0}
.ptable tr.tot{border-bottom:3px double var(--rule);border-top:1px solid var(--rule)}
.ptable .sub{margin-top:5px}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE LOG — the sequence as an artefact, not an illustration.
 *
 * Precision is the persuasion. A skeptical operator does not believe "fast" or
 * "automatic"; he believes 09:24:07. So the steps carry real clock times, the
 * amounts are exact, and the rail advances through them as they land.
 * ═══════════════════════════════════════════════════════════════════════════ */
.log{position:relative;margin-top:30px;padding-left:clamp(26px,3.2vw,40px)}
.log::before,.log::after{content:'';position:absolute;left:clamp(8px,1.1vw,13px);
  top:10px;bottom:26px;width:2px}
.log::before{background:var(--rule)}
.log::after{background:linear-gradient(180deg,var(--signal) 0%,var(--signal) 66%,rgba(255,81,16,.4) 100%);
  transform:scaleY(0);transform-origin:top;transition:transform 1700ms var(--ease) 140ms}
.log.on::after{transform:scaleY(1)}
.lrow2{position:relative;display:grid;
  grid-template-columns:clamp(74px,7.5vw,104px) minmax(0,1fr);
  gap:2px clamp(12px,1.6vw,22px);padding:0 0 clamp(16px,2vw,24px);
  opacity:0;transform:translateY(8px);
  transition:opacity 460ms var(--ease),transform 460ms var(--ease)}
.log.on .lrow2{opacity:1;transform:none}
.log.on .lrow2:nth-child(1){transition-delay:180ms}
.log.on .lrow2:nth-child(2){transition-delay:440ms}
.log.on .lrow2:nth-child(3){transition-delay:700ms}
.log.on .lrow2:nth-child(4){transition-delay:960ms}
.log.on .lrow2:nth-child(5){transition-delay:1220ms}
.lrow2 .dot{position:absolute;left:calc(clamp(8px,1.1vw,13px) - clamp(26px,3.2vw,40px) - 5px);
  top:4px;width:12px;height:12px;background:var(--ground);border:2px solid var(--rule);
  transform:rotate(45deg) scale(.5);opacity:.4;
  transition:transform 420ms var(--ease),opacity 420ms var(--ease),background 420ms,border-color 420ms}
.log.on .lrow2 .dot{transform:rotate(45deg) scale(1);opacity:1;
  background:var(--signal);border-color:var(--signal)}
.log.on .lrow2:nth-child(1) .dot{transition-delay:260ms}
.log.on .lrow2:nth-child(2) .dot{transition-delay:520ms}
.log.on .lrow2:nth-child(3) .dot{transition-delay:780ms}
.log.on .lrow2:nth-child(4) .dot{transition-delay:1040ms}
.log.on .lrow2:nth-child(5) .dot{transition-delay:1300ms}
.lg-t{font-family:var(--mono);font-size:clamp(11px,1.15vw,13px);color:var(--signal);
  font-variant-numeric:tabular-nums;letter-spacing:-.01em;white-space:nowrap}
.lg-k{font-family:var(--mono);font-size:clamp(9.5px,1vw,11px);letter-spacing:.19em;
  text-transform:uppercase;color:var(--muted)}
.lg-d{grid-column:2;max-width:62ch;font-size:15px;color:var(--body)}
.lg-d b{color:#fff}
.lg-d .amt{font-family:var(--mono);font-weight:700;color:#fff;font-variant-numeric:tabular-nums}
@media (max-width:620px){.lrow2{grid-template-columns:1fr;gap:3px}
.lg-k,.lg-d{grid-column:1}}
/* ── the failure path, drawn. The case he is looking for is the one you hide. ── */
.branch{margin-top:30px;border:1px solid var(--rule);background:var(--raise);
  padding:clamp(20px,2.6vw,30px);overflow-x:auto}
.branch svg{width:100%;height:auto;color:var(--body)}
.branch .branch-l{min-width:560px;max-width:760px}
/* ⭐ ONE diagram, two renderings. At 390px the landscape version was cut at
   "retried o…" with its whole right column off-screen behind a scrollbar. The
   portrait version stacks the same three outcomes, at the same type size, and
   needs no scrolling. Both are aria-hidden; the wrapper carries the one label. */
/* the role="img" wrapper that owns the single aria-label for both renderings */
.branch-figs{display:block}
.branch .branch-p{display:none;max-width:360px;margin:0 auto}
@media (max-width:620px){.branch{overflow-x:visible}
.branch .branch-l{display:none}
.branch .branch-p{display:block}}
.branch figcaption{margin:16px 0 0;color:var(--muted);font-size:14.5px;max-width:66ch}
.branch figure{margin:0}
/* 🩸 `auto-fit` GAVE FOUR COLUMNS FOR SIX CARDS, and the grid paints its own
   background through the gaps — so the two empty cells rendered as two blank
   boxes at the end of the row. Operator: "theres two random missing bxoes how
   the fuck do u think that look sgood". auto-fit is right when the count is
   unknown; here it is exactly six, so the column count is chosen to divide it. */
.rcodes{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:1px;margin-top:26px;background:var(--rule);border:1px solid var(--rule)}
@media (max-width:900px){.rcodes{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:560px){.rcodes{grid-template-columns:1fr}}
.rcode{background:var(--ground);padding:15px 16px}
.rcode .c{font-family:var(--mono);font-size:12.5px;font-weight:700;color:#fff;
  letter-spacing:.04em}
.rcode .w{display:block;color:var(--body);font-size:14px;margin-top:5px}
.rcode .a{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.17em;
  text-transform:uppercase;margin-top:9px;color:var(--muted)}
.rcode.retry .a{color:var(--signal)}
/* ── what it will not do. The negative claim, stated by us. ──────────────── */
.nots{display:grid;grid-template-columns:repeat(auto-fit,minmax(268px,1fr));
  gap:1px;margin-top:28px;background:var(--rule);border:1px solid var(--rule)}
.not{background:var(--ground);padding:clamp(17px,2.1vw,24px)}
.not .n{font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);display:block;margin-bottom:9px}
.not p{margin:0;font-size:15.5px;color:#fff;font-weight:700;line-height:1.34;
  letter-spacing:-.01em}
.not span{display:block;margin-top:8px;font-size:14px;color:var(--muted);font-weight:400;
  letter-spacing:0}
@media (prefers-reduced-motion:reduce){.log::after{transform:scaleY(1)}
.lrow2{opacity:1;transform:none}
.log .lrow2 .dot{transform:rotate(45deg);opacity:1;background:var(--signal);border-color:var(--signal)}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE REFERRAL PAGE — the ladder, computed rather than claimed.
 *
 * Every figure on this page is derived at runtime from the same constants the
 * billing engine uses. Nothing is typed in. A number on a marketing page that
 * was never executed is a claim, not a fact, and this is the page most likely
 * to be quoted back at us.
 * ═══════════════════════════════════════════════════════════════════════════ */
.rc-out{border:1px solid var(--rule);background:var(--raise);padding:clamp(20px,3vw,32px)}
.rc-hero{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;
  padding-bottom:16px;border-bottom:1px solid var(--rule)}
.rc-hero .n{font-family:var(--mono);font-weight:700;color:var(--signal);
  font-size:clamp(30px,5vw,54px);letter-spacing:-.03em;line-height:1;
  font-variant-numeric:tabular-nums}
.rc-hero .u{font-family:var(--mono);font-size:10.5px;letter-spacing:.19em;
  text-transform:uppercase;color:var(--muted)}
.rc-rows{margin-top:18px}
/* the working lands line by line, the way a bill is read down */
.js .rc-row{opacity:0;transform:translate3d(0,6px,0);
  transition:opacity 380ms var(--ease),transform 380ms var(--ease)}
.js .reveal.on .rc-row{opacity:1;transform:none}
.js .reveal.on .rc-row:nth-child(1){transition-delay:340ms}
.js .reveal.on .rc-row:nth-child(2){transition-delay:430ms}
.js .reveal.on .rc-row:nth-child(3){transition-delay:520ms}
.js .reveal.on .rc-row:nth-child(4){transition-delay:610ms}
.js .reveal.on .rc-row:nth-child(5){transition-delay:700ms}
@media (prefers-reduced-motion:reduce){.js .rc-row{opacity:1;transform:none}}
.rc-row{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  padding:10px 0;border-bottom:1px solid var(--rule)}
.rc-row .k{color:var(--body);font-size:14.5px}
.rc-row .k em{font-style:normal;display:block;color:var(--muted);font-size:12.5px;margin-top:2px}
.rc-row .v{font-family:var(--mono);font-weight:700;font-size:16px;color:#fff;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.rc-row.tot{border-bottom:3px double var(--rule);border-top:1px solid var(--rule);margin-top:6px}
.rc-row.tot .v{color:var(--signal);font-size:clamp(18px,2.2vw,24px)}
/* the ladder, drawn — each band a step, the one you are in lit */
.steps{display:flex;flex-direction:column;gap:1px;margin-top:28px;
  background:var(--rule);border:1px solid var(--rule)}
.step{display:grid;grid-template-columns:minmax(0,1.5fr) auto auto;gap:14px;
  align-items:baseline;background:var(--ground);padding:12px 15px;
  transition:background 220ms var(--ease-soft)}
.step.on{background:var(--signal)}
.step.on .sl,.step.on .sr{color:#000}
.step.on .sr{font-weight:700}
.sl{font-size:14.5px;color:var(--body)}
.sr{font-family:var(--mono);font-weight:700;font-size:15px;color:#fff;
  font-variant-numeric:tabular-nums;white-space:nowrap}
/* A SECOND money column. `.sc` is the label voice — uppercase, letter-spaced,
   muted — which is right for a caption and wrong for a figure: tracking pulls
   the digits apart and uppercasing does nothing to a number. Anything with a
   decimal point in it belongs in mono with tabular figures, secondary or not. */
.s2{font-family:var(--mono);font-size:13px;color:var(--muted);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.step.on .s2{color:#000;opacity:.68}
@media (max-width:900px){.step{grid-template-columns:1fr auto;row-gap:4px}
.s2{grid-column:1/-1;order:3}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE CARD, THE EYEBROW, THE COLUMNS — added 2026-08-20.
 *
 * 🩸 These six classes were being USED by refer.html and defined nowhere. The
 * referral page — the one an agency owner reads before they decide to introduce
 * anybody — shipped as unstyled paragraphs stacked in one column: no card, no
 * rule, no columns, the eyebrow rendering as ordinary body text. The markup was
 * right the whole time; the stylesheet had simply never been given them.
 *
 * ⭐ Nothing here invents a new visual idea. The card is the `.rc-out` surface
 * (raise on a hairline rule), the eyebrow is the `.label` voice at reading
 * weight, and the column gap is the same clamp the rest of the grid uses.
 * ═══════════════════════════════════════════════════════════════════════════ */
.box{border:1px solid var(--rule);background:var(--raise);
  padding:clamp(16px,2.2vw,24px)}
.box p:last-child{margin-bottom:0}
/* `raise` is the one card that sits ABOVE the page rather than in it — used once
   per screen, beside the headline, never twice. The shadow is the cut's dark
   half, so even the lift is derived. */
.box.raise{box-shadow:0 18px 48px -28px var(--shadow),0 1px 0 0 var(--rule)}
/* The label voice, but attached to a paragraph it introduces rather than a
   section. Slightly tighter tracking than `.label` because it sits on one line
   above body copy and has to hold its own width. */
.eyebrow{font-family:var(--mono);font-size:11px;letter-spacing:0.16em;
  text-transform:uppercase;color:var(--body);line-height:1.45}
.cols{display:grid;gap:clamp(14px,2vw,22px);margin-top:26px;
  grid-template-columns:1fr}
.cols>div{min-width:0}
/* Cards in a row must END level, whatever the copy does — a ragged bottom edge
   reads as a mistake in a system this square. */
.cols>div>.box{height:100%}
@media (min-width:760px){.cols.c2{grid-template-columns:repeat(2,minmax(0,1fr))}
.cols.c3{grid-template-columns:repeat(3,minmax(0,1fr))}}
/* Three columns need more room than two before they stop being readable; below
   this the third column's measure drops under about 30 characters. */
@media (min-width:760px) and (max-width:1000px){.cols.c3{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* ── THE REVEAL ────────────────────────────────────────────────────────────
   A section settles as it arrives: the same long decel as money landing, never
   a bounce. Guarded by `.js` on <html> so that with scripting off the content
   is simply present — a page whose text is invisible without JavaScript is a
   page that does not exist to a crawler or a reader with a blocked script. */
.js .reveal{opacity:0;transform:translate3d(0,18px,0);
  transition:opacity 620ms var(--ease-soft),transform 620ms var(--ease)}
.js .reveal.on{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){.js .reveal{opacity:1;transform:none}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE 320px PHONE — added 2026-08-20.
 *
 * 🩸 The nav carried five items and needed 330px of a 280px row, so every page
 * with a Refer link scrolled sideways 30px on an iPhone SE. It was invisible in
 * testing because `body{overflow-x:hidden}` clips the paint — but `html` still
 * scrolls, so the whole page slid under the thumb and the sticky header slid
 * with it.
 *
 * ⭐ `.hide-sm` existed and was only ever set to `display:inline`. It had no
 * rule that hid anything, on any page, at any width — a class named for a job
 * it never did. It hides here, which is the width it was named for.
 *
 * ⭐ Wrapping is the safety net, not the plan: hiding one link is not a promise
 * that four always fit, and a nav that overflows is worse than one that takes
 * two lines. Pricing stays one tap away in the footer of every page.
 * ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width:430px){nav{flex-wrap:wrap;column-gap:14px;row-gap:9px;justify-content:flex-start}
nav .hide-sm{display:none}
nav a{font-size:13px}
/* ‼️ THE PADDING MAY STEP; THE TYPE MAY NOT. A control getting tighter at the narrow
     end is a layout decision and is invisible as a jump. A font-size stepping 13 → 14
     at exactly 430px is the button's own label changing size as the window crosses one
     pixel, which is the thing "fluid at every width" means. The size is one continuous
     expression instead: 13px until 333, then rising to its 14px ceiling at 500. */
nav .cta.sm{padding:8px 12px;margin-left:auto}}
.cta.sm{font-size:clamp(13px, 0.6vw + 11.08px, 14px)}
/* ═══════════════════════════════════════════════════════════════════════════
 * SECTION MOTION — one idea per section, and the idea has to be the CONTENT.
 *
 * Everything here is guarded on `.js` for the same reason `.reveal` is: a rest
 * state of opacity:0 with nothing to switch it on is a blank page, not an
 * animation. With JavaScript off, or reduced motion on, every one of these is
 * simply already in its finished state.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* ── THE LEDGER OF BEING OWED ─────────────────────────────────────────────
   ⭐ On the home page these rows are DAY 01, 03, 06, 09, 14 — so the delays are
   the calendar itself, at roughly 55ms a day. The gaps widen because the wait
   widens; the rhythm of the animation is the argument the section is making.
   Only that instance carries data-rhythm="calendar". Elsewhere .lrow is a plain list and gets
   an even stagger, because inventing a calendar it does not have would be a lie
   told in timing. */
.js .lrow{opacity:0;transform:translate3d(0,8px,0);
  transition:opacity 420ms var(--ease),transform 420ms var(--ease)}
.js .ledger-rows.on .lrow{opacity:1;transform:none}
.js .ledger-rows.on .lrow:nth-child(1){transition-delay:70ms}
.js .ledger-rows.on .lrow:nth-child(2){transition-delay:180ms}
.js .ledger-rows.on .lrow:nth-child(3){transition-delay:290ms}
.js .ledger-rows.on .lrow:nth-child(4){transition-delay:400ms}
.js .ledger-rows.on .lrow:nth-child(5){transition-delay:510ms}
.js .ledger-rows.on .lrow:nth-child(6){transition-delay:620ms}
/* 🩸 THE LIST STOPPED AT SIX AND pricing.html HAS EIGHT. A child with no rule
   gets delay 0, so rows 7 and 8 arrived BEFORE row 1 — the sequence ran
   backwards at the end and read as a glitch rather than a defect. A stagger
   written as a fixed list silently inverts itself the day somebody adds a row,
   so there is now a catch-all: anything past the list lands last, never first. */
.js .ledger-rows.on .lrow:nth-child(7){transition-delay:730ms}
.js .ledger-rows.on .lrow:nth-child(8){transition-delay:840ms}
.js .ledger-rows.on .lrow:nth-child(9){transition-delay:950ms}
.js .ledger-rows.on .lrow:nth-child(10){transition-delay:1060ms}
.js .ledger-rows.on .lrow:nth-child(n+11){transition-delay:1140ms}
.js .ledger-rows.on[data-rhythm=calendar] .lrow:nth-child(1){transition-delay:55ms}
/* day 01 */
.js .ledger-rows.on[data-rhythm=calendar] .lrow:nth-child(2){transition-delay:165ms}
/* day 03 */
.js .ledger-rows.on[data-rhythm=calendar] .lrow:nth-child(3){transition-delay:330ms}
/* day 06 */
.js .ledger-rows.on[data-rhythm=calendar] .lrow:nth-child(4){transition-delay:495ms}
/* day 09 */
.js .ledger-rows.on[data-rhythm=calendar] .lrow:nth-child(5){transition-delay:770ms}
/* day 14 */
.js .ledger-rows.on[data-rhythm=calendar] .lrow:nth-child(6){transition-delay:1020ms}
/* the bill */
/* ── BOTH DIRECTIONS ──────────────────────────────────────────────────────
   A rail draws down each flow, and the amount that is YOURS lights when the
   rail reaches it. The two cards light on different lines because in one
   direction your cut is the second line and in the other it is the third —
   which is the whole point of the section. */
/* the pair arrives left then right — they are two answers to one question, so
   they should be read in order rather than taken in as a block. Every .dirs gets
   this; only the ones that contain a flow get the rail below. */
.js .dir{opacity:0;transform:translate3d(0,10px,0);
  transition:opacity 480ms var(--ease),transform 480ms var(--ease)}
.js .dirs.on .dir{opacity:1;transform:none}
.js .dirs.on .dir:nth-child(1){transition-delay:60ms}
.js .dirs.on .dir:nth-child(2){transition-delay:190ms}
/* 🩸 Same defect: creators.html puts FOUR cards in .dirs and only two had a
   delay, so cards 3 and 4 arrived first. */
.js .dirs.on .dir:nth-child(3){transition-delay:320ms}
.js .dirs.on .dir:nth-child(4){transition-delay:450ms}
.js .dirs.on .dir:nth-child(n+5){transition-delay:560ms}
.flowline{position:relative;padding-left:15px}
.flowline::before{content:'';position:absolute;left:0;top:5px;bottom:5px;width:1px;
  background:var(--rule)}
.js .flowline::before{transform:scaleY(0);transform-origin:top;
  transition:transform 760ms var(--ease) 140ms}
.js .dirs.on .flowline::before{transform:scaleY(1)}
.js .flowline .amt{color:var(--muted);transition:color 320ms var(--ease)}
.js .dirs.on .dir:nth-child(1) .flowline .amt{color:var(--signal);transition-delay:520ms}
.js .dirs.on .dir:nth-child(2) .flowline .amt{color:var(--signal);transition-delay:700ms}
/* ── THE PROMISE ──────────────────────────────────────────────────────────
   The one rule we will not bend, so the motion is a signature and nothing more:
   the statement arrives, then a rule is drawn under it. */
.js .promise .wrap>*{opacity:0;transform:translate3d(0,10px,0);
  transition:opacity 520ms var(--ease),transform 520ms var(--ease)}
.js .promise.on .wrap>*{opacity:1;transform:none}
.js .promise.on .wrap>*:nth-child(2){transition-delay:130ms}
.js .promise.on .wrap>*:nth-child(3){transition-delay:250ms}
.js .promise-grid>*{opacity:0;transform:translate3d(0,10px,0);
  transition:opacity 520ms var(--ease) 130ms,transform 520ms var(--ease) 130ms}
.js .promise.on .promise-grid>*{opacity:1;transform:none}
.js .promise.on .promise-grid>*:nth-child(2){transition-delay:280ms}
.promise .big{position:relative;padding-bottom:20px}
.promise .big::after{content:'';position:absolute;left:0;right:0;bottom:0;height:2px;
  background:#000;opacity:.24}
.js .promise .big::after{transform:scaleX(0);transform-origin:left;
  transition:transform 820ms var(--ease) 440ms}
.js .promise.on .big::after{transform:scaleX(1)}
/* ── THE PRICE TABLE ──────────────────────────────────────────────────────
   The last row is the sum of the ones above it, so it must land after them and
   be seen to. */
.js .ptable tbody tr{opacity:0;transform:translate3d(0,6px,0);
  transition:opacity 400ms var(--ease),transform 400ms var(--ease)}
.js .ptable.on tbody tr{opacity:1;transform:none}
.js .ptable.on tbody tr:nth-child(1){transition-delay:80ms}
.js .ptable.on tbody tr:nth-child(2){transition-delay:175ms}
.js .ptable.on tbody tr:nth-child(3){transition-delay:270ms}
.js .ptable.on tbody tr:nth-child(4){transition-delay:365ms}
.js .ptable.on tbody tr:nth-child(5){transition-delay:540ms}
.js .ptable.on tbody tr:nth-child(6){transition-delay:635ms}
/* ── THE FOUR CLOCKS ──────────────────────────────────────────────────────
   ⭐⭐ A line travels the whole row and each stage lights as it is passed —
   because these ARE four moments in sequence, and the section exists to say
   that only the last one is money. So the traveling line is neutral, and the
   only thing that ends up in signal is the stage where the credit lands. */
/* ── THE WALL OF REFUSALS ─────────────────────────────────────────────────
   Twenty-eight of them, arriving fast and in order. The point is the count, so
   the eye should have to keep up rather than take it in at once. */
.js .guards>div{opacity:0;transform:translate3d(0,6px,0);
  transition:opacity 300ms var(--ease),transform 300ms var(--ease)}
.js .guards.on>div{opacity:1;transform:none}
.js .guards.on>div:nth-child(1){transition-delay:20ms}
.js .guards.on>div:nth-child(2){transition-delay:44ms}
.js .guards.on>div:nth-child(3){transition-delay:68ms}
.js .guards.on>div:nth-child(4){transition-delay:92ms}
.js .guards.on>div:nth-child(5){transition-delay:116ms}
.js .guards.on>div:nth-child(6){transition-delay:140ms}
.js .guards.on>div:nth-child(7){transition-delay:164ms}
.js .guards.on>div:nth-child(8){transition-delay:188ms}
.js .guards.on>div:nth-child(9){transition-delay:212ms}
.js .guards.on>div:nth-child(10){transition-delay:236ms}
.js .guards.on>div:nth-child(11){transition-delay:260ms}
.js .guards.on>div:nth-child(12){transition-delay:284ms}
.js .guards.on>div:nth-child(13){transition-delay:308ms}
.js .guards.on>div:nth-child(14){transition-delay:332ms}
.js .guards.on>div:nth-child(15){transition-delay:356ms}
.js .guards.on>div:nth-child(16){transition-delay:380ms}
.js .guards.on>div:nth-child(17){transition-delay:404ms}
.js .guards.on>div:nth-child(18){transition-delay:428ms}
.js .guards.on>div:nth-child(19){transition-delay:452ms}
.js .guards.on>div:nth-child(20){transition-delay:476ms}
.js .guards.on>div:nth-child(21){transition-delay:500ms}
.js .guards.on>div:nth-child(22){transition-delay:524ms}
.js .guards.on>div:nth-child(23){transition-delay:548ms}
.js .guards.on>div:nth-child(24){transition-delay:572ms}
.js .guards.on>div:nth-child(25){transition-delay:596ms}
.js .guards.on>div:nth-child(26){transition-delay:620ms}
.js .guards.on>div:nth-child(27){transition-delay:644ms}
.js .guards.on>div:nth-child(28){transition-delay:668ms}
.js .guards.on>div:nth-child(29){transition-delay:692ms}
.js .guards.on>div:nth-child(30){transition-delay:716ms}
.js .guards.on>div:nth-child(31){transition-delay:740ms}
.js .guards.on>div:nth-child(32){transition-delay:764ms}
/* ── HONEST STATUS ────────────────────────────────────────────────────────
   Three cards, each underlining its own claim as it lands. */
.js .scard{opacity:0;transform:translate3d(0,10px,0);
  transition:opacity 460ms var(--ease),transform 460ms var(--ease)}
.js .status.on .scard{opacity:1;transform:none}
.js .status.on .scard:nth-child(1){transition-delay:70ms}
.js .status.on .scard:nth-child(2){transition-delay:200ms}
.js .status.on .scard:nth-child(3){transition-delay:330ms}
.scard .k{position:relative;padding-bottom:11px}
.scard .k::after{content:'';position:absolute;left:0;bottom:0;right:0;height:1px;
  background:var(--rule)}
.js .scard .k::after{transform:scaleX(0);transform-origin:left;
  transition:transform 560ms var(--ease)}
.js .status.on .scard:nth-child(1) .k::after{transform:scaleX(1);transition-delay:330ms}
.js .status.on .scard:nth-child(2) .k::after{transform:scaleX(1);transition-delay:460ms}
.js .status.on .scard:nth-child(3) .k::after{transform:scaleX(1);transition-delay:590ms}
@media (prefers-reduced-motion:reduce){.js .lrow,.js .promise-grid>*,.js .ptable tbody tr,.js .guards>div,.js .scard{
    opacity:1;transform:none}
.js .flowline::before,.js .clocks::before{transform:none}
.js .dir{opacity:1;transform:none}
.js .scard .k::after,.js .promise .big::after{transform:none}
.js .flowline .amt{color:var(--signal)}}
/* ── THE FAILURE DIAGRAM BUILDS ITSELF ────────────────────────────────────
   ⭐⭐ The section says "here it is, drawn" — so it draws. One branch at a time,
   in the order a reader needs them: what was submitted, what happens when it
   works, the single retry Nacha allows, and the terminal case. Taking the whole
   diagram in at once is the one way to read it that teaches nothing.

   ‼️ Reveal by GROUP rather than stroke-drawing the paths: an arrowhead marker
   paints at its vertex regardless of stroke-dashoffset, so a "drawn" line
   arrives with its arrowhead already waiting at the far end. */
.js .branch [data-branch]{opacity:0;transform:translate(-10px,0);
  transition:opacity 460ms var(--ease),transform 460ms var(--ease)}
.js .branch.on [data-branch]{opacity:1;transform:none}
.js .branch.on [data-branch="1"]{transition-delay:80ms}
.js .branch.on [data-branch="2"]{transition-delay:380ms}
.js .branch.on [data-branch="3"]{transition-delay:760ms}
.js .branch.on [data-branch="4"]{transition-delay:1080ms}
/* the codes underneath land after the picture that explains them */
.js .rcode{opacity:0;transform:translate3d(0,6px,0);
  transition:opacity 340ms var(--ease),transform 340ms var(--ease)}
.js .rcodes.on .rcode{opacity:1;transform:none}
/* ⭐ QUIET ON PURPOSE. A list of return codes is reference material — the reader
   is scanning for the one that happened to them, and eight things arriving in
   sequence makes that scan wait. They arrive together, softly. */
.js .rcodes.on .rcode{transition-delay:60ms}
/* ── THE REFUSALS, COUNTED OFF ────────────────────────────────────────────
   Six numbered rules. The number lands first and the rule follows it, because
   that is the order you read them in and the count is the point. */
.js .not{opacity:0;transform:translate3d(0,9px,0);
  transition:opacity 420ms var(--ease),transform 420ms var(--ease)}
.js .nots.on .not{opacity:1;transform:none}
.js .not .n{opacity:0;transition:opacity 300ms var(--ease)}
.js .nots.on .not .n{opacity:1}
/* the six refusals are a COUNT, so they still arrive in order — but at half the
   spacing, so the page reads rather than performs */
.js .nots.on .not:nth-child(1),.js .nots.on .not:nth-child(1) .n{transition-delay:40ms}
.js .nots.on .not:nth-child(2),.js .nots.on .not:nth-child(2) .n{transition-delay:100ms}
.js .nots.on .not:nth-child(3),.js .nots.on .not:nth-child(3) .n{transition-delay:160ms}
.js .nots.on .not:nth-child(4),.js .nots.on .not:nth-child(4) .n{transition-delay:220ms}
.js .nots.on .not:nth-child(5),.js .nots.on .not:nth-child(5) .n{transition-delay:280ms}
.js .nots.on .not:nth-child(6),.js .nots.on .not:nth-child(6) .n{transition-delay:340ms}
/* ── THE HEADLINE THAT IS TWO SENTENCES ───────────────────────────────────
   "We watch the bank." then, after a beat, "Nothing else." The pause IS the
   claim — the second sentence is a refusal, and a refusal delivered at the same
   moment as the offer does not read as one. */
.js .hero .col>*{opacity:0;transform:translate3d(0,12px,0);
  transition:opacity 560ms var(--ease),transform 560ms var(--ease)}
.js .hero.on .col>*{opacity:1;transform:none}
.js .hero.on .col>*:nth-child(2){transition-delay:120ms}
.js .hero.on .col>*:nth-child(3){transition-delay:420ms}
.js .display .beat{display:inline-block;opacity:0;transform:translate3d(0,10px,0);
  transition:opacity 520ms var(--ease),transform 520ms var(--ease)}
.js .hero.on .display .beat{opacity:1;transform:none}
.js .hero.on .display .beat:nth-of-type(2){transition-delay:460ms}
/* ── THE LAST THING ON THE PAGE ───────────────────────────────────────────
   A rule is drawn above the actions, the way a page is ruled off, and then the
   two choices arrive in the order they should be considered. */
.hero-actions{position:relative}
.js .hero-actions>*{opacity:0;transform:translate3d(0,8px,0);
  transition:opacity 440ms var(--ease),transform 440ms var(--ease)}
.js .hero-actions.on>*{opacity:1;transform:none}
.js .hero-actions.on>*:nth-child(1){transition-delay:220ms}
.js .hero-actions.on>*:nth-child(2){transition-delay:340ms}
@media (prefers-reduced-motion:reduce){.js .branch [data-branch],.js .rcode,.js .not,.js .not .n,
  .js .hero .col>*,.js .display .beat,.js .hero-actions>*,
  .js .promise .wrap>*,.js .promise-grid>*{opacity:1;transform:none}}
/* ── WHAT WE DO NOT ASK FOR ───────────────────────────────────────────────
 * The how-it-works hero used to be a 20ch column on a 1440px screen with two
 * thirds of the row empty, so the display type rendered at 41px and the lede ran
 * four words to a line. It needed a right-hand half, and the section's own
 * subject supplies one.
 *
 * ⛔ DELIBERATELY NOT A MOCK OF ANYONE'S SIGN-IN PAGE. No logo, no domain, no
 *   borrowed chrome — a convincing copy of a real company's login screen is a
 *   phishing template whatever it is captioned. It is a plain list of the three
 *   credentials, labeled as what OTHER tools ask for, and each one is struck
 *   out as it arrives. The strike is the whole idea.
 * ═══════════════════════════════════════════════════════════════════════════ */
.nolog{border:1px solid var(--rule);background:var(--raise);
  padding:clamp(16px,2vw,22px);max-width:400px;margin-left:auto}
.nolog-hd{font-family:var(--mono);font-size:10px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted);padding-bottom:13px;
  border-bottom:1px solid var(--rule)}
.nolog-f{position:relative;display:flex;justify-content:space-between;
  align-items:baseline;gap:14px;padding:15px 0;border-bottom:1px solid var(--rule)}
.nolog-f .fl{font-size:14px;color:var(--body)}
.nolog-f .fv{font-family:var(--mono);font-size:13px;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* the strike — drawn, left to right, one field at a time */
.nolog-f::after{content:'';position:absolute;left:0;right:0;top:50%;height:1.5px;
  background:var(--body)}
.js .nolog-f::after{transform:scaleX(0);transform-origin:left;
  transition:transform 460ms var(--ease)}
.js .nolog.on .nolog-f::after{transform:scaleX(1)}
.js .nolog.on .nolog-f:nth-child(2)::after{transition-delay:520ms}
.js .nolog.on .nolog-f:nth-child(3)::after{transition-delay:760ms}
.js .nolog.on .nolog-f:nth-child(4)::after{transition-delay:1000ms}
.nolog-ft{padding-top:15px;font-size:13.5px;color:var(--muted)}
.js .nolog-ft{opacity:0;transition:opacity 420ms var(--ease) 1320ms}
.js .nolog.on .nolog-ft{opacity:1}
@media (prefers-reduced-motion:reduce){.js .nolog-f::after{transform:none}
.js .nolog-ft{opacity:1}}
@media (max-width:860px){.nolog{margin-left:0;max-width:none}}
/* ── TWO BILLS, NEVER ONE ─────────────────────────────────────────────────
   The section says a second charge arrives from a second company. So there are
   two bars, to scale against each other, and the rule between them never
   closes — the gap IS the claim. Ours is signal because it is our fee; theirs
   is neutral because we do not collect it and cannot discount it.

   ⭐ The widths come from the page's own SPREAD and RAIL constants at runtime.
   Hardcoding them here would be a third copy of the price. */
.bills{margin-top:30px;max-width:640px}
.bills-track{display:flex;height:clamp(58px,7vw,74px);border:1px solid var(--rule);
  background:var(--raise);overflow:hidden}
.bill{display:flex;flex-direction:column;justify-content:center;gap:3px;
  padding:0 clamp(10px,1.6vw,16px);min-width:0;overflow:hidden;
  transition:transform 780ms var(--ease) 120ms,opacity 520ms var(--ease) 120ms}
.bill span{font-family:var(--mono);font-size:clamp(9px,1.2vw,10.5px);letter-spacing:.17em;
  text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bill b{font-family:var(--mono);font-size:clamp(14px,1.9vw,19px);letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.bill.ours{background:var(--signal);color:#000}
.bill.ours span{color:rgba(0,0,0,.66)}
.bill.ours b{color:#000}
/* ‼️ the divider is a real gap, not a border — a border would read as one bar
   ruled in two, which is the opposite of what this says */
.bill.theirs{background:linear-gradient(180deg,#1E1E1E,#141414);color:var(--body);
  margin-left:2px;box-shadow:-2px 0 0 var(--ground)}
.bill.theirs span{color:var(--muted)}
.bill.theirs b{color:#fff}
/* they arrive from opposite ends and stop short of each other */
.js .bill.ours{transform:translateX(-101%)}
.js .bill.theirs{transform:translateX(101%)}
.js .bills.on .bill{transform:none}
.bills-dim{display:flex;align-items:center;gap:10px;margin-top:9px;
  font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted)}
.bills-dim i{flex:1;height:1px;background:var(--rule)}
.js .bills-dim{opacity:0;transition:opacity 420ms var(--ease) 820ms}
.js .bills.on .bills-dim{opacity:1}
.bills-cap{margin-top:14px;color:var(--muted);font-size:14.5px;max-width:60ch}
@media (prefers-reduced-motion:reduce){.js .bill{transform:none}
.js .bills-dim{opacity:1}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE FIELD — the background is never still.
 *
 * ⭐ The brand's one motion is a diagonal, up and to the right: a payout arriving
 *   and being divided. Everything on this site is a single instance of that
 *   gesture. The field is the same gesture at the scale of the whole page and at
 *   a speed you notice only if you look — slow bands of warmth drifting along the
 *   diagonal, never repeating on a visible cycle, never competing with a figure.
 *
 * ‼️ IT IS A CANVAS, NOT A GIF AND NOT A VIDEO. A looping video background is
 *   megabytes, decodes on the main thread, and gives a phone a hot battery for a
 *   texture nobody consciously sees. This is a few hundred lines of gradient on a
 *   half-resolution canvas at 30fps, and it stops itself when the tab is hidden.
 *
 * ‼️ FIXED, BEHIND EVERYTHING, AND UNCLICKABLE. `position:fixed` + `z-index:-1` +
 *   `pointer-events:none`, and every section paints its own ground on top so the
 *   field only ever shows through where a section is transparent.
 * ═══════════════════════════════════════════════════════════════════════════ */
#field{position:fixed;inset:0;width:100%;height:100%;z-index:-1;pointer-events:none;
  display:block;background:var(--ground)}
/* without JS, or with reduced motion, it is simply the ground it sits on */
@media (prefers-reduced-motion:reduce){#field{display:none}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE BANDS — full-bleed imagery between sections.
 *
 * ⭐ Each band is the idea of the section it follows, rendered as an object, so
 *   scrolling the page is scrolling through one argument rather than past a
 *   gallery. Generated at 4K and served at 2400px, which is retina-sharp on a
 *   16" display without being a video-sized download.
 *
 * ‼️ ASPECT-RATIO BOX + object-fit, not a background-image. A background needs an
 *   explicit height at every breakpoint and gets one of them wrong; a real <img>
 *   in an aspect box is correct at every width, is fetched with the right
 *   priority, and carries alt text.
 * ‼️ `loading="lazy"` on everything below the fold and `decoding="async"` — a
 *   band is atmosphere and must never delay the sentence next to it.
 *
 * ⭐ The band FADES INTO the ground at both edges rather than butting against it
 *   with a hard line. A photographic rectangle stopping dead on a black page
 *   reads as a stock image dropped in; a band that dissolves reads as part of the
 *   page. Done with a mask so it costs nothing and needs no second element.
 */
/* 🩸🩸 THIS PAINTED AN OPAQUE BLACK RECTANGLE OVER THE PAGE. `body` is transparent
   so the ember field shows through everything — except a band, which filled itself
   with solid --ground. The photograph's mask faded correctly into BLACK, and that
   black sat on a warm moving background, so both edges of every band rendered as a
   hard horizontal line. Operator sent a photo of exactly that seam.
   ⭐ Transparent, the mask dissolves into whatever is actually behind the band, and
   the top and bottom of every photo join the section above and below with nothing
   between them. */
/* ⭐⭐ THE BAND PAINTS ITS OWN NEIGHBORS. Transparent was not enough: some
   sections carry --raise (#0B0B0B) and some carry nothing, so a photo fading to
   the page ground met a section that was 11 units lighter and drew a line across
   the screen. Solid --ground had the same problem in the other direction.
   The only correct answer is that the top of a band must BE whatever is above it
   and the bottom must BE whatever is below it — which varies per band and cannot
   be written as a constant. `--above` / `--below` are set from the real computed
   background of the actual siblings, so the join is seamless for every
   combination that exists now and every one added later. */
/* 🩸 THE FADE WAS THERE AND TOO SHORT TO SEE. 9% of a 21:9 strip is about 30px,
   which reads as a hard edge with a slight softening — operator: "the photo
   underneath it dosent fade at all". The mask was present the whole time, so a
   test asserting "a mask exists" passed while the thing it exists FOR did not
   happen. Widened to 18%, with a longer tail, so the photograph genuinely
   dissolves into the page instead of being cropped into it. */
/* a caption is optional and sits INSIDE the band, bottom-left, where it cannot
   be mistaken for the next section's copy */
/* ═══════════════════════════════════════════════════════════════════════════
 * THE NETTING — two movements becoming one. Added 2026-08-21.
 *
 * The idea this animates is the one sentence people do not believe: you are not
 * paid separately, your commission comes off the bill and only the DIFFERENCE
 * moves. So two opposing bars slide toward each other and collapse into a single
 * one — the picture is the arithmetic.
 *
 * ⭐ It settles on the NET, which is the number that actually leaves an account.
 * ═══════════════════════════════════════════════════════════════════════════ */
.net{--row:clamp(44px,5.4vw,54px);margin-top:26px;max-width:520px}
/* ⭐ the bill bar COVERS the commission label when it rises, which is the point —
   but it also leaves a settled state that cannot explain itself. So the total is
   dimensioned above the track the way a drawing is, and never moves. */
.net-scale{font-family:var(--mono);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);text-align:center}
.net-scale i{display:block;height:6px;margin-top:5px;
  border:1px solid var(--rule);border-bottom:0}
.net-track{position:relative;height:calc(var(--row) * 2);border:1px solid var(--rule);
  background:var(--raise);overflow:hidden;transition:height 760ms var(--ease) 120ms}
.net-bar{position:absolute;left:0;height:var(--row);display:flex;align-items:center;
  padding:0 13px;font-family:var(--mono);font-size:clamp(10.5px,1.35vw,12.5px);
  letter-spacing:.04em;white-space:nowrap;transition:transform 760ms var(--ease) 120ms}
/* the commission is the whole width, because it is the bigger number */
.net-earn{top:0;width:100%;background:var(--signal);color:#000}
/* the bill is 684.00/883.20 of it — TO SCALE — and it ends exactly at the cut */
.net-owe{top:var(--row);width:77.45%;background:#241109;color:var(--body);
  justify-content:flex-end}
/* on: the bill rises INTO the commission and cancels its own length of it. what is
   still lit on the right is the difference, and it was never drawn, only left over. */
.net.on .net-track{height:var(--row)}
.net.on .net-owe{transform:translateY(-100%)}
.net-rem{position:absolute;top:0;height:var(--row);left:77.45%;right:0;
  display:flex;align-items:center;justify-content:center;font-family:var(--mono);
  font-size:10px;letter-spacing:.16em;text-transform:uppercase;font-weight:600;
  color:#000;opacity:0;transition:opacity 320ms var(--ease) 700ms}
.net.on .net-rem{opacity:1}
.net-sum{display:flex;align-items:baseline;gap:12px;margin-top:14px;opacity:0;
  transform:translateY(4px);
  transition:opacity 420ms var(--ease) 840ms,transform 420ms var(--ease) 840ms}
.net.on .net-sum{opacity:1;transform:none}
.net-sum .n{font-family:var(--mono);font-variant-numeric:tabular-nums;font-weight:600;
  font-size:clamp(26px,3.6vw,38px);letter-spacing:-.03em;color:var(--signal);line-height:1}
.net-sum .u{font-family:var(--mono);font-size:10px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted)}
.net-cap{margin-top:12px;color:var(--muted);font-size:14px;max-width:52ch}
@media (prefers-reduced-motion:reduce){.net .net-track{height:var(--row)}
.net .net-owe{transform:translateY(-100%)}
.net .net-rem,.net .net-sum{opacity:1;transform:none}}
/* ── THE STAGGER ──────────────────────────────────────────────────────────
   Rows arriving one after another rather than all at once. Used where a list is
   really a sequence — more introductions, more money — so the eye reads it as
   accumulation instead of a table. */
.steps .step{opacity:0;transform:translateY(6px);
  transition:opacity 420ms var(--ease),transform 420ms var(--ease),background 220ms var(--ease-soft)}
.steps.on .step{opacity:1;transform:none}
.steps.on .step:nth-child(1){transition-delay:60ms}
.steps.on .step:nth-child(2){transition-delay:200ms}
.steps.on .step:nth-child(3){transition-delay:340ms}
.steps.on .step:nth-child(4){transition-delay:480ms}
.steps.on .step:nth-child(5){transition-delay:620ms}
@media (prefers-reduced-motion:reduce){.steps .step{opacity:1;transform:none}}
/* ── COLUMNS ARRIVE IN ORDER ──────────────────────────────────────────────
   Three cards landing at once is a table. Landing one after another is a list
   being read out, which is what a set of short rules actually is.

   ‼️ Guarded on `.js` exactly like `.reveal` — a rest state of opacity:0 with no
   observer to undo it is a blank page, not an animation. */
.js .cols>*{opacity:0;transform:translate3d(0,10px,0);
  transition:opacity 460ms var(--ease),transform 460ms var(--ease)}
.js .cols.on>*{opacity:1;transform:none}
.js .cols.on>*:nth-child(1){transition-delay:60ms}
.js .cols.on>*:nth-child(2){transition-delay:170ms}
.js .cols.on>*:nth-child(3){transition-delay:280ms}
.js .cols.on>*:nth-child(4){transition-delay:390ms}
@media (prefers-reduced-motion:reduce){.js .cols>*{opacity:1;transform:none}}
/* ── THE REFUSAL ──────────────────────────────────────────────────────────
   A rule drawn through the card as it arrives. Used on "what this does not do",
   where the content is a list of things that will not happen — the mark is the
   meaning, not decoration. */
/* 🩸 THE CODE DREW A TOP BORDER. The comment above says the rule is drawn THROUGH
   the card and that "the mark is the meaning" — and `top:0` puts it along the edge,
   where it reads as a divider like every other rule on the site. A refusal that
   looks like a divider communicates nothing. It now strikes the LABEL, which is
   the thing being refused, and is drawn left to right as the card lands. */
.nope{position:relative}
.nope .eyebrow{position:relative;display:inline-block}
.nope .eyebrow::after{content:'';position:absolute;left:0;right:0;top:calc(50% - 1px);
  height:2px;background:var(--signal);transform:scaleX(0);transform-origin:left;
  transition:transform 620ms var(--ease)}
.nope.on .eyebrow::after,.reveal.on .nope .eyebrow::after{transform:scaleX(1)}
@media (prefers-reduced-motion:reduce){.nope .eyebrow::after{transition:none;transform:scaleX(1)}}
.cols.on>*:nth-child(1) .nope::after{transition-delay:420ms}
.cols.on>*:nth-child(2) .nope::after{transition-delay:530ms}
.cols.on>*:nth-child(3) .nope::after{transition-delay:640ms}
@media (prefers-reduced-motion:reduce){.nope::after{transform:scaleX(1)}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE REFERRAL CHOOSER — three cards where five sliders used to be.
 *
 * 🩸 The calculator asked for the referred agency's payouts, creators and split,
 * AND the referrer's own creators and payouts: five drags before it said
 * anything, and a number nobody could trace back to what they had set. Operator:
 * "the referral tab doesn't make any sense … people are going to get confused
 * reading the numbers."
 *
 * ⭐ One decision, three concrete shapes, and the arithmetic printed underneath.
 * A slider is the right control for exploring a RANGE; this was never a range
 * question, it was "roughly how big are they".
 * ═══════════════════════════════════════════════════════════════════════════ */
.pick{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:26px 0 22px}
.pcard{display:flex;flex-direction:column;gap:6px;text-align:left;cursor:pointer;
  padding:16px 16px 18px;background:var(--raise);color:inherit;font:inherit;
  border:1px solid var(--rule);border-left:2px solid var(--rule);
  transition:border-color .22s ease,background .22s ease,transform .22s ease}
.pcard:hover{border-color:#4a4a4a;transform:translateY(-2px)}
.pcard .pk{font-family:var(--mono);font-size:9.5px;letter-spacing:.19em;
  text-transform:uppercase;color:var(--muted)}
.pcard .pn{font-size:15px;color:var(--body)}
.pcard .pn b{font-family:var(--mono);font-size:26px;font-weight:700;color:#fff;
  letter-spacing:-.02em;margin-right:5px}
.pcard .pv{font-size:13px;color:var(--muted);line-height:1.35}
/* ⭐ The selected card carries the signal on its EDGE, not as a fill — the fill is
   reserved for money, and a chooser is not money. */
.pcard.sel{border-left-color:var(--signal);background:#151515;border-color:#3a3a3a}
.pcard.sel .pk{color:var(--signal)}
.pcard:focus-visible{outline:2px solid var(--signal);outline-offset:3px}
@media (max-width:720px){.pick{grid-template-columns:1fr;gap:8px}
.pcard{flex-direction:row;align-items:baseline;flex-wrap:wrap;gap:4px 10px;padding:13px 14px}
.pcard .pk{width:100%}
.pcard .pn b{font-size:21px}}
/* the fork. height is fixed so the layout cannot shift when it starts drawing */
.flowcv{display:block;width:100%;height:118px;margin:20px 0 6px}
@media (max-width:560px){.flowcv{height:92px}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE BANDS, ONE AT A TIME.
 *
 * 🩸 All seventeen shared a single treatment — fade in, scale 1.06 → 1 — while
 * each carries a CAPTION making a specific claim. "Four texts, and then
 * nothing", "Only the last one is money", "None of them has an override". The
 * picture said one thing and the motion said "a photograph is arriving".
 *
 * ⭐ Each band now EXECUTES ITS OWN CAPTION. The rule throughout: the motion has
 * to be the argument. If you could swap two of these without noticing, one of
 * them is decoration and should be deleted rather than kept.
 *
 * Every one degrades to its finished state under prefers-reduced-motion, at the
 * bottom of the block, in one place — a per-band opt-out is a per-band thing to
 * forget.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* the shared fade stays as the DEFAULT for any band added later and not yet
   given a treatment of its own — a new band should look considered, not broken */
/* ── 1 · "Four texts, and then nothing" — DELETED 2026-08-22 ─────────────────
   Operator: "and this photo gotta go". The wake reveal goes with it — the veil was
   anchored on a beam that is no longer on the page, and a keyframe with no element
   is the thing somebody later copies onto a band it was never written for. */
/* ── 2 · "Whichever way it already flows" — DELETED 2026-08-22 ───────────────
   Operator, with a screenshot: "get rid of this photo".

   The reveal is gone with it rather than left behind: `band-both` opened the frame
   from both edges to meet in the middle, which was the caption made physical, and
   it has nothing left to open. A keyframe with no element is the kind of thing that
   gets copied onto the next band by somebody who assumes it was general. The
   argument it carried still stands on the page below it, drawn as two routes that
   end on the same two figures — which was always the stronger version of it. */
/* ── 3 · "Only the last one is money" ────────────────────────────────────────
   Four steps left to right, and the fourth is held twice as long as the others.
   Three of them are just time passing; the last one is the money, and it gets
   the time. Done with the frame, not with a glow painted over it. */
/* ═══════════════════════════════════════════════════════════════════════════
 * 🩸 FOUR BAND REVEALS JUDDERED, AND THE OPERATOR SAW EVERY ONE OF THEM.
 *
 * "the way it annimated when u scroll by it on desktop is disgusting" · "the way this
 * photo annimated in an its dry version is so digusting"
 *
 * Measured against the one band the operator singled out as RIGHT — `band-whole`, on
 * /creators — the difference is not the idea, it is the CURVE:
 *
 *     band-whole    one continuous ease from the center outward          ✅ liked
 *     band-clocks   `steps(1, end)` — four discrete jumps                ✖ juddered
 *     band-blocked  reveals to 34%, HOLDS for 7%, continues              ✖ stuttered
 *     band-ends     two mid-reveal holds, at 62% and at 30%              ✖ stuttered
 *     band-diff     nothing moves at all for the first 46% of it         ✖ dead pause
 *
 * ‼️ EACH HOLD WAS DELIBERATE AND EACH ONE WAS WRONG. The comments above them explain
 * the intent — "three uneven steps, the last one late", "in the frame for a beat" — and
 * the intent is sound as a story. As motion on a photograph you are scrolling past, a
 * frame that stops moving reads as a stalled image load, not as emphasis.
 *
 * ⭐ EVERY ONE IS NOW A SINGLE CONTINUOUS SWEEP, and the idea is carried by WHERE the
 * ease decelerates rather than by stopping. The photograph still arrives the way the
 * section is about; it just never appears to be broken while doing it.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* the ease carries the idea now: it crosses the first three blocks quickly and settles
   onto the last one, which is the only one that is money. */
/* ── 4 · "None of them has an override" ──────────────────────────────────────
   🩸 This was a white streak traveling the wall and stopping. It was a bar
   sliding over a photograph, which is the thing that was cut everywhere else.
   It opens to a hard stop instead: linear in, no ease-out, and it never reaches
   the far edge on the first attempt. Blocked, not arriving. */
/* ‼️ NOT `linear`. A constant-speed wipe reads as a progress bar; every other band on
   this site decelerates, and consistency across seventeen photographs is the thing that
   makes them feel like one publication. */
/* ── 5 · "Paid last, and only after asking" ─────────────────────────────────
   🩸 I DREW THE CABLE IN CSS. A 1px line and a radial gradient laid over the
   photograph, which is the exact thing every other overlay on this site was
   deleted for. Operator: "u just put a fucking line on th ephoto remake it
   perfectly".

   ⭐ The flex and the bulb are IN THE PHOTOGRAPH now — regenerated image-to-image
   from the original master so the stools, the floor, the camera and the grading
   are identical and only the lamp is new. The only thing left in CSS is the ROOM
   ANSWERING THE LIGHT: a shallow, uneven brightness drift, because a bulb that
   never varies is a sticker and a bulb that flickers is a fault. Uneven steps on
   purpose — an even cycle reads as a loop, and a loop stops being a room. */
/* ── 6 · "Nine tenths of one percent, to scale" ──────────────────────────────
   99.1% of the frame opens at once. The last 0.9% takes nearly a second, so the
   eye measures the sliver in TIME as well as in width. */
/* ═══════════════════════════════════════════════════════════════════════════
 * 🩸 `img:not(.wet)` ON EVERY ONE OF THESE, AND THE `:not` IS THE WHOLE FIX.
 *
 * These rules exist to stop the shared 900ms fade softening a bespoke clip-path reveal.
 * They were written as `.js #band-x img` — which matches BOTH images in the figure, the
 * dry one AND the wet hover layer. `.js #band-x img` is (1,1,1); the wet layer's own
 * `transition:--wr 1400ms` is (0,3,0). So on ten of the site's photographs the wet reveal
 * had `transition:none` and snapped in a single frame, while the two bands with no
 * bespoke treatment crossfaded correctly — which is exactly what the operator saw and
 * reported as "i dont want them to change to the wet version instantly".
 *
 * ‼️ THE ANIMATION RULES NEED IT TOO. A four-step clip-path chase applied to the wet layer
 * makes the water arrive in four steps as well, which is not the effect either.
 *
 * ⭐ `tools/verify/wetchk.mjs` hovers every band in a browser and fails if `--wr` is not
 * in the computed transition list. A static reading of this file cannot see the loss.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* ‼️ A BAND WITH ITS OWN TREATMENT OPTS OUT OF THE SHARED FADE. Otherwise the
   900ms opacity ramp runs UNDERNEATH the bespoke reveal and softens it into the
   same arriving-photograph it was written to replace — the four-step chase reads
   as one blur, and the 0.9% sliver is invisible because the frame is still fading
   up while it crawls. The clip is the reveal; there is nothing left for a fade to
   do. Listed explicitly, so a band added later still gets the sensible default. */
/* ═══════════════════════════════════════════════════════════════════════════
 * 🩸🩸 BANDS 7–17: EVERY DRAWN OVERLAY WAS DELETED.
 *
 * I had painted light seams, traveling rails, probe streaks and three-ended
 * diagrams ON TOP of the photographs. Operator, with screenshots: "why the fuck
 * are there random organe lines throgh this photo" · "just two bars down the
 * center of the phoo u can do so much fucking better".
 *
 * He is right, and the reason is worth writing down. These photographs are lit,
 * graded and finished. A 2px CSS line laid over one does not join it — it sits
 * on it, at a different sharpness, with no relationship to the light already in
 * the frame. It reads as a browser drawing on a picture, which is exactly the
 * "AI slop" tell the whole site is being kept clear of. A hard-edged gradient
 * bar over a photograph is the visual equivalent of explaining the joke.
 *
 * ⭐ THE RULE NOW: motion on a band comes from the PHOTOGRAPH — how it is
 * revealed, masked, or lit — never from geometry drawn over it. Two exceptions
 * survive, and both are lights that already exist in the scene rather than marks
 * on top of it: the pendant lamp on `site-crew`, which is a light source with a
 * pool that falls on the room and modulates the room's own brightness; and the
 * beam on `site-chase`, which CONTINUES a shaft of light that is in the
 * photograph, and does so OUTSIDE the frame, in the section above.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* ── 7 · "Two bills, from two companies" ─────────────────────────────────────
   Two halves arrive from opposite edges and meet. Nothing is drawn; the picture
   itself comes in as two things. */
/* ── 8 · "One account, read-only" ────────────────────────────────────────────
   The vault opens a crack and stops. A reveal that halts before it finishes is
   the caption, and it costs nothing drawn. */
/* ── 9 · "Timestamped, to the second" ────────────────────────────────────────
   Revealed left to right at a CONSTANT rate. A clock does not ease out, and the
   linear timing is the whole idea. */
/* ‼️ NOT `linear`. Two bands used it and both read as a progress bar crossing the frame
   at a constant speed; every other reveal on this site decelerates. */
/* ── 10 · "Every way it can end" ─────────────────────────────────────────────
   Three uneven steps, the last one late — outcomes that do not arrive together. */
/* ── 11 · "Things that do not move" ──────────────────────────────────────────
   Two pixels of settle and a dead stop. No overshoot; anything springy here
   contradicts the caption. */
/* ── 12 · "No way through any of them" ───────────────────────────────────────
   It opens partway three times, each attempt reaching less far, and settles at
   the last. Repetition getting you less, done with the frame itself. */
/* ── 13 · "Through, never held" ──────────────────────────────────────────────
   Revealed at a constant rate that never slows in the middle. The absence of a
   pause IS the claim — INV-NO-CUSTODY, without drawing a dot on the picture. */
/* ── 14 · "Nothing taken out of it" ──────────────────────────────────────────
   Opens from the center outward and closes seamlessly at both edges: nothing is
   removed on the way. */
/* ── 15 · "Nothing here asks you for anything" ───────────────────────────────
   It simply arrives, unhurried, with no hunting and no hesitation — which is
   what a page that asks you for nothing should feel like. */
/* ── 16 · "One introduction, paying again and again" ─────────────────────────
   The single beam is present from the first frame and the FAN opens out of it.
   One becomes many, in the only order that means anything. */
/* ── 17 · "Only the difference moves" ────────────────────────────────────────
   Both edges close in and stop, leaving only the middle — the difference — in
   the frame for a beat before the rest arrives. */
/* ‼️ ONE PLACE, FOR ALL SEVENTEEN. A per-band reduced-motion opt-out is a
   per-band thing to forget, and the failure mode is a band stuck mid-reveal —
   permanently cropped, for exactly the people who asked for less movement. */
/* ═══════════════════════════════════════════════════════════════════════════
 * OWED — two tracks, and only one of them moves.
 *
 * 🩸 This section used to make its point in six long rows and a closing
 * paragraph: "everyone is owed money, it moves by hand, on trust, late." The
 * point is a COMPARISON — fourteen days pass and the number does not change —
 * and a comparison written as prose makes the reader do the work of drawing it.
 *
 * ⭐ So it is drawn. Two rails, identical length, stacked. The top one fills.
 * The bottom one never does, and it is not broken — it is the argument. The
 * amount sits on the empty rail the whole time, so the eye reads "time moved,
 * money didn't" before it reads a single word.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* ⭐ THE PADDING IS STRUCTURAL, not taste. The day numbers sit ABOVE the rail and
   the labels BELOW it, both absolutely positioned — without room reserved here
   they are clipped by the section and the numbers simply vanish. */
/* ═══════════════════════════════════════════════════════════════════════════
 * TWO ACCOUNTS, AND THE MONEY IS IN THE WRONG ONE.
 *
 * 🩸 THIRD VERSION OF THIS SECTION. First it was two rails and you had to notice an
 * ABSENCE. Then a fortnight timeline with a figure under it — and the two disagreed:
 * "they send some of it" on day six, "still owed the whole amount" underneath.
 * Operator: "this makes no sense". He was right; it was two ideas fighting.
 *
 * ⭐ NOTHING TO DECODE NOW. Two boxes. The orange block is inside the left one. It is
 * still there on day fourteen. A reader does not have to hold anything in their head,
 * and there is no arithmetic to check against a caption.
 *
 * ‼️ THE ORANGE BLOCK NEVER MOVES, and that is the section. Only the day counts up.
 * An edit that animates the money across the gap deletes the meaning.
 * ═══════════════════════════════════════════════════════════════════════════ */
.acc{margin-top:clamp(28px,4vw,48px);display:grid;gap:clamp(12px,1.6vw,20px);
  grid-template-columns:1fr auto 1fr;align-items:stretch}
.acc-box{border:1px solid var(--rule);background:var(--ground);
  padding:clamp(18px,2.4vw,28px);display:flex;flex-direction:column;gap:10px;min-width:0}
.acc-k{font-family:var(--mono);font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted)}
.acc-n{font-family:var(--mono);font-weight:700;font-variant-numeric:tabular-nums;
  font-size:clamp(26px,4.2vw,46px);line-height:1;letter-spacing:-.035em;color:#fff}
.acc-zero{color:#3A3A3A}
/* the two boxes read differently at a glance: theirs holds something, yours does not */
.acc-theirs{border-color:#2A2A2A}
.acc-you{background:linear-gradient(180deg,#070707,#000)}
.acc-dayn{font-variant-numeric:tabular-nums}
.acc-empty{color:var(--muted);font-size:14px;margin-top:auto}
/* the payout, split. The orange part is the agency's, and it is on the wrong side. */
/* ‼️ THE LABELS SIT UNDER THE BAR, ALWAYS. Inside the blocks they were clipped at
   every width below 1280 — the orange block is 30% of half a column, and "Yours —
   $3,000.00" is 107px of text. It was cut to 52px on a phone, which is the one figure
   this whole section exists to show. A label that has to fit inside a proportional
   block is a label that disappears exactly when the proportion is small. */
.acc-bar{position:relative;display:flex;height:clamp(52px,7vw,74px);margin-top:auto;
  margin-bottom:28px;border:1px solid var(--rule)}
.acc-bar i{display:block;font-style:normal;min-width:0}
.acc-bar span{position:absolute;top:100%;margin-top:8px;white-space:nowrap;
  font-family:var(--mono);font-size:clamp(9.5px,1.15vw,11.5px);letter-spacing:.06em}
.acc-yours{flex:0 0 var(--w,30%);background:var(--signal);
  box-shadow:0 0 40px rgba(255,81,16,.28)}
.acc-yours span{left:0;color:var(--signal);font-weight:700}
.acc-rest{flex:1 1 auto;background:linear-gradient(180deg,#161616,#101010)}
.acc-rest span{right:0;color:var(--muted)}
/* the space between the two accounts, where nothing happens */
.acc-gap{display:flex;align-items:center;justify-content:center;padding:0 clamp(2px,1vw,10px)}
.acc-day{font-family:var(--mono);font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);white-space:nowrap}
.acc-day b{color:#fff;font-size:15px;margin-left:6px;font-variant-numeric:tabular-nums}
.acc-say{margin-top:clamp(16px,2.2vw,24px);max-width:46ch;font-size:clamp(15px,1.9vw,18px)}
.acc-say b{color:#fff}
/* ⭐ the day counts up when the section arrives; the money does not react to it. */
.js .acc-yours{transform:scaleX(.001);transform-origin:left center;
  transition:transform 900ms cubic-bezier(.16,.86,.3,1) 120ms}
.js .acc.on .acc-yours{transform:none}
@media (max-width:720px){.acc{grid-template-columns:1fr;gap:10px}
.acc-gap{padding:4px 0}}
/* 🩸 AT 320px THE ORANGE BLOCK IS 30% OF THE SCREEN and "Yours — $3,000.00" does not
   fit inside it — it was clipped to 52px of a 107px label, which is the one number
   the section exists to show. The labels move BELOW the bar instead of shrinking:
   the block stays a block, and the words stay words. */
/* ═══════════════════════════════════════════════════════════════════════════
 * ROUTE — the same two numbers, reached from opposite directions.
 *
 * 🩸 This section used to argue "we handle both directions" in two paragraphs
 * and eight lines of ledger. The claim is narrow and visual: the money enters at
 * a different bank, takes a different hop, and ARRIVES AT THE SAME TWO FIGURES.
 *
 * ⭐ So both routes are drawn and both end on $2,520.00 and $5,880.00. The
 * second hop runs left-to-right in one card and right-to-left in the other —
 * that reversal is the only difference between them, which is exactly the point.
 * ═══════════════════════════════════════════════════════════════════════════ */
.route{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(20px,3.4vw,44px);margin-top:38px}
.route-card{border:1px solid var(--rule);background:var(--raise);
  padding:clamp(20px,2.6vw,30px) clamp(18px,2.4vw,28px) clamp(22px,2.8vw,30px);
  position:relative;overflow:hidden}
/* the signal only ever marks the card you are being paid INTO */
.route-card::before{content:'';position:absolute;left:0;top:0;bottom:0;width:2px;
  background:var(--signal);transform:scaleY(0);transform-origin:top center;
  transition:transform 700ms var(--ease)}
.route.on .route-card::before{transform:scaleY(1)}
.route.on .route-card.rev::before{transition-delay:180ms}
.route-h{font-size:clamp(15px,2vw,18px);color:var(--muted);letter-spacing:-.01em}
.route-h b{color:#fff}
.route-rail{position:relative;height:64px;margin:24px 0 6px}
.route-node{position:absolute;top:14px;display:flex;flex-direction:column;
  align-items:center;gap:8px;transform:translateX(-50%)}
.route-node.n1{left:8%}
.route-node.n2{left:50%}
.route-node.n3{left:92%}
.route-node i{width:10px;height:10px;border-radius:50%;background:#2C2C2C;
  box-shadow:0 0 0 4px var(--raise);transition:background 380ms var(--ease),box-shadow 380ms var(--ease)}
.route-node em{font-style:normal;font-family:var(--mono);font-size:9.5px;letter-spacing:.14em;
  text-transform:uppercase;color:#6E6257;white-space:nowrap;transition:color 380ms var(--ease)}
.route.on .route-node i{background:var(--signal);box-shadow:0 0 0 4px var(--raise),0 0 14px rgba(255,81,16,.75)}
.route.on .route-node em{color:var(--body)}
.route.on .route-node.n2 i,.route.on .route-node.n2 em{transition-delay:520ms}
.route.on .route-node.n3 i,.route.on .route-node.n3 em{transition-delay:1180ms}
/* ═══════════════════════════════════════════════════════════════════════════
 * 🩸 TWO CARDS THAT ENDED UP IDENTICAL, AND AN ANIMATION THAT RAN ONCE.
 *
 * Operator: "this visual could b better". Three separate reasons it was not:
 *
 *   1. `route-run` and `route-run-rev` WERE THE SAME KEYFRAMES, character for character,
 *      under a comment saying the reversal "is the entire section".
 *
 *      ‼️ AND THE COMMENT WAS WRONG, WHICH IS WHY THEY WERE THE SAME. Checked against
 *      `authtext.commissionAgreement` clause 3, which is the contract both cards draw:
 *        collect  — OnlyFans pays the CREATOR; the agency's share moves FROM their account
 *        disburse — OnlyFans pays the AGENCY; the creator's share moves TO their account
 *      Read left to right as the nodes are labeled, BOTH routes run the same way: source,
 *      then the bank it lands in, then the party who is owed. Nothing reverses. Making the
 *      second card animate backwards — which is what a first pass at this did — draws a
 *      money movement that does not happen.
 *   2. BOTH HOPS WERE THE SAME ORANGE. The first hop is OnlyFans paying somebody, which
 *      happens with or without us; the second is the one WE make. Drawing them identically
 *      throws away the only thing this section is trying to say.
 *   3. IT PLAYED ONCE AND STOPPED. After the reveal, both cards are two static rails with
 *      the same two figures under them — which is precisely what the operator was looking
 *      at when they said it could be better.
 *
 * ⭐ NOW: hop one is a dim rule (already true), hop two is the signal and carries a pulse
 * that LOOPS FOR EVER, and the pulse runs the direction the money actually goes — right in
 * the first card, LEFT in the second, because in the second the money starts in your bank
 * and travels out to them.
 * ═══════════════════════════════════════════════════════════════════════════ */
.route-hop{position:absolute;top:18px;height:2px;background:#242424;overflow:hidden}
.route-hop.h1{left:8%;width:42%}
.route-hop.h2{left:50%;width:42%}
/* ‼️ HOP ONE IS NOT OURS, so it is not the accent. It is drawn as a settled fact. */
.route-hop.h1{background:#2E2E2E}
/* hop two is the transfer OnlyFlow makes, and it is the only orange on the rail */
.route-hop.h2::after{content:'';position:absolute;inset:0;background:var(--signal);
  box-shadow:0 0 10px rgba(255,81,16,.55);
  transform:scaleX(0);transform-origin:left center;transition:transform 620ms var(--ease)}
.route.on .route-hop.h2::after{transform:scaleX(1);transition-delay:420ms}
/* ‼️ NO `transform-origin:right` HERE ANY MORE. It mirrored a hop that does not mirror. */
/* ⭐ AND IT KEEPS MOVING. A pulse inside hop two, looping, so the claim is being made
   whenever anybody looks rather than once to whoever happened to be scrolling. The same
   reasoning as the compliance wall, which the operator named as the thing that works. */
/* ⭐ THE END OF THE ROUTE IS THE POINT. In the first card the money arrives with YOU; in
   the second it arrives with THEM. That is the whole difference, so the last node is lit
   and its label is the one in white. */
.route-node.n3 i{box-shadow:0 0 0 4px rgba(255,81,16,.16)}
.route.on .route-node.n3 em{color:#fff;font-weight:700}
.route-hop.h2 i{position:absolute;top:0;bottom:0;width:38%;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.95),transparent);
  animation:hop-pulse 2.6s linear infinite;pointer-events:none}
@keyframes hop-pulse{
  0%{transform:translateX(-100%);opacity:0} 12%{opacity:1}
  70%{opacity:1} 100%{transform:translateX(300%);opacity:0}
}
/* ‼️ IT STARTS INVISIBLE AND THE ANIMATION IS WHAT BRINGS IT BACK — which a
   stylesheet reader cannot see, so the "starts invisible, nothing restores it"
   guard flagged it, correctly. Reduced motion REMOVES the dot rather than leaving
   it at opacity 0, because a decoration nobody can see should not still be in the
   accessibility tree. */
.route-dot{position:absolute;top:14px;left:8%;width:10px;height:10px;border-radius:50%;
  background:#fff;box-shadow:0 0 16px rgba(255,255,255,.9);opacity:0;transform:translateX(-50%)}
.route.on .route-dot{opacity:1}
.route.on .route-dot{animation:route-run 1900ms var(--ease) both}
/* ‼️ ONE ANIMATION, BOTH CARDS, because both routes run the same way. `route-run-rev` is
   gone rather than kept as an identical twin of `route-run`. */
@keyframes route-run{
  0%{left:8%;opacity:0} 8%{opacity:1}
  40%{left:50%} 88%{left:92%;opacity:1} 100%{left:92%;opacity:0}
}
.route-out{display:flex;gap:26px;flex-wrap:wrap;border-top:1px solid var(--rule);padding-top:16px}
.route-out span{display:flex;flex-direction:column;gap:3px}
.route-out em{font-style:normal;font-family:var(--mono);font-size:9.5px;letter-spacing:.15em;
  text-transform:uppercase;color:#6E6257}
.route-out b{font-family:var(--mono);font-size:clamp(15px,2vw,19px);color:#fff;letter-spacing:-.02em}
.route-out b.amt{color:var(--signal);text-shadow:0 0 22px rgba(255,81,16,.45)}
@media (max-width:780px){.route{grid-template-columns:1fr}}
@media (prefers-reduced-motion:reduce){.route-card::before,.route-node i,.route-node em,.route-hop::after{transition:none}
.route-dot,.route.on .route-dot,.route.on .route-card.rev .route-dot{animation:none;display:none}}
/* ‼️ EVERY BAND OVERLAY FADES WITH THE PHOTO IT SITS ON.
 *
 * 🩸 The bespoke reveals paint into `.band::before` / `::after` — light seams,
 * probes, the darkening on "only the difference moves". Those pseudo-elements
 * are `inset:0`, so they ran to the band's exact top and bottom edge while the
 * PHOTOGRAPH underneath them faded out over 20%. The result is a hard step at
 * the boundary in whatever columns the overlay darkens or lights: the photo
 * dissolved and the effect on top of it did not.
 *
 * ⭐ One rule, matching the image mask exactly, rather than a fade added by hand
 * to each of the nine overlays — nine copies of a gradient is nine chances to
 * mistype one, and the one you mistype is the one nobody looks at.
 * Verified by tools/verify/bandseam.mjs, which reads real pixels. */
/* ═══════════════════════════════════════════════════════════════════════════
 * WET ON HOVER — the same photograph, soaked.
 *
 * ⭐ The pair is generated image-to-image from the 4K master, so the camera,
 * the objects and the light are IDENTICAL and only the water differs. That is
 * the entire effect: two renders of the same subject would read as two
 * pictures, and the illusion depends on nothing else moving.
 *
 * ⭐ It crossfades rather than cuts, and slowly — a fast swap reads as a broken
 * image loading. Both layers carry the band's mask, so the wet frame dissolves
 * into the page exactly like the dry one and no seam appears on hover.
 *
 * ‼️ HOVER ONLY WHERE HOVER EXISTS. On a touch screen `:hover` sticks after a
 * tap and the photo silently stays wet forever, which looks like a bug. Gated on
 * a real pointer.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════════════════════
 * FATES — how far the money gets, drawn as distance.
 *
 * 🩸 This was a boxes-and-arrows state diagram, in two SVGs, one landscape and
 * one portrait. Operator: "the visual representation above is so fucking ugly u
 * can maek this so much better". A flowchart is a thing you have to READ before
 * it says anything, and the reader's real question is much simpler than the
 * state machine: if this goes wrong, where does my money stop?
 *
 * ⭐ So the answer is the LENGTH OF THE LANE. Accepted runs the full width. A
 * retryable return gets most of the way and carries a notch where it was sent
 * again. Anything else stops short against a hard cap. Nothing to decode, and it
 * is legible before a single word is read.
 * ═══════════════════════════════════════════════════════════════════════════ */
.fates{display:flex;flex-direction:column;gap:clamp(26px,3.6vw,40px);margin-top:36px}
.fate{display:grid;grid-template-columns:minmax(140px,auto) minmax(0,1fr) minmax(150px,auto);
  gap:clamp(14px,2vw,26px);align-items:center}
.fate-k{font-family:var(--mono);font-size:11px;letter-spacing:.15em;text-transform:uppercase;
  color:var(--muted);white-space:nowrap}
.fate-k b{color:var(--body);font-weight:700}
.fate-out{font-size:14.5px;color:var(--body);line-height:1.35}
.fate.ok .fate-out{color:#fff;font-weight:700}
.fate-rail{position:relative;height:3px;background:#1C1C1C}
.fate-rail i{position:absolute;inset:0;transform-origin:left center;transform:scaleX(0);
  transition:transform 1400ms cubic-bezier(.16,.9,.28,1)}
/* ⭐ the rail only ever reaches its own --reach, so the distances stay comparable */
.fates.on .fate-rail i{transform:scaleX(1)}
.fate-rail{width:100%}
.fate-rail i{width:var(--reach,100%)}
.fate.ok  .fate-rail i{background:linear-gradient(90deg,var(--signal),#FF8A4C);
  box-shadow:0 0 16px rgba(255,81,16,.6)}
.fate.retry .fate-rail i{background:linear-gradient(90deg,var(--signal),rgba(255,81,16,.45))}
.fate.halt  .fate-rail i{background:linear-gradient(90deg,#6E6257,#3A342E)}
.fates.on .fate.retry .fate-rail i{transition-delay:180ms}
.fates.on .fate.halt  .fate-rail i{transition-delay:360ms}
/* the notch: where it was sent again. A gap in the rail, not a symbol on top. */
.fate-notch{position:absolute;top:-4px;bottom:-4px;left:52%;width:9px;
  background:var(--ground);opacity:0;transition:opacity 300ms var(--ease) 1100ms}
.fate-notch::after{content:'';position:absolute;left:3px;top:4px;bottom:4px;width:3px;
  background:var(--signal)}
.fates.on .fate-notch{opacity:1}
/* the cap: a wall, thicker than the rail and taller, so it stops the eye too */
.fate-cap{position:absolute;top:-7px;bottom:-7px;left:var(--reach,38%);width:3px;
  background:#8C6A58;transform:scaleY(0);transform-origin:center;
  transition:transform 420ms cubic-bezier(.2,.9,.3,1) 1300ms}
.fates.on .fate-cap{transform:scaleY(1)}
.fate-note{margin:6px 0 0;max-width:56ch;font-size:13.5px;line-height:1.6;color:var(--muted)}
.fate-note b{color:var(--body)}
@media (max-width:720px){.fate{grid-template-columns:1fr;gap:9px}
.fate-rail{order:3}
.fate-out{order:2}
.fates{gap:clamp(30px,7vw,44px)}}
@media (prefers-reduced-motion:reduce){.fate-rail i,.fate-notch,.fate-cap{transition:none}}
/* ═══════════════════════════════════════════════════════════════════════════
 * ⭐ IDEA 1 — TRY TO OVERRIDE A GUARD.
 *
 * The section claims "none of them has an override — no force flag, no admin
 * bypass, no environment variable." That is a claim you should be able to TEST,
 * so every chip is now a button, and pressing one attempts exactly that.
 *
 * It types `--force` into the chip and the chip refuses it, in place. Nothing
 * shakes and nothing flashes red — a refusal that throws a tantrum reads as an
 * error. This one just does not move, which is the point: the wall is not
 * dramatic, it is simply closed.
 * ═══════════════════════════════════════════════════════════════════════════ */
.guards div{position:relative;cursor:pointer;user-select:none;
  transition:color .2s ease,background .2s ease}
.guards div:hover{color:var(--body);background:#0E0E0E}
.guards div:focus-visible{outline:2px solid var(--signal);outline-offset:-2px}
/* the attempt, typed into the chip */
.guards div::after{content:attr(data-try);position:absolute;left:14px;right:14px;top:12px;
  font-family:var(--mono);font-size:11.5px;color:var(--signal);
  opacity:0;pointer-events:none;transition:opacity .12s linear}
.guards div[data-try]::after{opacity:1}
.guards div[data-try]{color:transparent}
/* and the refusal that replaces it */
.guards div[data-refused]{color:transparent}
.guards div[data-refused]::after{content:attr(data-refused);color:#8C6A58;opacity:1}
/* ═══════════════════════════════════════════════════════════════════════════
 * ⭐ IDEA 2 — SCRUB THE FOURTEEN DAYS.
 *
 * The owed section animates once and makes its point. Dragging across it hands
 * the reader the controls: they move time themselves, forwards and backwards,
 * and the money rail below does not move at any position. An animation is a
 * claim; a control you operate yourself is a demonstration.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* ‼️ and the money rail is NOT listed here, at any scrub position, deliberately */
/* ═══════════════════════════════════════════════════════════════════════════
 * ⭐ IDEA 3 — THE SUMMING BRACKET.
 *
 * Hovering a total lights exactly the rows that produce it and draws a bracket
 * down their edge. A total nobody can trace is the thing every agency owner has
 * already been burned by, so the page lets you trace it with your eyes.
 * ═══════════════════════════════════════════════════════════════════════════ */
.ptable{position:relative}
.ptable tr.sums td{background:#0E0E0E;transition:background .18s ease}
.ptable::before{content:'';position:absolute;left:-10px;width:2px;
  top:var(--sum-top,0);height:var(--sum-h,0);background:var(--signal);
  opacity:0;transition:opacity .2s ease;pointer-events:none;
  box-shadow:0 0 12px rgba(255,81,16,.6)}
.ptable.summing::before{opacity:1}
/* ═══════════════════════════════════════════════════════════════════════════
 * ⭐ IDEA 4 — THE ROUTES ANSWER EACH OTHER.
 *
 * The section's claim is that the direction reverses and the outcome does not.
 * Hovering either card runs BOTH, at the same moment — so the reader triggers the
 * comparison instead of being told about it. Touching one and watching the other move is
 * the fastest way to understand that they are the same journey.
 *
 * ‼️ "IN OPPOSITE DIRECTIONS" WAS THE CLAIM HERE AND IT WAS NEVER TRUE. `route-run-rev`
 * was byte-identical to `route-run`, so both cards always ran the same way — and checking
 * clause 3 of the agreement they draw, they SHOULD: collect and disburse both go source →
 * bank → the party who is owed. The comment described an effect the code never had and the
 * contract never had either.
 * ═══════════════════════════════════════════════════════════════════════════ */
.route-card{cursor:default}
.route.paired .route-hop::after{transition-duration:900ms}
.route.paired .route-dot{animation:route-run 1500ms var(--ease) both !important}
.route.paired .route-card::before{transform:scaleY(1)}
/* the card you are actually on is the lit one; its twin is clearly the echo */
.route-card{transition:border-color .25s ease}
.route-card:hover{border-color:#3F3F3F}
/* ═══════════════════════════════════════════════════════════════════════════
 * ⭐ IDEA 5 — THE RAIN STARTS WHERE YOU TOUCH IT.
 *
 * 🩸 The first version crossfaded the whole wet frame in on hover, which is fine
 * and is also just a swap. The photograph is one image in two states, so the
 * interesting question is not WHETHER it is wet but WHERE it got wet — and the
 * answer should be "where you put your hand".
 *
 * The wet layer is revealed through a circular mask centered on the pointer that
 * opens from nothing to cover the frame. Leave, and it closes back to the point
 * you left from rather than fading uniformly, so the water has somewhere to go.
 * ═══════════════════════════════════════════════════════════════════════════ */
@property --wr{syntax:'<percentage>';inherits:false;initial-value:0%}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE PROMISE — set in one pass.
 *
 * This is the only full-bleed signal section on the site and it carries the one
 * rule that does not bend. A fade would say "here is another paragraph".
 *
 * ⭐ A hairline crosses the whole field at CONSTANT speed and the words appear
 * behind it, in lockstep, like a press laying them down. Linear timing on
 * purpose — an ease-out is a thing arriving and settling, and this is a thing
 * being SET. It makes one pass, it does not repeat, and it leaves.
 *
 * ⭐ It works on all four promise sections without knowing what any of them
 * says, because the mechanism is about the claim's STATUS, not its content.
 * ═══════════════════════════════════════════════════════════════════════════ */
.promise{position:relative;overflow:hidden}
.promise::before{content:'';position:absolute;top:0;bottom:0;left:0;width:2px;
  background:#000;opacity:0;pointer-events:none;z-index:2}
.js .promise.on::before{animation:promise-press 1500ms linear 120ms both}
@keyframes promise-press{
  0%   {left:-2px;  opacity:0}
  6%   {opacity:.55}
  94%  {opacity:.55}
  100% {left:100%;  opacity:0}
}
/* the words appear behind the head, at the same rate */
.js .promise .big{clip-path:inset(0 100% 0 0)}
.js .promise.on .big{animation:promise-set 1500ms linear 120ms both}
@keyframes promise-set{
  0%   {clip-path:inset(0 100% 0 0)}
  100% {clip-path:inset(0 0 0 0)}
}
/* everything else follows once the pass is done — nothing competes with it */
.js .promise .lede,.js .promise .promise-grid>div:last-child p{
  opacity:0;transform:translateY(6px);
  transition:opacity 520ms var(--ease),transform 520ms var(--ease)}
.js .promise.on .lede{opacity:1;transform:none;transition-delay:1450ms}
.js .promise.on .promise-grid>div:last-child p{opacity:1;transform:none;transition-delay:1560ms}
.js .promise.on .promise-grid>div:last-child p+p{transition-delay:1680ms}
@media (prefers-reduced-motion:reduce){.js .promise.on::before{animation:none;opacity:0}
.js .promise .big,.js .promise.on .big{animation:none;clip-path:none}
.js .promise .lede,.js .promise .promise-grid>div:last-child p{opacity:1;transform:none;transition:none}}
/* 🩸 THE BODY PARAGRAPH CARRIED `opacity:.86` INLINE, so the reveal rule below it
   could never win — an inline style beats a stylesheet no matter how specific the
   selector — and the paragraph sat there fully visible while the headline was
   still being pressed. It is a class now. Any "why won't this animate" that ends
   in a shrug is worth grepping for `style="` first. */
.promise-p{color:#000;opacity:.86;max-width:52ch;margin:0}
.js .promise .promise-p{opacity:0;transform:translateY(6px);
  transition:opacity 520ms var(--ease),transform 520ms var(--ease)}
.js .promise.on .promise-p{opacity:.86;transform:none;transition-delay:1620ms}
@media (prefers-reduced-motion:reduce){.js .promise .promise-p,.js .promise.on .promise-p{opacity:.86;transform:none;transition:none}}
/* ═══════════════════════════════════════════════════════════════════════════
 * HONEST STATUS — two claims are revealed, and one never was hidden.
 *
 * The section is "built and tested / the company / not live yet". The first two
 * are things we are disclosing; the third is the one nobody discloses, and it is
 * the reason the section exists.
 *
 * ⭐ So the first two are WIPED OPEN, left to right, and the third simply arrives
 * — no wipe, nothing withheld, and it lands FIRST. A section about honesty in
 * which the uncomfortable card is the one that was never covered.
 * ═══════════════════════════════════════════════════════════════════════════ */
.js .scard{position:relative}
.js .status .scard:nth-child(-n+2)>*{clip-path:inset(0 100% 0 0)}
.js .status.on .scard:nth-child(-n+2)>*{
  animation:scard-open 620ms cubic-bezier(.16,.9,.28,1) both}
@keyframes scard-open{to{clip-path:inset(0 0 0 0)}}
.js .status.on .scard:nth-child(1)>*:nth-child(1){animation-delay:460ms}
.js .status.on .scard:nth-child(1)>*:nth-child(2){animation-delay:540ms}
.js .status.on .scard:nth-child(1)>*:nth-child(3){animation-delay:620ms}
.js .status.on .scard:nth-child(2)>*:nth-child(1){animation-delay:700ms}
.js .status.on .scard:nth-child(2)>*:nth-child(2){animation-delay:780ms}
.js .status.on .scard:nth-child(2)>*:nth-child(3){animation-delay:860ms}
/* ‼️ THE THIRD CARD HAS NO WIPE AT ALL and arrives before the others. Do not
   "fix" this by giving it one — the asymmetry is the entire point of the block. */
.js .status .scard:nth-child(3){opacity:0;transform:translateY(6px);
  transition:opacity 520ms var(--ease),transform 520ms var(--ease)}
.js .status.on .scard:nth-child(3){opacity:1;transform:none;transition-delay:80ms}
/* the edge of the honest one stays lit */
.js .status .scard:nth-child(3){border-left:2px solid var(--signal)}
@media (prefers-reduced-motion:reduce){.js .status .scard>*,.js .status.on .scard>*{animation:none;clip-path:none}
.js .status .scard:nth-child(3){opacity:1;transform:none;transition:none}}
/* the six refusals divide evenly at every width; 6 = 3 × 2 */
.nots{grid-template-columns:repeat(3,minmax(0,1fr))}
@media (max-width:980px){.nots{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:600px){.nots{grid-template-columns:1fr}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE LADDER ACCUMULATES.
 *
 * "It just adds up" — one introduction, two, three, five, ten, all at the same
 * flat rate. The rows used to fade in one after another, which says "here is a
 * table". A table is not addition.
 *
 * ⭐ Each row now carries a bar whose width is that row's share of the ten-
 * introduction total, so the block builds into a staircase and the shape of the
 * arithmetic is visible before any figure is read. Flat rate means the staircase
 * is straight — if it ever curves, somebody has introduced a tier.
 * ═══════════════════════════════════════════════════════════════════════════ */
.step{position:relative}
.step::before{content:'';position:absolute;left:0;right:0;bottom:0;height:2px;
  background:linear-gradient(90deg,var(--signal),rgba(255,81,16,.25));
  transform:scaleX(0);transform-origin:left center;
  transition:transform 900ms cubic-bezier(.16,.9,.28,1)}
.steps.on .step::before{transform:scaleX(var(--w,0))}
.steps.on .step:nth-child(1)::before{transition-delay:120ms}
.steps.on .step:nth-child(2)::before{transition-delay:260ms}
.steps.on .step:nth-child(3)::before{transition-delay:400ms}
.steps.on .step:nth-child(4)::before{transition-delay:540ms}
.steps.on .step:nth-child(5)::before{transition-delay:680ms}
@media (prefers-reduced-motion:reduce){.step::before{transition:none}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE BLOG.
 *
 * ⭐ It uses the site's own type scale, ground and rules rather than a "blog
 * theme". A reader arriving from a search result should not be able to tell they
 * have left the product's world — that continuity is most of what makes a small
 * company look like a real one.
 *
 * ⭐ MEASURE IS THE WHOLE JOB HERE. Running text sits at ~68 characters. Wider
 * and the eye loses the line return; the marketing pages get away with short
 * blocks and this does not.
 * ═══════════════════════════════════════════════════════════════════════════ */
.post{padding:clamp(40px,7vw,96px) 0 clamp(60px,9vw,120px)}
.crumbs{display:flex;gap:9px;align-items:center;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted);margin-bottom:26px}
.crumbs a{color:var(--muted);text-decoration:none}
.crumbs a:hover{color:var(--body)}
.crumbs span{color:var(--rule)}
.post h1{font-size:clamp(30px,5.2vw,58px);line-height:1.04;letter-spacing:-.035em;
  margin:0 0 22px;max-width:20ch;text-wrap:balance;color:#fff}
.post-meta{display:flex;flex-wrap:wrap;gap:10px 26px;margin:0 0 clamp(30px,4vw,46px);
  padding-bottom:22px;border-bottom:1px solid var(--rule);
  font-size:13.5px;color:var(--body)}
.post-meta em{font-style:normal;display:block;color:var(--muted);font-size:12px;margin-top:2px}
.post-body{max-width:68ch}
.post-body>p{margin:0 0 20px;font-size:17px;line-height:1.68;color:var(--body)}
.post-body>p.lede{font-size:clamp(18px,2.3vw,22px);line-height:1.5;color:#fff;
  margin-bottom:30px;max-width:34ch}
.post-body>p.dim{color:var(--muted);font-size:15px}
.post-body b{color:#fff}
.post-body i{font-style:italic;color:#fff}
.post-body h2{font-size:clamp(21px,2.9vw,27px);letter-spacing:-.02em;line-height:1.2;
  margin:clamp(38px,5vw,54px) 0 16px;color:#fff;max-width:26ch;
  padding-top:22px;border-top:1px solid var(--rule)}
.post-body ul{margin:0 0 20px;padding-left:0;list-style:none}
.post-body li{position:relative;padding-left:22px;margin-bottom:12px;
  font-size:16.5px;line-height:1.62;color:var(--body)}
/* the marker is a rule, not a bullet — the site divides with rules everywhere else */
.post-body li::before{content:'';position:absolute;left:0;top:.72em;width:11px;height:1px;
  background:var(--signal)}
.post-body .tscroll{margin:30px 0}
/* ON-RECORD QUOTES. Written before the first one arrives, deliberately: a class used
   in markup and defined in no stylesheet renders as unstyled text and nobody notices,
   because the day it first appears is the day nobody is looking at the CSS. The block
   emits nothing while blog/voices.mjs is empty. */
.voices{margin-top:clamp(40px,5.5vw,64px);max-width:68ch;
  display:flex;flex-direction:column;gap:20px}
.voices h2{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted);margin:0}
.voice{margin:0;padding:0 0 0 clamp(16px,2.2vw,24px);border-left:2px solid var(--rule)}
.voice blockquote{margin:0 0 10px;font-size:clamp(16px,2vw,19px);line-height:1.55;
  color:#fff;font-weight:500}
.voice figcaption{display:flex;gap:10px;align-items:center;flex-wrap:wrap;
  font-size:13px;color:var(--muted)}
/* a face, when somebody has given us one. Square, small, and never the point. */
.voice-face{width:44px;height:44px;object-fit:cover;flex:0 0 auto;
  border:1px solid var(--rule)}
.voice figcaption a{color:var(--body);text-decoration:none;border-bottom:1px solid var(--rule)}
.voice figcaption a:hover{color:#fff;border-color:var(--body)}
.post-cta{margin-top:clamp(44px,6vw,72px);padding:clamp(24px,3.4vw,38px);
  border:1px solid var(--rule);background:var(--raise);max-width:68ch}
.post-cta .big{font-size:clamp(19px,2.6vw,25px);font-weight:700;letter-spacing:-.02em;
  color:#fff;margin:0 0 10px;max-width:24ch}
.post-cta p{color:var(--body);margin:0 0 18px;max-width:52ch;font-size:15.5px;line-height:1.6}
.post-links{display:flex;gap:20px;align-items:center;flex-wrap:wrap;margin:0}
/* ══════════════════════════════════════════════════════════════════════════
 * FROM THE BLOG, ON THE HOMEPAGE.
 *
 * Three posts one click from the only page Google has indexed. It shares the
 * read-next treatment deliberately — a reader who meets this on the homepage and
 * then again at the foot of a post is meeting the same component, and a site that
 * uses one pattern for one job reads as considered rather than assembled.
 *
 * ‼️ NO SIGNAL ORANGE. The accent belongs to money or the next action, and two
 * sections below this one is the actual call to action. A blog block louder than
 * the thing it sits above is a leak.
 * ══════════════════════════════════════════════════════════════════════════ */
.home-reads{border-top:1px solid var(--rule)}
.reads{list-style:none;margin:clamp(24px,3.5vw,38px) 0 0;padding:0;max-width:72ch}
.reads li{padding:20px 0;border-bottom:1px solid var(--rule)}
.reads li:first-child{border-top:1px solid var(--rule)}
.reads a{display:block;color:#fff;font-size:clamp(17px,2.2vw,21px);font-weight:600;
  letter-spacing:-.015em;line-height:1.3;text-decoration:none}
.reads a:hover{color:var(--signal);text-decoration:none}
.reads span{display:block;color:var(--body);font-size:15px;line-height:1.6;
  margin-top:7px;max-width:62ch}
.home-reads .post-links{margin-top:clamp(22px,3vw,30px)}
@media (max-width:640px){.reads li{padding:16px 0}
.reads span{font-size:14.5px}}
/* ══════════════════════════════════════════════════════════════════════════
 * READ NEXT — three posts, each with the reason you would want it.
 *
 * Measured 2026-08-30: four of the twelve posts linked to no other post and one had
 * nothing linking to it. Internal links pass authority between pages, tell a crawler
 * twelve pages are one subject, and give a reader who finishes a post somewhere to go
 * other than away.
 *
 * It sits UNDER the call to action deliberately. Somebody converting has already
 * clicked; somebody not converting is the person this is for, and putting it above
 * would compete with the one control on the page that earns money.
 *
 * ‼️ QUIET ON PURPOSE. The signal orange is reserved for money or the next action —
 * this is neither, so it is a rule, a heading and the same link color the body copy
 * uses. A read-next block louder than the CTA above it is a leak, not a feature.
 * ══════════════════════════════════════════════════════════════════════════ */
.read-next{margin-top:clamp(38px,5vw,58px);padding-top:clamp(22px,3vw,30px);
  border-top:1px solid var(--rule);max-width:68ch}
.read-next h2{font-family:var(--mono,ui-monospace,monospace);font-size:11px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--muted);font-weight:400;
  margin:0 0 4px}
.read-next ul{list-style:none;margin:0;padding:0}
.read-next li{padding:16px 0;border-bottom:1px solid var(--rule)}
.read-next li:last-child{border-bottom:0;padding-bottom:0}
.read-next a{display:block;color:#fff;font-size:clamp(16px,2vw,18.5px);font-weight:600;
  letter-spacing:-.01em;line-height:1.35;text-decoration:none}
.read-next a:hover{color:var(--signal);text-decoration:none}
.read-next span{display:block;color:var(--body);font-size:14.5px;line-height:1.55;
  margin-top:5px;max-width:56ch}
@media (max-width:640px){.read-next li{padding:14px 0}}
/* ── the hub ── */
.post-list{display:flex;flex-direction:column;margin-top:clamp(30px,4vw,46px);
  border-top:1px solid var(--rule)}
.pcard-row{display:grid;grid-template-columns:minmax(110px,auto) minmax(0,1fr) auto;
  gap:clamp(14px,2.4vw,32px);align-items:baseline;padding:22px 4px;
  border-bottom:1px solid var(--rule);text-decoration:none;color:inherit;
  transition:background .2s ease}
.pcard-row:hover{background:var(--raise)}
.pr-date,.pr-min{font-family:var(--mono);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);white-space:nowrap}
.pr-min{text-align:right}
.pr-main b{display:block;font-size:clamp(17px,2.3vw,21px);letter-spacing:-.02em;color:#fff;
  line-height:1.25;margin-bottom:6px}
.pr-main em{font-style:normal;display:block;color:var(--muted);font-size:14.5px;
  line-height:1.5;max-width:62ch}
.pcard-row:hover .pr-main b{color:var(--signal)}
@media (max-width:720px){.pcard-row{grid-template-columns:1fr;gap:6px;padding:20px 2px}
.pr-min{text-align:left}
.post-meta{gap:8px 18px}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE RETURN CODES — two of the six behave differently, so two of them arrive
 * differently.
 *
 * Six codes land together, quietly, because this is reference material and not a
 * sequence to sit through. Then the TWO that can be re-presented light their
 * "retried once" label a beat later. The eye finds the pair that behaves
 * differently without anyone having to read all six.
 * ═══════════════════════════════════════════════════════════════════════════ */
.js .rcode .a{opacity:0;transition:opacity 420ms var(--ease)}
.js .rcodes.on .rcode .a{opacity:1;transition-delay:420ms}
.js .rcodes.on .rcode.retry .a{transition-delay:900ms}
.js .rcode.retry .a{position:relative}
.js .rcode.retry .a::before{content:'';position:absolute;left:-11px;top:50%;
  width:5px;height:5px;margin-top:-2.5px;border-radius:50%;background:var(--signal);
  transform:scale(0);transition:transform 320ms cubic-bezier(.2,.9,.3,1)}
.js .rcodes.on .rcode.retry .a::before{transform:scale(1);transition-delay:1000ms}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE PRICE TABLE ADDS ITSELF UP.
 *
 * The rows arrive in order, then a rule draws under them and the total lands
 * after it — the shape of an invoice being totted up rather than a table
 * appearing. The rule is the arithmetic happening; the total cannot arrive
 * before the line that produces it.
 * ═══════════════════════════════════════════════════════════════════════════ */
.js .ptable tbody tr.tot td{position:relative}
.js .ptable tbody tr.tot td::before{content:'';position:absolute;left:0;right:0;top:0;
  height:1px;background:var(--signal);transform:scaleX(0);transform-origin:left center;
  transition:transform 620ms cubic-bezier(.16,.9,.28,1)}
.js .ptable.on tbody tr.tot td::before{transform:scaleX(1);transition-delay:700ms}
.js .ptable.on tbody tr.tot{transition-delay:1180ms}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE ANSWER FIRST.
 *
 * `.dirs` on the creators page holds four objections — "will this touch my
 * money", "can they take more". Somebody scanning that section is looking for
 * the ANSWER, so the answer word arrives alone, holds, and the explanation fills
 * in under it. Nobody reads an objection card top to bottom.
 * ═══════════════════════════════════════════════════════════════════════════ */
.js .dir h3{position:relative}
.js .dir p{opacity:0;transform:translateY(4px);
  transition:opacity 420ms var(--ease),transform 420ms var(--ease)}
.js .dirs.on .dir p{opacity:1;transform:none}
.js .dirs.on .dir:nth-child(1) p{transition-delay:460ms}
.js .dirs.on .dir:nth-child(2) p{transition-delay:590ms}
.js .dirs.on .dir:nth-child(3) p{transition-delay:720ms}
.js .dirs.on .dir:nth-child(4) p{transition-delay:850ms}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE CLOSING ACTION.
 *
 * The last thing on every page is a button. It used to fade up with everything
 * else, which is the one moment on the page where "one more element arriving" is
 * the wrong note. ⭐ The signal cut sweeps across it ONCE, on arrival — the same
 * gesture as the mark in the wordmark, so the page ends where it began.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* 🩸🩸 TWO WRONG WAYS FIRST, both of which the sweep caught.
   `overflow:hidden` made every button report as clipped text — 33 across the sweep —
   because the truncation detector looks for exactly that property and a button is
   text in a box. Swapping to clip-path did not help either, and the reason is the
   real one: the sweep was an absolutely positioned ::after sitting at left:-40%, and
   an out-of-flow child that pokes out of its parent ADDS TO scrollWidth. The element
   was invisible and still 71px wider than its box, so the detector was right both
   times — it was reporting a real overflow that happened to be a decoration.

   ⭐ The sheen is a BACKGROUND LAYER now. No box, no child, nothing to overflow,
   and the button measures exactly as wide as its text. */
.js .hero-actions .cta{position:relative}
.js .hero-actions.on .cta{
  background-image:linear-gradient(100deg,transparent 42%,rgba(255,255,255,.40) 50%,transparent 58%);
  background-repeat:no-repeat;background-size:240% 100%;
  animation:cta-cut 900ms cubic-bezier(.3,.7,.2,1) 620ms both}
@keyframes cta-cut{
  from{background-position:-140% 0}
  to  {background-position:240% 0}
}
@media (prefers-reduced-motion:reduce){.js .rcode .a,.js .dir p{opacity:1;transform:none;transition:none}
.js .rcode.retry .a::before{transform:scale(1);transition:none}
.js .ptable tbody tr.tot td::before{transform:scaleX(1);transition:none}
.js .hero-actions.on .cta::after{animation:none;display:none}}
/* ═══════════════════════════════════════════════════════════════════════════
 * TRUST SIGNALS.
 *
 * ⭐ Every card names a specific thing we do or refuse, and carries the CODE or
 * the RULE that enforces it. "Bank-level security" is not a trust signal; a guard
 * code you can search for is. Six is chosen because it divides by three and two
 * and can never leave a hole — see gridgaps.mjs.
 *
 * ‼️ NO BANK LOGOS HERE, ever. We do not have permission to use them, and a logo
 * wall implying a partnership nobody agreed to reads to an underwriter as a red
 * flag rather than as reassurance.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* 🩸 NO TOP RULE. On the home page this section follows a photograph, and a 1px
   #222 line under a band is exactly the hard edge the whole mask system exists to
   remove — bandseam.mjs caught it at 88–101% across, where the picture is darkest.
   Pages where the section follows text add the rule inline, at the one place it is
   actually a separator. */
.trust{}
.trust-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:1px;margin-top:34px;background:var(--rule);border:1px solid var(--rule)}
.tsig{background:var(--ground);padding:clamp(18px,2.3vw,26px);display:flex;
  flex-direction:column;gap:8px}
.tsig b{font-size:16px;color:#fff;letter-spacing:-.01em;line-height:1.3}
.tsig span{font-size:14px;color:var(--body);line-height:1.5}
.tsig em{font-style:normal;margin-top:auto;padding-top:10px;font-family:var(--mono);
  font-size:9.5px;letter-spacing:.17em;text-transform:uppercase;color:var(--signal)}
@media (max-width:920px){.trust-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:600px){.trust-grid{grid-template-columns:1fr}}
/* they arrive left to right, one rule at a time — the order they are read in */
.js .tsig{opacity:0;transform:translateY(8px);
  transition:opacity 480ms var(--ease),transform 480ms var(--ease)}
.js .trust-grid.on .tsig{opacity:1;transform:none}
.js .trust-grid.on .tsig:nth-child(1){transition-delay:60ms}
.js .trust-grid.on .tsig:nth-child(2){transition-delay:150ms}
.js .trust-grid.on .tsig:nth-child(3){transition-delay:240ms}
.js .trust-grid.on .tsig:nth-child(4){transition-delay:330ms}
.js .trust-grid.on .tsig:nth-child(5){transition-delay:420ms}
.js .trust-grid.on .tsig:nth-child(6){transition-delay:510ms}
.js .trust-grid.on .tsig:nth-child(n+7){transition-delay:560ms}
@media (prefers-reduced-motion:reduce){.js .tsig{opacity:1;transform:none;transition:none}}
/* a calculator inside an article: the inputs have to read as part of the table */
.post-body .ptable input{background:var(--ground);border:1px solid var(--rule);color:#fff;
  font-family:var(--mono);font-size:16px;padding:7px 10px;width:min(160px,40vw);
  text-align:right;border-radius:0}
.post-body .ptable input:focus{outline:2px solid var(--signal);outline-offset:1px;
  border-color:var(--signal)}
.post-body .ptable label{cursor:pointer}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE REFUSALS — a barrier dropping, not a card fading.
 *
 * "What OnlyFlow will never do", six of them. A fade says "here is a list". The
 * left edge of each card now DRAWS DOWN in signal as it arrives and then settles
 * to a plain rule — a barrier coming down and staying down. It is the same
 * gesture six times because they are the same kind of statement six times, and
 * varying it would suggest some of them are softer than others.
 * ═══════════════════════════════════════════════════════════════════════════ */
.not{position:relative}
.not::before{content:'';position:absolute;left:0;top:0;bottom:0;width:2px;
  background:var(--signal);transform:scaleY(0);transform-origin:top center;
  transition:transform 480ms cubic-bezier(.2,.85,.3,1),background 700ms var(--ease) 520ms}
.nots.on .not::before{transform:scaleY(1);background:var(--rule)}
.nots.on .not:nth-child(1)::before{transition-delay:60ms,580ms}
.nots.on .not:nth-child(2)::before{transition-delay:160ms,680ms}
.nots.on .not:nth-child(3)::before{transition-delay:260ms,780ms}
.nots.on .not:nth-child(4)::before{transition-delay:360ms,880ms}
.nots.on .not:nth-child(5)::before{transition-delay:460ms,980ms}
.nots.on .not:nth-child(6)::before{transition-delay:560ms,1080ms}
.nots.on .not:nth-child(n+7)::before{transition-delay:620ms,1140ms}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE CREATOR'S FOUR STEPS — the money leaves the first line and lands on the
 * third.
 *
 * The section walks a creator through what happens to a payout. It read as four
 * rows appearing. ⭐ Now the amount on STEP 01 stays lit while the rows arrive,
 * and the share on STEP 03 lights as it lands — so the eye connects the two
 * figures that are the same money, and the $0.00 on the last line stays plain
 * because nothing happened to it. That is the argument of the whole page.
 * ═══════════════════════════════════════════════════════════════════════════ */
.js .ledger-rows[data-flow] .lrow:nth-child(1) .v{color:var(--signal);
  text-shadow:0 0 26px rgba(255,81,16,.35)}
.js .ledger-rows[data-flow] .lrow:nth-child(3) .v{color:var(--body);
  transition:color 520ms var(--ease),text-shadow 520ms var(--ease)}
.js .ledger-rows[data-flow].on .lrow:nth-child(3) .v{color:var(--signal);
  text-shadow:0 0 26px rgba(255,81,16,.35);transition-delay:820ms}
/* ‼️ the last line is $0.00 and gets NOTHING. Lighting it would say something
   happened, and the entire point is that nothing did. */
@media (prefers-reduced-motion:reduce){.not::before{transition:none;transform:scaleY(1);background:var(--rule)}
.js .ledger-rows[data-flow] .lrow:nth-child(3) .v{transition:none}}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE ANSWERS PAGE — a search that behaves like a terminal, not a widget.
 *
 * Operator, 2026-08-23: "why is there not a specific faq page with 10000000s of
 * questions answered with the most unique search mechanism with the most beautiful
 * ui ux ever."
 *
 * ⭐ WHAT MAKES IT ITS OWN THING: the field is a prompt with a caret, the live count
 * sits inside it, "/" focuses it from anywhere and Escape clears it, and the moment a
 * search leaves exactly one answer standing that answer OPENS ITSELF. Nobody should
 * have to click the only result.
 *
 * ⭐ AND IT IS ALL LOCAL. Everything is already in the DOM, so results move on the
 * keystroke rather than after a request. With script off, the page is a complete
 * document and every answer is still readable — which is also how it gets indexed.
 * ═══════════════════════════════════════════════════════════════════════════ */
.faq-hero{padding:clamp(38px,6vw,86px) 0 clamp(22px,3vw,34px)}
.faq-body{padding-bottom:clamp(50px,7vw,96px)}
.finder{margin-top:clamp(26px,3.6vw,44px)}
.finder-box{display:flex;align-items:center;gap:12px;
  border:1px solid var(--rule);background:var(--raise);
  padding:clamp(12px,1.6vw,17px) clamp(14px,2vw,20px);
  transition:border-color .18s var(--ease),box-shadow .18s var(--ease)}
.finder-box:focus-within{border-color:var(--signal);
  box-shadow:0 0 0 1px var(--signal),0 0 34px rgba(255,81,16,.16)}
.finder-caret{font-family:var(--mono);color:var(--signal);font-size:15px;line-height:1}
.finder-box input{flex:1 1 auto;background:transparent;border:0;outline:none;color:#fff;
  font-family:var(--sans);font-size:clamp(16px,2vw,20px);letter-spacing:-.01em;
  min-width:0;padding:0}
.finder-box input::placeholder{color:#5A5A5A}
.finder-box input::-webkit-search-cancel-button{-webkit-appearance:none}
.finder-count{font-family:var(--mono);font-size:12.5px;color:var(--muted);
  font-variant-numeric:tabular-nums;flex:0 0 auto}
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}
.chip{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);background:transparent;border:1px solid var(--rule);
  padding:7px 12px;cursor:pointer;transition:color .16s,border-color .16s,background .16s}
.chip:hover{color:var(--body);border-color:var(--muted)}
/* ‼️ aria-pressed, not a class. `.on` on this site means "revealed by the scroll
   observer", and a guard enforces that every such class is watched by one — a filter
   chip that borrowed the name would either break that rule or teach somebody to
   weaken it. The attribute is also the thing a screen reader reads. */
.chip[aria-pressed="true"]{color:#000;background:var(--body);border-color:var(--body)}
.qa-group{margin-top:clamp(34px,4.6vw,60px)}
.qa-group h2{font-family:var(--mono);font-size:11px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--muted);font-weight:400;margin:0 0 6px}
.qa{border-bottom:1px solid var(--rule)}
.qa summary{list-style:none;cursor:pointer;display:flex;align-items:flex-start;gap:14px;
  padding:clamp(15px,1.8vw,20px) 0;font-size:clamp(16px,2.1vw,20px);font-weight:600;
  letter-spacing:-.015em;color:var(--body);transition:color .16s}
.qa summary::-webkit-details-marker{display:none}
.qa summary::marker{content:''}
.qa summary::after{content:'+';margin-left:auto;font-family:var(--mono);font-weight:400;
  color:var(--muted);font-size:19px;line-height:1;transition:transform .2s var(--ease),color .16s}
.qa[open] summary::after{transform:rotate(45deg);color:var(--signal)}
.qa summary:hover,.qa[open] summary{color:#fff}
.qa-a{padding:0 0 clamp(16px,2vw,24px);max-width:64ch}
.qa-a p{margin:0 0 10px;color:var(--muted);font-size:clamp(14.5px,1.7vw,16.5px);line-height:1.62}
.qa-a p:first-child{color:var(--body)}
.qa-a p:last-child{margin-bottom:0}
.js .qa[open] .qa-a{animation:qa-open 260ms var(--ease) both}
@keyframes qa-open{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
.qa-none{padding:clamp(30px,5vw,56px) 0;border-top:1px solid var(--rule);margin-top:30px}
.qa-none .big{font-size:clamp(20px,2.8vw,27px);font-weight:800;letter-spacing:-.025em;
  color:#fff;margin:0 0 8px}
.qa-none p{color:var(--muted);margin:0}
.faq-cta{border-top:1px solid var(--rule);padding:clamp(44px,6vw,86px) 0}
@media (prefers-reduced-motion:reduce){.js .qa[open] .qa-a{animation:none}}
/* ═══════════════════════════════════════════════════════════════════════════
 * PRICING — the three numbers, then one bill.
 *
 * 🩸 THE PAGE THIS REPLACED had a table of three prices, a calculator that listed
 * the same three prices again, a four-row table of effective rates, three explainer
 * cards and two photographs. Operator: "who is reading all of this? r u serious? more
 * ai slop" · "this should be the best visual on the whole site".
 *
 * ⭐ SO: the price is the first thing on the page, and the calculator IS the invoice.
 * You move your own size and the bill re-prints. Everything that was explanation is
 * on /faq.html, where somebody who wants it can find it and nobody else has to scroll
 * past it.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════════════════════
   🩸 THREE PRICES MUST NEVER BE TWO PLUS ONE. `auto-fit` with a 240px floor gives two
   columns from about 500px to about 820px, which leaves the third price alone beside an
   empty grid cell — and an empty cell on this background renders as a grey box.
   `gridgaps.mjs` found it at 768.

   ⭐ THE TWO-COLUMN STATE IS REMOVED RATHER THAN PATCHED. Making the last one span is
   the fix `.wall` and `.guards` need, because 29 items genuinely cannot divide evenly;
   three items in three columns always can, so the honest fix is to go straight from one
   column to three at the width where three fit. No hole to paper over.
   ═══════════════════════════════════════════════════════════════════════════ */
.price3{display:grid;gap:1px;background:var(--rule);border:1px solid var(--rule);
  margin-top:clamp(26px,3.6vw,44px);
  grid-template-columns:1fr}
@media (min-width:820px){.price3{grid-template-columns:repeat(3,minmax(0,1fr))}}
/* ⭐ THE ONE LINE UNDER A DIAL THAT SAYS WHAT IT IS. The operator read "Payouts a
   month" three different ways and none of them was certain — a calculator whose input
   is ambiguous returns a confident wrong answer. */
.dial-note{margin:8px 0 0;font-size:12.5px;color:var(--muted);line-height:1.45}
.p3{background:var(--ground);padding:clamp(20px,2.6vw,30px);display:flex;
  flex-direction:column;gap:6px}
.p3-n{font-family:var(--mono);font-weight:700;font-variant-numeric:tabular-nums;
  font-size:clamp(38px,5.4vw,62px);line-height:.9;letter-spacing:-.04em;color:#fff}
.p3-n i{font-style:normal;font-size:.34em;color:var(--muted);margin-left:.08em;
  letter-spacing:0}
.p3-k{font-family:var(--mono);font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted)}
.p3 p{margin:4px 0 0;color:var(--body);font-size:14.5px;line-height:1.5;max-width:30ch}
.p3-hot .p3-n{color:var(--signal)}
/* ── the bill ─────────────────────────────────────────────────────────────── */
/* 🩸 NAMED `.invoice`, NOT `.bill` — `.bill` has meant the two-bills comparison since
   August and its `span` rule sets `white-space:nowrap`. My new component inherited it
   and every label in it was CLIPPED instead of wrapping, on eleven viewports at once.
   Two components with one class name is a collision the cascade resolves silently. */
.invoice{margin-top:clamp(26px,3.4vw,42px);display:grid;gap:clamp(18px,2.4vw,30px);
  grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr));align-items:start}
.invoice-set{display:flex;flex-direction:column;gap:clamp(16px,2vw,24px)}
.dial{display:grid;gap:6px}
.dial label{font-family:var(--mono);font-size:10.5px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--muted)}
.dial output{font-family:var(--mono);font-weight:700;font-variant-numeric:tabular-nums;
  font-size:clamp(26px,3.6vw,40px);line-height:1;letter-spacing:-.03em;color:#fff}
/* the track is a lit line, not a widget */
.dial input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:22px;
  background:transparent;cursor:pointer}
.dial input[type=range]::-webkit-slider-runnable-track{height:2px;background:#242424}
.dial input[type=range]::-moz-range-track{height:2px;background:#242424}
.dial input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;
  width:14px;height:14px;margin-top:-6px;background:var(--signal);border:0;border-radius:0;
  box-shadow:0 0 16px rgba(255,81,16,.55)}
.dial input[type=range]::-moz-range-thumb{width:14px;height:14px;background:var(--signal);
  border:0;border-radius:0}
.dial input[type=range]:focus-visible{outline:2px solid var(--signal);outline-offset:6px}
.dial-seg .seg{display:flex;border:1px solid var(--rule)}
.dial-seg .seg button{flex:1 1 0;background:transparent;border:0;color:var(--muted);
  font-family:var(--sans);font-weight:700;font-size:14px;padding:11px 10px;cursor:pointer;
  transition:background .16s,color .16s}
.dial-seg .seg button[aria-pressed="true"]{background:var(--signal);color:#000}
.invoice-out{border:1px solid var(--rule);background:var(--raise);
  padding:clamp(20px,2.6vw,30px)}
.invoice-earn{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  padding-bottom:14px;border-bottom:1px solid var(--rule)}
.invoice-earn span{font-family:var(--mono);font-size:10.5px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--muted)}
.invoice-earn b{font-family:var(--mono);font-size:clamp(17px,2.2vw,22px);color:#fff;
  font-variant-numeric:tabular-nums}
.invoice-rows{padding:6px 0}
.brow{display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  padding:11px 0;border-bottom:1px solid rgba(255,255,255,.05)}
/* ‼️ `min-width:0` and a real flex basis, or the label is CLIPPED rather than
   wrapped: a flex item's minimum size is its content by default, so "0.90% of the
   $30,000.00 we moved" ran under the amount at every width below 430px. Caught by
   the viewport sweep on eleven combinations at once. */
.brow span{color:var(--muted);font-size:14.5px;flex:1 1 auto;min-width:0}
.brow b{font-family:var(--mono);color:var(--body);font-variant-numeric:tabular-nums;
  font-size:15px;white-space:nowrap;flex:0 0 auto}
.invoice-tot{padding-top:16px}
.invoice-k{font-family:var(--mono);font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted)}
.invoice-n{font-family:var(--mono);font-weight:700;font-variant-numeric:tabular-nums;
  font-size:clamp(46px,7.6vw,86px);line-height:.9;letter-spacing:-.045em;color:var(--signal);
  margin:6px 0 4px;text-shadow:0 0 60px rgba(255,81,16,.28)}
.invoice-say{margin:0;color:var(--body);font-size:15.5px}
.invoice-say b{color:#fff}
.invoice-side{margin:18px 0 0;padding-top:16px;border-top:1px solid var(--rule);
  color:var(--muted);font-size:13.5px;line-height:1.6}
.invoice-side b{color:var(--body)}
/* ═══════════════════════════════════════════════════════════════════════════
 * THE WALL — twenty-nine refusals, and a light that never stops moving.
 *
 * Operator, 2026-08-23: "needs to be moved to compliance and visually shown
 * different in a different animation that always moves."
 *
 * 🩸 THE VERSION THIS REPLACES was a static grid of code names on the home page. It
 * read as a screenshot of a config file: impressive to somebody already convinced,
 * meaningless to somebody deciding whether to care. It is on /compliance now, where
 * the reader is checking us rather than meeting us.
 *
 * ⭐ AND IT NEVER SETTLES. One light travels the wall forever, lifting each code as
 * it passes. The claim is that these run on every transfer, continuously — a picture
 * that stops moving argues the opposite. The loop is one keyframe and a per-cell
 * delay, so twenty-nine elements animate without twenty-nine rules.
 * ═══════════════════════════════════════════════════════════════════════════ */
.wall{margin-top:clamp(26px,3.4vw,40px);display:grid;gap:1px;background:var(--rule);
  border:1px solid var(--rule);
  grid-template-columns:repeat(auto-fit,minmax(min(210px,100%),1fr))}
.wall span{background:var(--ground);padding:13px 15px;font-family:var(--mono);
  font-size:clamp(10px,1.15vw,11.5px);letter-spacing:.08em;color:#4E4E4E;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  /* ⭐ the delay IS the position of the light. --i comes from the markup, so the
     order on screen and the order of the sweep cannot disagree. */
  animation:wall-sweep 9s linear infinite;
  animation-delay:calc(var(--i) * -0.31s)}
@keyframes wall-sweep{
  0%,   92%  { color:#4E4E4E; background:var(--ground); box-shadow:none }
  95%        { color:#fff;    background:#0E0E0E;
               box-shadow:inset 2px 0 0 var(--signal), 0 0 30px rgba(255,81,16,.10) }
  100%       { color:#4E4E4E; background:var(--ground); box-shadow:none }
}
/* ‼️ HOVER STOPS IT ON THAT CELL. Somebody reading a code should not have it move
   under their eye — and the pause is also how you tell it is one continuous sweep
   rather than a random flicker. */
.wall span:hover{animation-play-state:paused;color:#fff;background:#101010}
/* 🩸 29 IS PRIME, so the last row always left empty tracks — and an empty grid cell on
   this background renders as a grey box. The operator has already sent a screenshot of
   that exact thing on another section. The last code spans the row instead, which reads
   as deliberate rather than as a hole. */
.wall span:last-child{grid-column:1/-1}
@media (prefers-reduced-motion:reduce){.wall span{animation:none;color:#5A5A5A}}

/* ═══════════════════════════════════════════════════════════════════════════
 * ⭐ THE MENU IS FOUR LINKS AND A BUTTON — 2026-09-02.
 *
 * 🩸 It was eight links in three labeled groups and Charlie counted them out loud:
 * "There's like 50 different pages." adam: "Too much." Three of the nine existed for
 * search traffic that adam says will never matter — "seo doesnt matter, all customers
 * will come from refs" — so /creators, /faq and /blog left the menu. They did NOT
 * leave the site: they are in the footer and in the sitemap, because the operator's
 * rule on this whole pass is "no info lost".
 *
 * ⭐ With four links the three group kickers were furniture rather than help, so they
 * went too. Charlie: "sign in can be animated as a button at the bottom when you click
 * the hamburger" — so it is a button, and it arrives after the links do.
 *
 * ‼️ THE ANIMATION IS DECLARED ON `.menu[open]`, NOT `.js .menu[open]`. The menu is a
 * <details> that opens with the script blocked; hanging the button's only appearance on
 * JavaScript would hide sign-in from anyone whose script never ran. Without JS it simply
 * appears instantly, which is the correct degradation.
 * ═══════════════════════════════════════════════════════════════════════════ */
.menu-panel > a:first-child{margin-top:6px}

.menu-signin{
  margin:12px 20px 4px;padding:12px 16px;
  background:var(--signal);color:#0A0A0A;
  font-family:var(--mono);font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  font-weight:700;text-align:center;border-left:0;
}
/* ‼️ the panel paints #141414 on any <a>:hover; this one is signal orange and must not
   be repainted by it, so the override is as specific as the rule it is beating. */
.menu-panel a.menu-signin:hover,.menu-panel a.menu-signin:focus-visible{
  background:var(--signal);filter:brightness(1.08)}

.menu[open] .menu-signin{animation:menu-signin-in 260ms var(--ease) 120ms both}
@keyframes menu-signin-in{
  from{opacity:0;transform:translate3d(0,10px,0)}
  to{opacity:1;transform:none}
}
@media (prefers-reduced-motion:reduce){
  .menu[open] .menu-signin{animation:none}
}


/* ═══════════════════════════════════════════════════════════════════════════
 * ⭐ THE HOME HERO IS THE PHONE NOW — 2026-09-02.
 *
 * 🩸 It was two 3D slabs cut by a diagonal, `.stage`, and on a phone it was a
 * 430px SQUARE: `max-width:430px; aspect-ratio:1` with no cap below 620px, so on
 * a 390px screen the graphic was 390px tall — adam: "These triangles are huge, and
 * it takes up half the screen. The talk to us button is being cut off bc of it."
 * That was not a rendering accident. The stylesheet said 1:1 up to 430px and
 * nothing ever said otherwise on a small screen.
 *
 * ⭐ THE REPLACEMENT WAS ALREADY SHIPPING ON /refer, where adam's verdict was
 * "This is really nice and this graphic makes sense. This is lowkey best graphic
 * on sight" and "we should do more of those instead of ... random PNGs of rocks or
 * vaults or chairs". So the home hero uses the same component, not a new one.
 *
 * ‼️ `.stage` ITSELF IS NOT DELETED — /how-it-works still carries one. It gets the
 * mobile cap it never had, because the same 430px square is in that page's hero too
 * and adam's complaint applies to it word for word.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* adam: "Text here needs more spacing. Especially between bolded text v the subtext."
   🩸 `.hero .lede{margin-top:22px}` existed and never applied here — the home and
   referral heroes are `.split-hero`, not `.hero`, so both were falling back to the
   browser's default paragraph margin. */
.split-hero .col .lede{margin-top:clamp(20px,3.4vw,32px)}
.split-hero .col .label + .display{margin-top:14px}

/* the phone is the first thing on a phone, so it is the thing that must not dominate */
@media (max-width:620px){
  .split-grid .phone{width:clamp(168px,44vw,196px)}
  .hero-actions{margin-top:26px}
}

/* ‼️ AND THE SQUARE THAT CAUSED THE COMPLAINT, capped everywhere it still exists. */
@media (max-width:620px){
  .stage{max-width:min(300px,62vw)}
}
