/* =============================================================================
   Founders Program invite landing (/founders for guests, /founders/join/<code>).
   Scoped entirely under .fi -- nothing here leaks into the rest of the site.

   ANIMATION CONTRACT (read before adding anything):
     - transform + opacity ONLY. Never width/height/top/left/margin.
     - NOTHING runs forever. Every animation here is a one-shot reveal that
       settles and then stops, so no permanent GPU layer is promoted and no
       overlapping sibling gets dragged into a layer with it.
     - The "hidden" starting states live behind .fi-motion, which JS only adds
       when the browser supports what we need AND the visitor hasn't asked for
       reduced motion. With JS off / reduced motion on, the page is simply
       already in its final state.
     - No backdrop-filter anywhere in this file: the cards repeat, and repeated
       backdrop-filter is what cooked members' phones.
   ========================================================================== */

.fi{
  --fi-measure: 62ch;        /* body copy line length */
  --fi-gap: 18px;
  --fi-pad: 20px;
  /* Tier colours. t30 rides --accent (gold in dark, blue in light) because the top
     tier should always look like the site's "good" colour -- which means t20 must
     NOT be blue, or the two collapse into each other in light mode. Teal reads
     clearly against both backgrounds and is nobody else's accent. */
  --fi-t10: #8a93a6;
  --fi-t20: #2fb3a8;
  --fi-t30: var(--accent);
  max-width: 720px;
  margin: 0 auto;
  padding: 0 16px 40px;
}

/* Light mode needs darker tier inks: the cream page background washes out both the
   grey and the teal at the values that work on near-black. Same override shape the
   rest of rova.css uses (explicit [data-theme] + the OS-preference fallback). */
[data-theme="light"] .fi{ --fi-t10: #6b7280; --fi-t20: #0d8f86; }
@media (prefers-color-scheme: light){
  :root:not([data-theme="dark"]) .fi{ --fi-t10: #6b7280; --fi-t20: #0d8f86; }
}

/* ---------- shared blocks --------------------------------------------------- */
.fi-card{
  background: var(--panel);
  border: 1px solid var(--stroke-soft);
  border-radius: var(--radius);
  padding: var(--fi-pad);
  margin: 0 0 var(--fi-gap);
}
.fi-card.fi-accent{ border-color: var(--stroke); }
/* PROJECTION card on the Founder dashboard. That page shows REAL MONEY -- the accrual ledger, paid
   and pending commission, the 1099 threshold -- so a modelled figure sitting next to it has to be
   impossible to mistake for one. Dashed edge + the "projection" tag in its eyebrow do that without
   shouting. Border only: no backdrop-filter, no shadow, nothing that costs a layer. */
.fi-card.fi-proj{ border-style: dashed; }
.fi-now{
  display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 16px;
}
.fi-now span{
  flex: 1 1 auto; min-width: 96px; text-align: center;
  background: var(--panel-2); border: 1px solid var(--stroke-soft);
  border-radius: var(--radius-sm); padding: 9px 10px;
  font-size: 12px; color: var(--muted); line-height: 1.35;
}
.fi-now strong{ display: block; font-size: 17px; color: var(--text); font-weight: 820; font-variant-numeric: tabular-nums; }

/* THE SPACING FIX. The old page centred every paragraph and let each one pick
   its own max-width/margin inline, which is what read as "off": ragged edges on
   both sides and inconsistent gaps. Body copy is now left-aligned on a single
   measure with one rhythm; only headings and the CTA are centred. */
.fi p{
  margin: 0 0 0.85em;
  max-width: var(--fi-measure);
  line-height: 1.62;
  text-align: left;
  text-wrap: pretty;
}
.fi p:last-child{ margin-bottom: 0; }
/* The one exception to left-aligned copy: a lone badge is a centred ELEMENT, not a line of
   text, and left-aligning it under a centred crown/headline/CTA reads as a misalignment. */
/* The badge opens a new subject (your membership) under copy about earnings, and it had a
   margin-bottom but no margin-top -- so it sat flush against the paragraph above it, which
   ends on margin-bottom:0. 18px is the hero block rhythm (.fi-cta, .fi small, .fi-fine all
   use it), so the pill now breathes like every other block instead of a bespoke number. */
/* The bottom gap used to be a bespoke `.7em` here (11.2px) and is now --pillrow-gap, the token that
   rova.css's shared .pillrow rule uses -- one number for the gap under the pill on both pages
   (views/founders.php renders the same badge). It has to be read as a token rather than left to
   .pillrow, because `.fi p` (0,1,1) out-specifies `.pillrow` (0,1,0) and would silently win.
   Only the deviations this page actually needs stay local: centred, and the 18px hero top margin. */
.fi .fi-pillrow{ text-align: center; max-width: none; margin: 18px 0 var(--pillrow-gap); }
.fi h2, .fi h3{ text-wrap: balance; }
.fi h2{ font-size: clamp(23px, 5.6vw, 31px); line-height: 1.18; margin: 0 0 .4em; letter-spacing: -.015em; }
.fi h3{ font-size: 15px; line-height: 1.3; margin: 0 0 12px; letter-spacing: .01em; }
.fi .fi-eyebrow{
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .12em;
  color: var(--muted); font-weight: 700; margin: 0 0 10px;
}
/* Footnotes under a section (owner 2026-07-30: "where it says your membership, it lacks upper margin
   space from the section above it"). The gap was NOT just too small -- `display:block` was commented out,
   so these were INLINE, and vertical margins do not apply to a non-replaced inline box: the margin-top
   here had never had any effect at all, and neither had the max-width. Restoring block also needs the auto
   side margins, or a max-width box left-aligns itself inside the centred hero. Both <small>s in
   founders_invite.php are footnote paragraphs, so block is right for both. */
.fi small, .fi .fi-fine{
  font-size: 12.5px; line-height: 1.55; color: var(--muted);
  max-width: var(--fi-measure); margin: 18px auto 0;
  /* Fine print is COPY, and the rule above says only headings and the CTA are centred.
     .fi-fine is a <p> so it already inherited that; a <small> is not, so it silently
     centred itself and the same sentence rendered two different ways in one card. */
  text-align: left;
}
.fi strong{ font-weight: 750; }

/* ---------- hero ------------------------------------------------------------ */
.fi-hero{ text-align: center; padding: 26px var(--fi-pad) 24px; }
.fi-hero p{ margin-left: auto; margin-right: auto; }
.fi-crown{ font-size: 42px; line-height: 1; margin-bottom: 6px; }
/* BIGGER, ON OWNER'S REPORT (2026-08-18): "make the 'Rob invited you' whole pill bigger so
   they can see it even without zooming it". It was 13.5px/650 -- BELOW the site's own 16px body
   copy (rova.css body{font:16px/1.55 ...}) for what is the single most personal line on the whole
   landing page. Bumped past body size (16px/700) rather than to some arbitrary bigger number, and
   the avatar/monogram + gap scale with it so the chip reads as one deliberately larger badge, not
   just wider text crammed into the old frame. .fi-by span still ellipsizes on a long handle, and
   .fi .fi-pillrow's max-width:100% keeps the whole chip from ever overflowing a narrow phone. */
.fi-by{
  display: inline-flex; align-items: center; gap: 11px;
  padding: 9px 18px 9px 8px; border-radius: 999px;
  background: var(--panel-2); border: 1px solid var(--stroke);
  font-size: 16px; font-weight: 700; margin-bottom: 16px; max-width: 100%;
}
.fi-by img, .fi-by .fi-by-ph{
  width: 40px; height: 40px; border-radius: 50%; object-fit: cover; flex: none;
  background: var(--accent-grad); color: var(--accent-ink);
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 16px;
}
/* the referrer photo is real media, tapped open in the shared lightbox (app.js) -- same
   affordance the profile photo (.pf-avatar) and a DM photo (.msg-media img) already use. The
   monogram fallback has no photo behind it, so it keeps the default cursor. */
.fi-by img{ cursor: zoom-in; }
.fi-by span{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fi-cta{ display: flex; flex-direction: column; gap: 9px; max-width: 330px; margin: 18px auto 0; }

/* ---------- calculator ------------------------------------------------------ */
.fi-readout{
  display: grid; grid-template-columns: 1fr; gap: 10px; margin: 0 0 16px;
}
@media (min-width: 520px){ .fi-readout{ grid-template-columns: 1fr 1fr; } }
.fi-stat{
  background: var(--panel-2); border: 1px solid var(--stroke-soft);
  border-radius: var(--radius-sm); padding: 13px 14px;
}
.fi-stat.fi-stat-lead{ border-color: var(--stroke); }
.fi-stat-k{ font-size: 11.5px; text-transform: uppercase; letter-spacing: .09em; color: var(--muted); font-weight: 700; }
.fi-stat-v{
  font-size: clamp(24px, 6.4vw, 33px); font-weight: 800; line-height: 1.12; margin-top: 4px;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.fi-stat-lead .fi-stat-v{ color: var(--accent-text); }
.fi-stat-s{ font-size: 12.5px; color: var(--muted); margin-top: 3px; line-height: 1.45; }

.fi-field{ margin: 0 0 16px; }
.fi-field:last-of-type{ margin-bottom: 0; }
.fi-field-top{
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 7px;
}
.fi-field-top label{ font-size: 13.5px; font-weight: 650; }
.fi-field-val{ font-size: 14.5px; font-weight: 800; color: var(--accent-text); font-variant-numeric: tabular-nums; }
/* Provenance marker. Plain = an assumption the visitor sets; .on = a figure Rova has actually
   measured. The distinction is the whole reason the calculator is allowed to open on an
   optimistic sign-up rate: nothing may imply we measured a number we did not. */
.fi-tag{
  display: inline-block; vertical-align: 1px; margin-left: 6px;
  font-size: 9.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .07em;
  padding: 2px 6px; border-radius: 999px; white-space: nowrap;
  color: var(--muted); background: var(--panel-2); border: 1px solid var(--stroke-soft);
}
.fi-tag.on{ color: var(--accent-text); border-color: var(--stroke); }
.fi-assump .fi-tag{ font-size: 9px; }
.fi input[type=range]{
  -webkit-appearance: none; appearance: none; width: 100%; height: 26px;
  background: transparent; margin: 0; cursor: pointer; display: block;
}
.fi input[type=range]::-webkit-slider-runnable-track{
  height: 6px; border-radius: 999px; background: var(--panel-2); border: 1px solid var(--stroke-soft);
}
.fi input[type=range]::-moz-range-track{
  height: 6px; border-radius: 999px; background: var(--panel-2); border: 1px solid var(--stroke-soft);
}
.fi input[type=range]::-webkit-slider-thumb{
  -webkit-appearance: none; appearance: none; width: 22px; height: 22px; border-radius: 50%;
  background: var(--accent-grad); border: 1px solid var(--accent-rim); margin-top: -9px;
  box-shadow: 0 1px 4px rgba(0,0,0,.3);
}
.fi input[type=range]::-moz-range-thumb{
  width: 22px; height: 22px; border-radius: 50%; border: 1px solid var(--accent-rim);
  background: var(--accent); box-shadow: 0 1px 4px rgba(0,0,0,.3);
}
.fi input[type=range]:focus-visible{ outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 999px; }
.fi-scalerow{
  display: flex; justify-content: space-between; font-size: 11.5px; color: var(--muted);
  margin-top: 2px; font-variant-numeric: tabular-nums;
}
.fi-note{ font-size: 12.5px; color: var(--muted); line-height: 1.5; margin-top: 6px; }
.fi-note b{ color: var(--text); font-weight: 700; }

.fi-chips{ display: flex; flex-wrap: wrap; gap: 7px; margin-top: 9px; }
.fi-chip{
  font: inherit; font-size: 12.5px; font-weight: 650; cursor: pointer;
  padding: 6px 12px; border-radius: 999px; color: var(--text);
  background: var(--panel-2); border: 1px solid var(--stroke-soft);
  transition: transform .12s ease, border-color .2s ease;
}
.fi-chip:hover{ border-color: var(--stroke); }
.fi-chip:active{ transform: scale(.95); }
.fi-chip[aria-pressed="true"]{ border-color: var(--accent); color: var(--accent-text); }

/* ---------- chart ----------------------------------------------------------- */
.fi-chart{ margin: 4px 0 2px; }
.fi-chart svg{ display: block; width: 100%; height: auto; overflow: visible; }
.fi-chart .fi-axis{ fill: var(--muted); font-size: 9px; font-weight: 600; }
.fi-chart .fi-grid{ stroke: var(--stroke-soft); stroke-width: 1; }
.fi-chart .fi-band-lbl{ font-size: 8.5px; font-weight: 800; letter-spacing: .04em; }
.fi-legend{ display: flex; flex-wrap: wrap; gap: 12px; margin-top: 8px; font-size: 12px; color: var(--muted); }
.fi-legend i{ display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; }

/* ---------- tier ladder ----------------------------------------------------- */
.fi-ladder{ display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 2px; }
.fi-rung{
  border: 1px solid var(--stroke-soft); border-radius: var(--radius-sm);
  padding: 11px 10px; text-align: center; background: var(--panel-2);
  transition: border-color .25s ease, transform .25s ease;
}
.fi-rung.on{ border-color: var(--accent); transform: translateY(-2px); }
.fi-rung-t{ font-size: 21px; font-weight: 850; line-height: 1; letter-spacing: -.02em; }
.fi-rung.on .fi-rung-t{ color: var(--accent-text); }
.fi-rung-s{ font-size: 11.5px; color: var(--muted); margin-top: 5px; line-height: 1.35; }
/* .now = the tier they are on TODAY (server-rendered, real). .on = where the PROJECTION lands
   (JS, modelled). They are frequently different rungs and must not read as the same thing. */
.fi-rung.now{ border-style: dashed; border-color: var(--stroke); }
.fi-rung-now{ font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); margin-top: 5px; }
.fi-whatif:empty{ display: none; }
.fi-whatif{ border-left: 2px solid var(--accent); padding-left: 10px; margin-top: 10px; }

/* ---------- the road to $100k rail ------------------------------------------ */
.fi-rail{ margin-top: 14px; }
.fi-rail-track{
  position: relative; height: 10px; border-radius: 999px;
  background: var(--panel-2); border: 1px solid var(--stroke-soft); overflow: hidden;
}
.fi-rail-fill{
  position: absolute; inset: 0; border-radius: 999px; background: var(--accent-grad);
  transform-origin: left center; transform: scaleX(0);
  transition: transform .5s cubic-bezier(.22,.9,.3,1);
}
.fi-rail-ticks{
  position: relative; height: 30px; margin-top: 4px; font-size: 10.5px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.fi-rail-tick{ position: absolute; top: 0; transform: translateX(-50%); text-align: center; white-space: nowrap; }
.fi-rail-tick::before{
  content: ""; display: block; width: 1px; height: 5px; margin: 0 auto 3px; background: var(--stroke-soft);
}
.fi-rail-tick.fi-tick-end{ transform: translateX(-100%); text-align: right; }
.fi-rail-tick.fi-tick-end::before{ margin-right: 0; }
.fi-rail-tick.fi-tick-start{ transform: none; text-align: left; }
.fi-rail-tick.fi-tick-start::before{ margin-left: 0; }

/* ---------- assumptions / disclaimer ---------------------------------------- */
.fi-assump{ list-style: none; padding: 0; margin: 0; }
.fi-assump li{
  font-size: 13px; line-height: 1.55; color: var(--muted);
  padding: 8px 0; border-bottom: 1px solid var(--stroke-soft);
  display: flex; gap: 10px; justify-content: space-between; align-items: baseline;
}
.fi-assump li:last-child{ border-bottom: 0; padding-bottom: 0; }
.fi-assump b{ color: var(--text); font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.fi-disc{
  font-size: 12.5px; line-height: 1.6; color: var(--muted);
  border: 1px dashed var(--stroke-soft); border-radius: var(--radius-sm);
  padding: 13px 14px; margin-top: 4px;
}
.fi-disc p{ max-width: none; margin-bottom: .6em; }
.fi-disc p:last-child{ margin-bottom: 0; }

/* ---------- steps ----------------------------------------------------------- */
.fi-steps{ list-style: none; margin: 0; padding: 0; counter-reset: fistep; }
.fi-steps li{
  counter-increment: fistep; position: relative; padding: 0 0 14px 40px;
  font-size: 14.5px; line-height: 1.55; max-width: var(--fi-measure);
}
.fi-steps li:last-child{ padding-bottom: 0; }
.fi-steps li::before{
  content: counter(fistep); position: absolute; left: 0; top: -1px;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--panel-2); border: 1px solid var(--stroke);
  color: var(--accent-text); font-size: 13px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
}

/* =============================================================================
   ONE-SHOT REVEALS. Everything below only takes effect once JS has added
   .fi-motion to the .fi root -- so the no-JS / reduced-motion / unsupported
   render is the finished page, never a blank one.
   ========================================================================== */
.fi-motion .fi-rev{
  opacity: 0; transform: translate3d(0, 14px, 0);
  transition: opacity .5s ease, transform .5s cubic-bezier(.22,.9,.3,1);
}
.fi-motion .fi-rev.in{ opacity: 1; transform: translate3d(0, 0, 0); }
/* will-change is deliberately absent: these settle within half a second and a
   promoted layer that never comes back down is exactly the cost we're avoiding. */

.fi-motion .fi-crown{
  opacity: 0; transform: scale(.72);
  transition: opacity .45s ease, transform .55s cubic-bezier(.2,1.5,.4,1);
}
.fi-motion .fi-hero.in .fi-crown{ opacity: 1; transform: scale(1); }

/* Chart grows up from its own baseline. transform-box:fill-box puts the origin
   on the group's own bounding box, so scaleY(0) collapses it onto the axis.
   JS feature-detects fill-box before adding .fi-motion. */
.fi-motion .fi-plot{
  transform-box: fill-box; transform-origin: 50% 100%;
  transform: scaleY(0);
  transition: transform .85s cubic-bezier(.22,.9,.3,1);
}
.fi-motion .fi-chart.in .fi-plot{ transform: scaleY(1); }
.fi-motion .fi-plot-late{ opacity: 0; transition: opacity .4s ease .55s; }
.fi-motion .fi-chart.in .fi-plot-late{ opacity: 1; }

.fi-motion .fi-rung{ opacity: 0; transform: translate3d(0, 10px, 0); transition: opacity .4s ease, transform .4s cubic-bezier(.22,.9,.3,1), border-color .25s ease; }
.fi-motion .fi-ladder.in .fi-rung{ opacity: 1; transform: translate3d(0, 0, 0); }
.fi-motion .fi-ladder.in .fi-rung:nth-child(2){ transition-delay: .07s; }
.fi-motion .fi-ladder.in .fi-rung:nth-child(3){ transition-delay: .14s; }
.fi-motion .fi-ladder.in .fi-rung.on{ transform: translate3d(0, -2px, 0); }

/* Belt and braces: even if JS somehow adds .fi-motion on a machine that later
   reports reduced motion, kill every transition dead. */
@media (prefers-reduced-motion: reduce){
  .fi-motion .fi-rev,
  .fi-motion .fi-crown,
  .fi-motion .fi-plot,
  .fi-motion .fi-plot-late,
  .fi-motion .fi-rung,
  .fi-rail-fill{ transition: none !important; opacity: 1 !important; transform: none !important; }
  .fi-rail-fill{ transform: scaleX(var(--fi-rail, 0)) !important; }
}

/* ---------- hero: the lede + the three facts, above the fold ----------------
   Added 2026-07-31. The pitch used to put every number below the fold inside the
   calculator, so a visitor's first screen carried a promise with nothing sizing
   it -- and the headline's "everyone you bring" read as recruiting. These three
   tiles are the smallest set that answers "what is one member worth", "what does
   $20k look like" and "how big do I have to be", so the reader can price the
   offer before deciding to scroll. Three across even on the narrowest phone:
   stacking them would push the CTA off the first screen, which is the one thing
   this block exists to prevent. */
.fi-lede{
  max-width: var(--fi-measure); margin: 0 auto; font-size: 15.5px; line-height: 1.62;
}
.fi-facts{ /* sits directly under the headline -- numbers before prose, see the view */
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  margin: 16px auto 16px; max-width: var(--fi-measure); text-align: center;
}
.fi-facts .fi-stat{ padding: 11px 10px; }
/* Reserve TWO label lines on every tile. The row of numbers is the point of this strip, and
   a label that wraps on one tile only ("Each paying member") dropped its own value 16px
   below its neighbours. Equal label height => equal value top => equal sub-copy top, whatever
   the wording later becomes. */
.fi-facts .fi-stat-k{ font-size: 10px; letter-spacing: .07em; line-height: 1.45; min-height: 2.9em; }
.fi-facts .fi-stat-v{ font-size: clamp(19px, 5.2vw, 28px); }
.fi-facts .fi-stat-s{ font-size: 11.5px; margin-top: 4px; line-height: 1.4; }
@media (max-width: 420px){
  .fi-facts{ gap: 6px; }
  .fi-facts .fi-stat{ padding: 9px 7px; }
  .fi-facts .fi-stat-s{ font-size: 11px; }
}

/* The one-line answer to "what is this", above the headline. Centred with the crown,
   chip and headline it belongs to -- it reads as part of the heading block, the same
   exception .fi-pillrow already takes -- and deliberately a touch smaller than the h2
   so it informs without competing with the offer. */
.fi-what{
  max-width: var(--fi-measure); margin: 0 auto 12px; text-align: center;
  font-size: 14.5px; line-height: 1.55; color: var(--muted);
}
.fi-what strong{ color: var(--text); }

/* ---------- narrow phones: stop spending 17% of the screen on gutters ---------
   Owner, 2026-07-31: "make sure we use the whole width of the screen, there's too
   much blank spotty areas on the right side". Measured on his 420pt device: the
   page pads 16px AND the card pads another 20px, so 36pt a side -- 72 of 420, or
   17% of the width -- went to margins before a word was set. That is a desktop
   measure applied to a phone, and it is what leaves the ragged right edge of the
   body copy looking like holes. Tightened to 10 + 15 (25 a side, ~12%), which
   gives the copy ~22pt more to work with and lets the three tiles breathe,
   without letting anything touch the bezel. Desktop is untouched. */
@media (max-width: 480px){
  .fi{ padding-left: 10px; padding-right: 10px; --fi-pad: 15px; }
}

/* ---------- let the lines actually fill ---------------------------------------
   Owner, 2026-07-31: "more letters/words can fit on the right". Measured on a
   420pt phone, the hero copy was leaving up to 65px of empty track at the end of
   a line -- not because the column is narrow but because hyphens were off
   (computed: manual), so one long word that would not fit ("algorithm",
   "permanently", "everything") dropped whole and took the rest of the line's
   space with it. The document already declares lang="en", so automatic
   hyphenation has a dictionary to work with.
   -webkit- prefix is not optional here: Safari and every iOS in-app browser --
   which is exactly where this link gets opened, from a DM -- still needs it.
   hyphenate-limit-chars keeps it tasteful: never break a word under 8 letters,
   and never leave fewer than 4 before or 3 after the break, so it fills the line
   without turning the right edge into a ladder of hyphens. */
.fi p, .fi .fi-what, .fi .fi-fine, .fi small, .fi li{
  /* text-wrap:pretty (set on .fi p above) is the wrong tool for a paragraph this
     narrow: it protects the LAST line from being an orphan by pulling words down,
     and pays for it out of the lines above. Measured on the same 420pt phone with
     hyphens on -- worst dead track per paragraph, lower is fuller:
         auto 33.8 / 29.5 / 33.0   pretty 53.4 / 29.5 / 64.5   balance 95.5 / 63.9 / 87.5
     balance equalises by making every line short, which is right for a heading and
     wrong here; .fi h2/h3 keep it. auto simply fills, which is what was asked for. */
  text-wrap: auto;
  -webkit-hyphens: auto;
          hyphens: auto;
  -webkit-hyphenate-limit-before: 4;
  -webkit-hyphenate-limit-after: 3;
  hyphenate-limit-chars: 8 4 3;
}

/* =============================================================================
   THE MONEY-FLOW DIAGRAM (.fmf) -- MOVED HERE from founders-dash.css on
   2026-08-21, the day the guest invite landing adopted the dashboard's flow
   hero ("our new animation that shows the link and each paying member etc").
   Same reasoning as .fbl's move to rova.css when the sitewide banner adopted
   it: ONE copy, in the sheet every surface that renders the component loads.
   This sheet is that sheet -- views/founders.php links it for founders and
   views/founders_invite.php links it for guests -- where rova.css would tax
   every page on the site for a founders-only component. founders-dash.css
   keeps a stub at the old spot.
   The combined .ffl-* selectors ride along untouched: the finders flow is
   dashboard-only markup, and the dashboard loads this sheet before
   founders-dash.css, so its .ffl-node padding override still lands last.
   MOTION INVENTORY on the invite surface, three loops: 2 traveling dots +
   1 halo ring. (The dashboard's total stays six -- its 3 .ffl dots live on
   with these 3.) All transform/opacity; prefers-reduced-motion (bottom)
   hides every one of them outright -- they are pure decoration.
   ========================================================================== */

/* ------------------------------------------------------------- shared pieces ---- */
/* Node: FLOATING content, no tile. The panel background + 1px border + 14px radius that
   used to box each step were cut on 2026-08-21 (owner: "I don't like the big rectangles
   around each part it looked cleaner without them" -- and, same day, "and the finders
   panel", so .ffl-node sheds its boxes too). The lanes/dots + the padding below carry the
   three-step grouping on their own; do NOT reintroduce a surface here. The padding stays
   for two reasons: it is the inter-step breathing room (the phone stack's step separation
   is gap + this padding now that no border delineates), and .fmf-chip's symmetric -10px
   margin bleed is budgeted against it (see that note). */
.fmf-node,.ffl-node{
  padding:14px 12px;
  display:flex;flex-direction:column;gap:6px;align-items:center;justify-content:center;
  text-align:center;min-width:0;
}
.fmf-cap{font-size:12.5px;color:var(--muted);line-height:1.45;max-width:100%}
.fmf-cap strong,.fmf-cap em{color:var(--text)}
/* The big friendly figure. */
.fmf-big{font-size:clamp(22px,2.6vw,28px);font-weight:900;letter-spacing:-.5px;line-height:1.05;color:var(--text)}
.fmf-big small{font-size:.55em;font-weight:800;color:var(--muted);letter-spacing:0}
.fmf-big.gold{color:var(--accent-text,#f0b429);text-shadow:0 0 22px rgba(240,180,41,.35)}
/* Little pill for a URL or a live figure.
   HORIZONTAL PADDING >= THE CORNER RADIUS (owner, 2026-08-21: the URL "nearly touches
   both edges" of the tap-to-copy pill). border-radius:999px makes the radius half the
   pill's height (~11.5px at this font), so the old 10px inset left the copy glyph and
   the last character/ellipsis visually kissing the curved ends. 13px clears the curve
   and matches the sitewide pill rhythm (.pill and .reflink-act both use 13px, rova.css).
   The ellipsis fires on the inner span at the CONTENT edge, so truncation keeps this
   padding intact -- text never runs into the corner. Does not touch the track fix on
   button.fmf-chip-btn below (minmax(0,max-content)): padding only insets the content
   box; the track still sizes to the URL and shrinks with it.
   THE PADDING-BAND BLEED (same round): at desktop the .fmf hero's 1fr nodes are ~165px
   (680px .wrap, 3 columns + two 44px lanes) leaving ~135px of content box -- less than
   "rovasocial.com/@Rick" or "$107.46/wk right now" plus this padding. The symmetric
   negative margins widen the chip's available space by 20px, capped at its own
   max-content: a chip that fits is pixel-unchanged, a cramped one borrows up to 10px a
   side from the TILE's padding before ellipsizing. 10px stays inside the slimmest tile
   padding (.ffl-node's 12px 10px override, founders-dash.css), so a chip can never leave
   the node's own box (the tile border it once guarded is gone -- nodes float now, see the
   .fmf-node note -- but the geometry budget is unchanged). max-width MUST be
   calc(100% + 20px), not 100%: the percentage
   resolves against the node's CONTENT box, and a plain 100% would re-clamp away exactly
   the width the margins freed. */
.fmf-chip{
  max-width:calc(100% + 20px);margin-left:-10px;margin-right:-10px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:11px;font-weight:600;padding:4px 13px;border-radius:999px;
  border:1px solid var(--stroke-soft);color:var(--muted);background:var(--panel);
}
.fmf-chip.gold{
  color:var(--accent-text,#f0b429);
  border-color:color-mix(in srgb, var(--accent,#f0b429) 45%, transparent);
  background:color-mix(in srgb, var(--accent,#f0b429) 10%, transparent);
  font-weight:800;
}
/* The hero pill as a real tap-to-copy BUTTON (owner ask 2026-08-21; dashboard-only markup --
   the invite page's chip is a plain span, guests have no link to copy). Rides the sitewide
   .copy-swap contract (rova.css): both labels stacked in one grid cell, .is-copied cross-fades
   them, so the pill never changes size on tap. The glyph + press state make it read as tappable. */
button.fmf-chip-btn{
  cursor:pointer;-webkit-tap-highlight-color:transparent;
  font-family:inherit;line-height:normal;
  /* (the padding-band bleed -- negative margins + max-width:calc(100% + 20px) -- lives
     on .fmf-chip above, so the plain gold "$X/wk right now" chip gets it too) */
  /* One explicit track, minmax(0,max-content): sized by the URL (the widest label), clamped by
     the button's max-width, and free to shrink -- without this the stacked cell sized itself to
     the SHORT "Copied" span and ellipsized the URL with room to spare. */
  grid-template-columns:minmax(0,max-content);
  transition:border-color .15s ease, color .15s ease, transform .1s ease;
}
/* STRETCH, NOT CENTER, or the ellipsis never fires (owner report 2026-08-21: the URL sat
   flush against the pill's rounded ends, and the finders pill clipped MID-CHARACTER).
   .copy-swap (rova.css) sets justify-items:center, and a center-justified grid item is
   shrink-to-fit sized -- min(max-content, max(min-content, area)). A nowrap span's
   min-content IS its full text width, so the span could never shrink below the text: it
   overflowed the area, centered, and the button's overflow:hidden hard-clipped it flush
   at the padding box. text-overflow needs the SPAN to be the narrow box, so stretch it
   to the track (which minmax(0,max-content) above already clamps to the button's content
   box) and re-center the text typographically. Measured 2026-08-21: insets went from
   -29..-66px (text under the corner curve) to a constant 13px padding with a real "..."
   at every width. Both spans stretch, so the Copied swap stays size-stable. */
.fmf-chip-btn>span{min-width:0;overflow:hidden;text-overflow:ellipsis;justify-self:stretch;text-align:center}
.fmf-chip-btn:hover{border-color:color-mix(in srgb, var(--accent,#f0b429) 55%, transparent);color:var(--accent-text,#f0b429)}
.fmf-chip-btn:active{transform:scale(.96)}
.fmf-chip-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.fmf-chip-btn.is-copied{
  color:var(--accent-text,#f0b429);
  border-color:color-mix(in srgb, var(--accent,#f0b429) 60%, transparent);
  background:color-mix(in srgb, var(--accent,#f0b429) 10%, transparent);
}
.fmf-cop{font-style:normal;opacity:.7;margin-right:5px}
/* Member cluster: three overlapping heads (one, for the single finder). */
.fmf-crowd{display:inline-flex;align-items:center;height:34px}
/* OPAQUE heads, deliberately (the translucent-token lesson): semi-transparent circles
   overlap into a venn blob instead of reading as three people in a row. */
.fmf-crowd i{
  width:30px;height:30px;border-radius:50%;flex:none;
  border:2px solid var(--panel-2);
  background:linear-gradient(135deg,#6fa8ff,#8f6fe8);
}
.fmf-crowd i + i{margin-left:-10px;background:linear-gradient(135deg,#e88fa8,#d86f6f)}
.fmf-crowd i + i + i{background:linear-gradient(135deg,#78d0a8,#5f9fd8)}
.fmf-crowd.one i{border-color:var(--accent,#f0b429)}
/* REAL FACES variant (owner, 2026-08-21): the cluster renders real members through
   avatar_img() -- photos, video loops, or monogram discs -- overlapped like the generic
   circles, plus a "+N" chip for the rest. Sizing overrides .avatar.sm so the cluster keeps
   the generic version's exact geometry. */
.fmf-crowd.has-real > *{flex:none;position:relative}
.fmf-crowd.has-real > * + *{margin-left:-10px}
.fmf-crowd.has-real .avatar{width:30px;height:30px;min-width:30px;font-size:13px;
  border:2px solid var(--panel-2);box-shadow:none}
/* the finders "friend" node keeps its gold ring on the real face, same as the generic circle had */
.fmf-crowd.one.has-real .avatar{border-color:var(--accent,#f0b429)}
.fmf-more{display:inline-flex;align-items:center;justify-content:center;
  height:30px;min-width:30px;padding:0 8px;border-radius:999px;
  background:var(--panel);border:2px solid var(--panel-2);
  font-size:10.5px;font-weight:800;font-style:normal;color:var(--muted);z-index:1}
/* Lane + traveling dot. The lane columns are FIXED-width (44px / 34px), which is
   what lets the dot animate transform over a known distance instead of `left`. */
.fmf-lane,.ffl-lane{
  position:relative;align-self:center;height:2px;
  background:linear-gradient(90deg,transparent,var(--stroke-soft) 30%,var(--stroke-soft) 70%,transparent);
}
.fmf-lane.is-gold,.ffl-lane.is-gold{
  background:linear-gradient(90deg,transparent,color-mix(in srgb, var(--accent,#f0b429) 55%, transparent) 30%,
    color-mix(in srgb, var(--accent,#f0b429) 55%, transparent) 70%,transparent);
}
.fmf-dot{
  position:absolute;top:-3px;left:-2px;width:8px;height:8px;border-radius:50%;
  background:#6fa8ff;box-shadow:0 0 10px rgba(111,168,255,.65);opacity:0;
  animation:fmfGo 4.5s cubic-bezier(.4,0,.6,1) infinite;
}
.fmf-dot.gold{background:var(--accent,#f0b429);box-shadow:0 0 10px rgba(240,180,41,.7)}
.fmf-dot.f2{animation-delay:2.25s}
@keyframes fmfGo{
  0%,14%{transform:translateX(-4px);opacity:0}
  22%{opacity:1}
  46%{opacity:1}
  56%,100%{transform:translateX(44px);opacity:0}
}

/* ------------------------------------------------------------------ .fmf hero ---- */
.fmf{display:grid;grid-template-columns:1fr 44px 1fr 44px 1fr;gap:8px;align-items:stretch;margin:2px 0 14px}
/* Gold halo around the "you" spot: a ring + one breathing pulse. On the dashboard it
   wraps the founder's own avatar; on the invite page it wraps the .fmf-ghost below. */
.fmf-halo{position:relative;display:inline-flex;border-radius:50%;padding:3px;
  border:2px solid var(--accent,#f0b429);box-shadow:0 0 18px rgba(240,180,41,.35)}
.fmf-halo::after{content:"";position:absolute;inset:-2px;border-radius:50%;
  border:2px solid var(--accent,#f0b429);opacity:0;pointer-events:none;
  animation:fmfHalo 3.6s ease-out infinite}
@keyframes fmfHalo{0%,55%{transform:scale(.85);opacity:0}62%{opacity:.7}90%,100%{transform:scale(1.45);opacity:0}}
/* INVITE-ONLY: the prospect has no account yet, so the "You" node gets a gold
   silhouette disc instead of an avatar -- same 34px box avatar_img('sm') fills on
   the dashboard, so the halo's geometry is identical on both surfaces. */
.fmf-ghost{
  width:34px;height:34px;border-radius:50%;flex:none;
  display:inline-flex;align-items:center;justify-content:center;
  font-size:17px;line-height:1;
  color:#0d0c09;background:linear-gradient(180deg,#ffdd8f,#f0b429);
}

/* -------------------------------------------------------------- phones (.fmf) ---- */
@media (max-width:700px){
  .fmf,.ffl{grid-template-columns:1fr}
  .fmf-lane,.ffl-lane{width:2px;height:30px;margin:0 auto;align-self:auto;
    background:linear-gradient(180deg,transparent,var(--stroke-soft) 30%,var(--stroke-soft) 70%,transparent)}
  .fmf-lane.is-gold,.ffl-lane.is-gold{
    background:linear-gradient(180deg,transparent,color-mix(in srgb, var(--accent,#f0b429) 55%, transparent) 30%,
      color-mix(in srgb, var(--accent,#f0b429) 55%, transparent) 70%,transparent)}
  .fmf-dot{left:-3px;top:-2px;animation-name:fmfGoV}
  @keyframes fmfGoV{
    0%,14%{transform:translateY(-4px);opacity:0}
    22%{opacity:1}
    46%{opacity:1}
    56%,100%{transform:translateY(30px);opacity:0}
  }
}

/* ------------------------------------------------------ reduced motion (.fmf) ---- */
@media (prefers-reduced-motion: reduce){
  .fmf-dot{animation:none;opacity:0}
  .fmf-halo::after{animation:none;opacity:0}
  button.fmf-chip-btn{transition:none}
}
