/* Roboto ships no arrow glyphs (U+2190-21FF) and no check mark (U+2713).
   Without this, each browser picks its own substitute and the arrow in a
   button looks different per platform. Pull just those ranges from a known
   system face so the choice is deterministic. Roboto is otherwise untouched. */
@font-face {
  font-family: 'GF Symbols';
  src: local('Helvetica Neue'), local('Helvetica'), local('Arial'),
       local('Segoe UI Symbol'), local('Segoe UI'),
       local('Liberation Sans'), local('DejaVu Sans');
  unicode-range: U+2190-21FF, U+2713, U+2794-27BF, U+2B00-2BFF;
}

/* ============================================================
   GlobalFinex Design System — typefaces
   Roboto, self-hosted as WOFF and subset to latin + latin-ext
   plus the symbols this site uses. Seven faces, 315KB in total,
   against 823KB for the Aptos set they replace.

   Weights map onto the previous Aptos cuts, with two gaps closed:
   Aptos had no 500 or 600, so those were being synthesised by the
   browser. Roboto ships both, so every weight the stylesheet asks
   for now resolves to a real file.

   Roboto Mono was not in the supplied family, so --font-mono falls
   through to the system monospace stack.
   ============================================================ */
@font-face { font-family:'Roboto'; src:url('fonts/Roboto-Light.woff') format('woff'); font-weight:300; font-style:normal; font-display:swap; }
@font-face { font-family:'Roboto'; src:url('fonts/Roboto-Regular.woff') format('woff'); font-weight:400; font-style:normal; font-display:swap; }
@font-face { font-family:'Roboto'; src:url('fonts/Roboto-Italic.woff') format('woff'); font-weight:400; font-style:italic; font-display:swap; }
@font-face { font-family:'Roboto'; src:url('fonts/Roboto-Medium.woff') format('woff'); font-weight:500; font-style:normal; font-display:swap; }
@font-face { font-family:'Roboto'; src:url('fonts/Roboto-SemiBold.woff') format('woff'); font-weight:600; font-style:normal; font-display:swap; }
@font-face { font-family:'Roboto'; src:url('fonts/Roboto-Bold.woff') format('woff'); font-weight:700; font-style:normal; font-display:swap; }
@font-face { font-family:'Roboto'; src:url('fonts/Roboto-ExtraBold.woff') format('woff'); font-weight:800; font-style:normal; font-display:swap; }

/* ============================================================
   GlobalFinex B2B — Brand Design System
   ============================================================ */

:root {
  /* ---------- GlobalFinex Design System tokens ---------- */
  /* Primary ramp */
  --blue-50:  #F4F5FC;  --blue-100: #E8EBF8;  --blue-200: #C6CDEE;
  --blue-300: #A4B0E4;  --blue-400: #6074CF;  --blue-500: #1C39BB;
  --blue-600: #18309F;  --blue-700: #142883;  --blue-800: #111953;
  --blue-900: #0B174B;
  /* Accent — cyan (Pace) */
  --cyan-100: #C1F5FC;  --cyan-500: #63E7F8;  --cyan-700: #45A2AE;
  --cyan-900: #2D6870;  --cyan-ink: #111953;
  /* Accent — magenta (Flow) */
  --magenta-100: #FCD9EB; --magenta-500: #E9007B; --magenta-700: #A30056;
  --magenta-900: #690037; --magenta-ink: #111953;
  /* Semantic */
  --red-100: #FCE7E4; --red-500: #CD2526; --red-700: #981819;
  --green-100: #C9FDCF; --green-500: #20873C; --green-700: #14632A;
  --orange-100: #FCE8DE; --orange-500: #DD6300; --orange-700: #823B0C;
  --navy: #0C1F3A;

  /* ---------- Mapped onto the names this stylesheet already uses ---------- */
  --gf-blue:       var(--blue-500);
  --gf-blue-dark:  var(--blue-600);
  --gf-blue-deep:  var(--blue-700);
  --gf-blue-ink:   var(--blue-900);
  --gf-royal:      var(--blue-500);
  --gf-royal-soft: var(--blue-400);
  --gf-cyan:       var(--cyan-500);

  --ink:       #000000;
  --ink-2:     #4A4F66;
  --muted:     #767B93;
  --line:      var(--blue-200);
  --line-soft: var(--blue-100);
  --soft:      var(--blue-50);
  --softer:    #FAFBFE;
  --white:     #FFFFFF;

  --green: var(--green-500);
  --amber: var(--orange-500);

  /* Type */
  --font-display: 'GF Symbols', 'Roboto', system-ui, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-sans:    'GF Symbols', 'Roboto', system-ui, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-serif:   'GF Symbols', 'Roboto', system-ui, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-mono:    ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* One tracking value for every uppercase micro-label — eyebrows, chips,
     tags, column and field labels. Five values had drifted apart (0.08em to
     0.14em) because each component set its own. Do not hardcode letter-spacing
     on an uppercase label anywhere in this file; use this token.
     Table and matrix column heads (0.82–0.92rem) are a separate species and
     keep their own tighter tracking — see round 2026-09-15a. */
  --track-label: 0.12em;

  /* The same tracking does not read the same on a dark ground. Light glyphs
     bloom outward into the background, the strokes visually thicken and the
     gaps between letters close up, so 0.12em looks tighter on navy than on
     white — more so at weight 700, where there is more stroke to bloom.
     This is the optical compensation, +8%, and it is a token for the same
     reason --track-label is: no uppercase label may hardcode letter-spacing.
     Currently carried by .eyebrow only. Chips, tags and .band-tag on dark
     bands still take --track-label; widening it to the whole micro-label
     family on dark is a separate round. */
  --track-label-dark: 0.13em;

  /* Layout */
  --container: 1240px;
  --container-narrow: 880px;
  --read-progress-h: 4px;
  --radius-sm: 6px;
  --radius:    10px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-pill: 999px;

  /* Shadows */
  --shadow-sm: 0 1px 2px rgba(11,23,75,.06), 0 1px 1px rgba(11,23,75,.04);
  --shadow:    0 4px 12px rgba(11,23,75,.08), 0 2px 4px rgba(11,23,75,.05);
  --shadow-lg: 0 12px 32px rgba(11,23,75,.12), 0 4px 8px rgba(11,23,75,.06);
  --shadow-ambient: 0 0 20px rgba(11,23,75,.16);
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.6;
  color: var(--ink);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'cv11', 'ss01', 'ss03';
}
img { max-width: 100%; display: block; }
a { color: var(--gf-royal); text-decoration: none; }
a:hover { color: var(--gf-royal-soft); }
button { font-family: inherit; cursor: pointer; }
:focus-visible { outline: 2px solid var(--gf-royal); outline-offset: 2px; border-radius: 6px; }

/* ---------- Typography ---------- */
h1, h2, h3, h4, h5 {
  font-family: var(--font-sans);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.022em;
  color: var(--ink);
  margin: 0 0 0.5em;
  text-wrap: balance;
}
h1 { font-size: clamp(2.4rem, 4.6vw, 4.2rem); letter-spacing: -0.03em; font-weight: 600; }
h2 { font-size: clamp(1.9rem, 3vw, 2.8rem); letter-spacing: -0.025em; }
h3 { font-size: 1.4rem; letter-spacing: -0.015em; }
h4 { font-size: 1.06rem; letter-spacing: -0.01em; }
p  { margin: 0 0 1em; text-wrap: pretty; }
.lede { font-size: clamp(1.1rem, 1.4vw, 1.32rem); color: var(--ink-2); line-height: 1.55; max-width: 60ch; }
strong { font-weight: 600; color: var(--ink); }
.muted { color: var(--muted); }
.center { text-align: center; }
.mt-0 { margin-top: 0 !important; }
.mt-2 { margin-top: 1rem; } .mt-3 { margin-top: 1.5rem; } .mt-4 { margin-top: 2rem; } .mt-5 { margin-top: 3rem; }
.mb-2 { margin-bottom: 1rem; } .mb-3 { margin-bottom: 1.5rem; } .mb-4 { margin-bottom: 2rem; }

/* ------------------------------------------------------------
   EYEBROW — the small uppercase label above a heading.

   One definition, one colour rule. Do not set eyebrow colour
   anywhere else in this file: it was previously spread across
   fourteen rules and each patch broke the one before it.

     light surface     -> --gf-blue,  --track-label
     dark or coloured  -> --gf-cyan,  --track-label-dark
     themed hero       -> #fff (the chip shape is set with the hero)
     .eyebrow-muted    -> --muted, on light surfaces

   Surface drives two properties now, not one. The dark rule below is the
   only place an eyebrow's tracking is changed, and it sits with the colour
   it travels with so the pair cannot drift apart.

   ROUND 2026-09-15: the light ink is no longer a constant. A product page
   tints it with its own accent — Flow magenta, Pace teal — so the label above
   a heading reads as part of the product rather than as site chrome. Colour
   now travels the way tracking already does: the surface picks one of two
   inks, and a page may replace either ink by setting the token that surface
   reads. Both fall back to the site value, so an untinted page is unchanged
   and a theme that sets neither token behaves exactly as it did before.

     --eyebrow-ink-light   light surfaces     -> falls back to --gf-blue
     --eyebrow-ink-dark    dark and coloured  -> falls back to --gf-cyan

   On a product page the light ink is themed and the dark ink is decided per
   surface, because "dark" is not one ground there. See the product-accent
   block below.
   ------------------------------------------------------------ */
.eyebrow {
  /* Surface sets these once; letter-spacing, the .center compensation and the
     colour all read them, so surface and label can never disagree. */
  --eyebrow-track: var(--track-label);
  --eyebrow-ink: var(--eyebrow-ink-light, var(--gf-blue));
  display: inline-block;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: var(--eyebrow-track);
  text-transform: uppercase;
  color: var(--eyebrow-ink);
  margin-bottom: 14px;
}
.eyebrow-muted { color: var(--muted); }

/* ---- The two product accents ----
   Declared as the surface's ink rather than as a colour on .eyebrow, so the
   dark rule below still wins on a navy band without having to out-specify a
   body-level selector. The outcome pages carry the same two accents under
   their own theme names and take the same inks; combined.html is deliberately
   absent from the two rules below — it shows both products, so neither accent
   can speak for its eyebrows and they stay blue on light and cyan on navy.
   Its HERO is a different matter and is not exempt: the hero rule further down
   is keyed on the presence of a theme, not on which one, and combined's hero
   wash is magenta-into-teal — a product wash like any other, where white is
   the right ink for the same reason. Its hero runs three labels rather than
   two, one lead and two peers, and the step below holds for both peers.

   LIGHT is one ink per page: the ramp step that reads dark on white, index
   700 for both ramps.

     Flow / Working Capital  --lv-method  magenta-700  7.80:1 on white
     Pace / EBITDA           --lv-timing  cyan-900     6.31:1 on white

   DARK is one ink per SURFACE, not per page. A product page has three dark
   grounds and they are not interchangeable — two of them are the product's
   own colour, which is exactly what a product-coloured label cannot sit on.
   One ink for all three was the mistake of the round before this one: it put
   magenta-100 on the hero, which cleared the contrast bar and still read as
   dusty pink rather than as Flow.

     .page-hero     the themed wash, magenta or teal   -> #fff
     .section-cool  navy, the one ground that is not
                    the product's colour               -> --gf-cyan
     .callout       the product's own wash             -> the product's bright

   White on the hero is the only ink that is unambiguous on both washes, and
   it is the strongest available on either: 13.95:1 where the Flow eyebrow
   sits. It also retires a dependency — cyan on the PACE hero was only passing
   because of the 28% black that .page-hero::after lays over the wash (4.30:1
   without it), so removing that overlay no longer breaks a label.

   The navy band keeps the site cyan. It is the site's dark-surface eyebrow
   everywhere else, the ground is not the product's colour, and cyan-500 is
   Pace's own bright step in any case — 11.25:1 on navy.
   ------------------------------------------------------------------------ */
/* 2026-09-16, BLUE PASS: eyebrows and links return to the site ramp.
   Light-surface eyebrows are primary blue, navy-band eyebrows stay cyan,
   and every themed link override is gone. Kept as a note rather than a
   silent deletion because the reasoning below it was the record. */
/* REMOVED: the two rules that tinted --eyebrow-ink-light with the product
   accent (magenta-700 / cyan-900). Light-surface eyebrows now fall through
   to --gf-blue, 8.93:1 on white, on every themed page. */

/* TWO PAGES OFF THE RAMP STEP. flow.html takes the bright step rather than the
   dark one for its light-surface eyebrows, by request. It stays inside the
   rule above it -- a page replaces an ink by setting the token its surface
   reads -- so the hero keeps #fff and the navy band keeps cyan; only the
   light surfaces move. Keyed on the page, not the theme, because
   globalfinex-design-system.html carries data-theme="lever-method" too and
   must keep showing the system value. Equal specificity to the rule above,
   so it wins on source order and must stay after it.

   SECOND PAGE ADDED 2026-09-16: outcome-working-capital.html, so that the
   Working Capital page reads at the same step as the Flow page it sits
   beside. It shares Flow's theme already -- outcome-wc and lever-method are
   paired in every rule in this file -- and this block is the only thing that
   was holding the two pages apart. The page list is deliberately enumerated
   rather than widened to the theme, for the design-system reason above.
   Three light-surface eyebrows on that page move; its hero eyebrow stays
   #fff and its navy-band eyebrow stays cyan, both set by surface.

   CONTRAST, DECLARED: magenta-500 on white is 4.43:1. An eyebrow is 13px at
   700, which is not large text, so the bar is 4.5:1 and this misses it. The
   700 step above exists because it clears at 7.80:1. Accepted deliberately
   for flow.html on 2026-09-16, and extended to outcome-working-capital.html
   the same day with the same caveat: this is a named two-page exception, not
   a pattern to copy to a third. */
/* REMOVED with the rule above: the named two-page exception that took
   --magenta-500 at 4.43:1, under the 4.5:1 floor. Both pages now read
   --gf-blue at 8.93:1 and the exception is retired, not re-homed. */

/* THE REST OF THE PAGE, SAME STEP. Four more places take the bright step,
   asked for together with the eyebrows above. Two of them were already
   magenta and only move 700 -> 500; the button is the one that leaves blue.
   All four hang off the page marker rather than the theme, for the same
   reason the rule above does, and all four are written to out-specify or
   out-order the site rule they replace -- so this block must stay at the end
   of the eyebrow section, after every rule it overrides.

   WHAT RENDERS ON WHICH PAGE: all four render on flow.html. On
   outcome-working-capital.html only the button does -- that page has no
   subnav, no prose hyperlink inside a .section paragraph and no feature-list
   today. The other three are carried there for parity, so that adding any of
   those elements later lands on the page's own colour rather than reverting
   it to the site blue. Two of the four render nowhere on that page as it
   stands; that is intended, and stated here rather than left to be
   rediscovered.

   WHAT IS DELIBERATELY NOT INCLUDED:
     .ghost-on-dark   the second callout button is transparent on the magenta
                      wash and its label must stay #fff. Without the :not()
                      below, this rule out-specifies it and paints magenta on
                      magenta. Both pages have one.
     .section-cool    LINKS on the navy band are held at cyan by a
                      higher-specificity rule further down, and stay there.
                      The band's EYEBROW is a separate mechanism and does
                      move on one page -- see 5 below. The two are not the
                      same decision and the link rule is untouched.
     header / footer  chrome, not page content, and the footer is navy.

   CONTRAST, DECLARED: every value below is 4.43:1 -- magenta-500 on white for
   the link, the anchor highlight and the button label, white on magenta-500
   for the numerals. The bar is 4.5:1 and none of them clear it. Three of the
   four are moving DOWN from magenta-700 at 7.80:1, which did clear it. Same
   decision as the eyebrows, taken on 2026-09-16, same caveat: named pages
   only. */

/* 2 - the anchor highlight. REMOVED 2026-09-16: back to the site blue. */

/* 3 - prose hyperlinks. REMOVED 2026-09-16: back to --gf-blue, and
   --gf-blue-deep on hover, via the site link rule. */

/* 4 - the feature-list numerals. REMOVED 2026-09-16: the numerals join the
   eyebrows and links on the site ramp. Base .fl-icon is --gf-blue on #fff,
   and the themed overrides further down this sheet are removed too. */

/* 1 - the white CTA on the themed washes, hero and callout both. The ghost
   button beside it is excluded by name, not by accident.

   The label takes 700, not the 500 the rest of this block takes: changed by
   request on 2026-09-16, and it is the one element here that clears the
   contrast bar -- magenta-700 on the white button face is 7.80:1. Hover goes
   one step darker again, the way the blue it replaced did. This is the one
   rule in the block that renders on both pages: two buttons on flow.html,
   two on outcome-working-capital.html. */
/* REMOVED 2026-09-16: the CTA label returns to the site blue (--blue-600,
   --gf-blue-deep on hover). Asked for as part of the anchor pass. */

/* 1b - THE SAME BUTTON, ON PACE. pace.html carried no page marker at all, so
   both its .btn-light CTAs -- the hero "Contact us" and the callout "See
   Flow: ePayment" -- fell through to the site default and rendered
   --gf-blue on a teal wash, while flow.html and
   outcome-working-capital.html each took their own colour. Pace was the odd
   page out rather than a deliberate hold-out. Marker added and rule added
   here on 16 September 2026.

   THE STEP IS NOT THE MIRROR OF FLOW'S, AND THAT IS ON PURPOSE. The ramps
   pair off cleanly -- cyan 500/700/900 against magenta 500/700/900 -- so the
   literal mirror of Flow's magenta-700 would be cyan-700. It is not used:
   cyan-700 on the white button face is 2.99:1 and fails badly. cyan-900 is
   the step that works, and it is --lv-timing, the colour this theme already
   names as Pace's own.

   CONTRAST, DECLARED: cyan-900 on white is 6.31:1. The bar for a button
   label is 4.5:1 and this clears it. Stated plainly because the block
   directly above is the opposite case -- a named exception that misses the
   bar at 4.43:1 and is held to two enumerated pages. This rule is NOT part
   of that exception and does not extend it. Pace joins the page-keyed
   button colour on its own terms, passing.

   HOVER LEAVES THE RAMP, THE ONE PLACE THIS DIFFERS. Flow hovers 700 -> 900.
   Pace starts at 900 and the cyan ramp has no step below it, so hover takes
   --cyan-ink, the ramp's own ink token, to keep the darken-on-hover
   affordance the blue it replaced had. Deliberate, not an oversight.

   .ghost-on-dark is excluded by name for the same reason it is excluded
   above: pace.html's callout has one, it is transparent on the teal wash and
   its label must stay #fff. Without the :not() this rule would paint the
   product colour onto the product's own wash. */
/* REMOVED 2026-09-16 with Flow's equivalent above, so the three pages stay
   consistent with each other. Pace's cyan-900 passed at 6.31:1; it is
   removed for system consistency, not because it failed. */

/* 5 - the navy band eyebrow, one page only. outcome-working-capital.html
   takes --magenta-500 on .section-cool, where the site rule gives the band
   --gf-cyan. Asked for on 16 September 2026, to bring the page's last
   light-step hold-out onto the same step as the rest of it.

   This overturns, for this one band, the rule argued near the top of this
   file: the navy band keeps the site cyan, because navy is the one dark
   ground that is NOT the product's own colour. flow.html already made the
   same move at #card-rails, with the same figure, and this is the second
   instance rather than a new idea.

   Scoped to the page, not to an id, because this section has no anchor of
   its own -- flow.html could key on #card-rails and this page cannot. The
   page has one .section-cool, so the selector reaches exactly one eyebrow.
   It sets the token the dark-surface rule reads, so it does not need to sit
   after that rule.

   CONTRAST, DECLARED: magenta-500 on navy is 3.73:1, under the 4.5:1 floor
   for small text. --gf-cyan is 11.25:1 there. Chosen with the figure known,
   same as its counterpart on flow.html.

   NOT the same rule as the dots in Flow's band, which take the same value
   and pass, because a non-text graphic is held to 3:1. Recorded in
   TODO-design-system.md so the two are not conflated. */
/* REMOVED: the navy band returns to --gf-cyan, 11.25:1, the value the
   surface rule already gives it. magenta-500 on navy was 3.73:1. */

/* The themed hero. Overrides the generic dark ink for every themed page. */
body[data-theme] .page-hero .eyebrow { --eyebrow-ink-dark: #fff; }

/* The themed callout, whose ground IS the product's wash.
   NOTE, and it is a real one: the product's bright step on the product's own
   wash is magenta-500 on #7A0C4A → #A30056, which measures 2.40:1 and 1.76:1.
   That is below the 4.5:1 an eyebrow needs and below the 3:1 a non-text
   graphic needs. No eyebrow sits in a callout on any of the four themed pages
   today, so this renders nowhere — it is a rule waiting for a first use, and
   the first use will not be legible. Flagged, declared as asked, and left
   here rather than buried in a commit message. Pace's equivalent is cyan-500
   on its teal wash and does not have the problem. */
/* RESOLVED 2026-09-16. The callout wash is now blue-into-accent, the same
   family as the hero, so the callout eyebrow takes the hero's ink: #fff.
   That answers the problem the comment above describes — the product's
   bright step on the product's own wash, 2.40:1 and 1.76:1 — rather than
   leaving it waiting for a first use that would not be legible. */
body[data-theme] .callout .eyebrow { --eyebrow-ink-dark: #fff; }

/* Dark and coloured surfaces: cyan, and one step more tracking to hold the
   same optical rhythm as the light-surface eyebrow on white. */
.hero .eyebrow,
.page-hero .eyebrow,
.article-hero .eyebrow,
.section-cool .eyebrow,
.section-dark .eyebrow,
.callout .eyebrow {
  --eyebrow-track: var(--track-label-dark);
  --eyebrow-ink: var(--eyebrow-ink-dark, var(--gf-cyan));
}

/* Themed heroes used to carry the label as a chip, which needed white text to
   sit on the pill. The chip is gone and every hero eyebrow is now plain text,
   so a themed hero takes the same cyan as an unthemed one and this rule has
   nothing left to say. The paired second label (.eyebrow-alt) is the only
   hero eyebrow that still differs, and it is handled with .eyebrow-row. */

/* Centring a tracked label needs the trailing letter-space taken back.
   letter-spacing adds its space after EVERY character, the last one
   included. Left-aligned that sliver hangs off the right end and nothing
   references it, which is why it has never mattered anywhere else. In a
   centred box the browser centres the glyphs PLUS the trailing space, so
   the word lands half a tracking unit left of true centre: 13px x 0.12em
   = 1.56px, so 0.78px left. The h2 beneath it tracks -0.02em and lands
   0.42px right, so the label and its heading miss each other by ~1.2px
   in opposite directions and the eye reads it as loose tracking rather
   than as off-centre.

   Pulling the right edge in by one tracking unit widens the box to the
   right by exactly the trailing space and puts the glyphs back on centre.
   It reads --eyebrow-track rather than --track-label directly, so a centred
   eyebrow on a dark band compensates for the 0.13em it actually carries
   rather than for the 0.12em it would have had on white. */
.section .eyebrow.center,
.eyebrow.center {
  display: block;
  text-align: center;
  margin-right: calc(var(--eyebrow-track) * -1);
}

/* Serif accent (used very sparingly) */
.serif { font-family: var(--font-serif); font-weight: 400; letter-spacing: -0.01em; }

/* Mono accent */
.mono { font-family: var(--font-mono); font-size: 0.8em; letter-spacing: 0; }

/* Highlight */
.accent { color: var(--gf-royal); font-style: italic; font-family: var(--font-serif); font-weight: 400; }

/* ---------- Layout ---------- */
.container { width: 100%; max-width: var(--container); margin: 0 auto; padding: 0 28px; }
.container-narrow { max-width: var(--container-narrow); }
.section { padding: 96px 0; position: relative; }
/* Anchor targets clear both sticky bars plus a 24px breath, so a subnav jump
   lands on the section title rather than behind the chrome. Both offsets are
   measured at runtime. script.js reads this same computed value back to decide
   which chapter the subnav highlights, so the landing point and the highlight
   trigger can never disagree — they used to, by 23px, which lit the previous
   chapter on every jump. The fallbacks only apply in the sliver before
   script.js measures the real heights; 49px was the subnav's height before it
   gained its current padding and had drifted 15px stale. */
.section[id] { scroll-margin-top: calc(var(--header-h, 69px) + var(--subnav-h, 64px) + 24px); }
/* The gap above and below a final-CTA callout card.

   ROUND 2026-09-16e set padding-top to 0 on the reasoning that the
   preceding section's 96px padding-bottom already carried the gap. That
   was wrong, and the error is worth recording because it is easy to
   repeat: --soft is --blue-50 on a white body, so a .section-soft's
   padding-bottom sits INSIDE the tinted band. It is not white space
   above the card. Setting padding-top to 0 put the card's top edge
   directly on the band edge.

   ROUND 2026-09-16f: 80px top and bottom, so the white above the card
   matches the white below it. On the 18 pages where a band edge defines
   the gap — a .section-soft or .section-cool above, or the callout's own
   section carrying the band — that is exactly 80/80.

   The exception below is for the 7 pages where a plain white section
   meets a plain white callout section. There is no band edge there, so
   the previous section's 96px IS the visible gap and another 80 on top
   would make it 176. Those keep 96, which is the site's section number
   and near enough to 80 that the two readings do not diverge.

   The :not() on the right of the adjacency is load-bearing: blog.html
   follows a plain section with a callout section that is itself soft, so
   a bare padding-top: 0 there would land the band edge on the card — the
   same defect 16e introduced, in the one place the left-hand test misses.

   The card's own 64px of padding is untouched throughout: these rules
   move where the callout sits, not how dense it is. */
.section:has(> .container > .callout) { padding-top: 80px; padding-bottom: 80px; }
.section:not(.section-soft):not(.section-cool)
  + .section:not(.section-soft):not(.section-cool):has(> .container > .callout) { padding-top: 0; }
.section:has(> .container > .callout) > .container > .center.muted { margin-bottom: 32px; }

/* ============================================================
   PER-PAGE LEVER / OUTCOME THEME
   ============================================================ */
/* Lever 1 / Working Capital — royal indigo accent */
body[data-theme="lever-method"],
body[data-theme="outcome-wc"] {
  --theme-accent: var(--gf-royal);
  --theme-accent-deep: #312E81;
  --theme-tint-50: #EEF2FF;
  --theme-tint-100: #E0E7FF;
}
/* Lever 2 / EBITDA — deep brand blue accent */
body[data-theme="lever-timing"],
body[data-theme="outcome-ebitda"] {
  --theme-accent: var(--gf-blue);
  --theme-accent-deep: var(--gf-blue-deep);
  --theme-tint-50: #EFF6FF;
  --theme-tint-100: #DBEAFE;
}

/* The accent stripe that used to sit here is gone. The 2026-09-16 round
   removed it site-wide with a `border-top: 0` override at the end of the
   sheet; the wash consolidation deleted the four themed declarations it was
   overriding, and this base one with them, so the override could go too.
   This was the last stripe on the site. Base .page-hero sets no border-top,
   so nothing brings it back. */
body[data-theme] .page-hero::after {
  background: linear-gradient(95deg,
    color-mix(in oklab, var(--theme-accent) 55%, var(--gf-blue-deep)) 0%,
    rgba(15,30,80,0.15) 60%,
    rgba(15,30,80,0) 100%);
}
/* A themed hero's eyebrow used to be a chip, declared here as an accent fill
   that the pattern-background pass further down then quietly replaced with a
   translucent white, so the accent never actually rendered. The chip is gone
   entirely now — every hero eyebrow on the site is plain text — and nothing
   themed-specific is left to declare. Size, colour and tracking all come from
   the base .eyebrow above, so a hero label reads identically to one in the
   body of the page. */

/* Themed subnav REMOVED 2026-09-16. Flow and Pace used to hover and
   highlight in their own accent; primary blue is now the value everywhere,
   not just the default. */

/* Themed accent in cards / quotes */
body[data-theme] .quote { border-left-color: var(--theme-accent); }
body[data-theme] .quote::before { color: color-mix(in oklab, var(--theme-accent) 55%, transparent); }
body[data-theme] .ph-tag { background: var(--theme-accent); color: #fff; }

/* Themed feature-list bullets */
/* REMOVED 2026-09-16: numerals stay on the site blue from base .fl-icon. */

/* Themed primary button stays brand blue — but ghost on hero gets accent border on hover */
body[data-theme] .hero .btn-ghost:hover { box-shadow: inset 0 0 0 1.5px var(--theme-accent); }

/* Themed callouts (the bottom banner) get the accent on the chip / border */
body[data-theme] .callout {
  background: linear-gradient(155deg, var(--theme-accent-deep), var(--gf-blue-deep));
}

.section-soft { background: var(--soft); }
.section-cool { background: var(--gf-blue-ink); color: rgba(255,255,255,0.86); }
.section-cool h1, .section-cool h2, .section-cool h3, .section-cool h4 { color: #fff; }
.section-cool .muted { color: rgba(255,255,255,0.6); }
.section-cool a:not(.btn) { color: var(--gf-cyan); }

.grid { display: grid; gap: 24px; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 880px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
  .section { padding: 64px 0; }
}

.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 64px;
  align-items: center;
}
.two-col.reverse > *:first-child { order: 2; }
@media (max-width: 880px) {
  .two-col { grid-template-columns: 1fr; gap: 32px; }
  .two-col.reverse > *:first-child { order: 0; }
}

/* ============================================================
   HEADER / NAV
   ============================================================ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255,255,255,0.86);
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  border-bottom: 1px solid var(--line);
}
.site-header .nav {
  display: flex;
  align-items: center;
  gap: 28px;
  padding-top: 14px;
  padding-bottom: 14px;
}
.nav-brand {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--ink);
  flex-shrink: 0;
}
.nav-brand:hover { color: var(--ink); }
.nav-brand img {
  height: 38px;
  width: auto;
}
.nav-brand .brand-tag {
  display: block;
  font-size: 0.66rem;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 500;
  margin-top: 2px;
}
.nav-brand .brand-text { display: none; } /* using img logo */

/* ---- READING PROGRESS ----
   Mounted into .site-header by script, and only on pages that have an
   .article-body, so it never appears where there is nothing to read.

   It rides the header's bottom edge rather than being fixed to the
   viewport: the header is already sticky at top:0, so riding it means
   the bar needs no second copy of the header height to stay in sync at
   every breakpoint. bottom:-1px sets the 4px fill over the header's own
   1px border — which is the point. The border is the track. Where the
   reader has been the line is 4px of royal; where they have not it is
   the same hairline it has always been, so the component adds no new
   furniture to the page.

   scaleX on a full-width bar rather than an animated width: transform is
   compositor-only, so a scroll-linked update costs no layout and no
   paint. transform-origin pins the growth to the left edge.

   No transition, deliberately. The bar is a direct read-out of scroll
   position; easing it would only make it lag the reader's own finger.
   That also means prefers-reduced-motion has nothing to switch off —
   there is no autonomous motion here, only the scroll the reader is
   already making. */
.read-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: var(--read-progress-h);
  background: var(--gf-royal);
  transform: scaleX(0);
  transform-origin: 0 50%;
  will-change: transform;
  pointer-events: none;
}

/* Nothing to indicate on paper, and it would print as a stray rule. */
@media print { .read-progress { display: none; } }

.nav-links {
  display: flex;
  gap: 4px;
  list-style: none;
  margin: 0 0 0 16px;
  padding: 0;
  align-items: center;
}
.nav-links > li { position: relative; }
.nav-links a, .nav-trigger {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 9px 14px;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--ink-2);
  background: transparent;
  border: 0;
  border-radius: 8px;
  text-decoration: none;
  transition: background 0.15s, color 0.15s;
}
/* Menu hover, one treatment everywhere: the soft background stays and the
   text takes primary blue. Hover is the only state the menu carries — there
   is no active-page colour — so it does the whole job. No underline. */
.nav-links a:hover, .nav-trigger:hover { background: var(--soft); color: var(--gf-blue); }
.nav-trigger .caret { width: 11px; height: 11px; opacity: 0.6; transition: transform 0.18s; }
.nav-trigger[aria-expanded="true"] .caret { transform: rotate(180deg); }

/* No active-page state on the menu — decided 2026-09-14. The top-level item
   for the current section used to render in --gf-royal. Removed deliberately:
   do not add it back without a decision. The `data-active-nav` attribute is
   still set on <body> and still drives page content further down this sheet
   (see the .lever-grid rules), so it stays in the markup. */

.nav-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  left: -8px;
  background: #fff;
  min-width: 290px;
  padding: 10px;
  border-radius: 14px;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  list-style: none;
  margin: 0;
  display: none;
  z-index: 60;
}
.nav-dropdown.is-open, .nav-links li:hover .nav-dropdown { display: block; }
.nav-dropdown li { list-style: none; }
.nav-dropdown a {
  display: block;
  padding: 10px 14px;
  border-radius: 8px;
  color: var(--ink);
  font-weight: 500;
  font-size: 0.95rem;
}
.nav-dropdown a small {
  display: block;
  margin-top: 2px;
  font-weight: 400;
  font-size: 0.82rem;
  color: var(--muted);
  letter-spacing: 0;
}
/* Colour stated explicitly: without it the global `a:hover` handed this
   --gf-royal-soft (#6074CF), a different blue from the rest of the menu. */
.nav-dropdown a:hover { background: var(--soft); color: var(--gf-blue); }
.nav-dropdown.two-col { min-width: 540px; padding: 16px; }
.nav-dropdown.two-col .cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.nav-dropdown .group-label {
  display: block;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--muted);
  padding: 6px 14px;
  margin-bottom: 4px;
}

.nav-cta-row {
  margin-left: auto;
  display: flex;
  gap: 10px;
  align-items: center;
  flex-shrink: 0;
}
.nav-cta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 18px;
  background: var(--gf-blue);
  color: #fff;
  border-radius: var(--radius-pill);
  font-size: 0.9rem;
  font-weight: 500;
  letter-spacing: -0.005em;
  transition: background 0.15s, transform 0.15s;
}
.nav-cta:hover { background: var(--gf-blue-deep); color: #fff; }
.nav-cta.ghost {
  background: transparent;
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--line);
}
.nav-cta.ghost:hover { background: var(--soft); color: var(--ink); }
.nav-cta-mobile { display: none; }

.nav-toggle {
  display: none;
  margin-left: auto;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 8px;
  color: var(--ink);
}

@media (max-width: 1080px) {
  .nav-links { display: none; }
  .nav-cta-row { display: none; }
  .nav-toggle { display: inline-flex; }
  .site-header.is-open .nav-links {
    display: flex;
    position: absolute;
    top: 100%;
    left: 0; right: 0;
    flex-direction: column;
    align-items: stretch;
    background: #fff;
    padding: 16px;
    margin: 0;
    gap: 4px;
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow-lg);
    max-height: 80vh;
    overflow: auto;
  }
  .site-header.is-open .nav-cta-mobile {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 8px;
    padding-top: 16px;
    border-top: 1px solid var(--line);
  }

  /* The two CTAs in the collapsed menu sit inside .nav-links, so
     `.nav-links a` (0,1,1) was beating `.nav-cta` (0,1,0) and stripping
     them back to plain menu links — the readiness check lost its fill and
     read as body text on white. The desktop pair escapes this because
     .nav-cta-row is a sibling of the list, not inside it, which is why it
     only ever showed on a phone.

     Scoped to `.nav-links .nav-cta` (0,2,0) so the button treatment wins
     back, with the same tokens the desktop pair resolves to. The ghost
     keeps its inset hairline, which survived because `.nav-links a` resets
     `border`, not `box-shadow`.

     justify-content is the second half: the column stretches both to full
     width, and .nav-cta only ever centred by being shrink-to-fit. */
  .nav-links .nav-cta {
    justify-content: center;
    background: var(--blue-500);
    color: #fff;
  }
  .nav-links .nav-cta:hover { background: var(--blue-600); color: #fff; }
  .nav-links .nav-cta.ghost {
    background: transparent;
    color: var(--ink);
    box-shadow: inset 0 0 0 1px var(--line);
  }
  .nav-links .nav-cta.ghost:hover { background: var(--soft); color: var(--ink); }
  .site-header.is-open .nav-dropdown {
    position: static;
    box-shadow: none;
    border: 0;
    padding-left: 12px;
    background: var(--soft);
  }
}

/* ============================================================
   BUTTONS
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 22px;
  border-radius: var(--radius-pill);
  font-size: 0.96rem;
  line-height: 1.5;
  font-weight: 500;
  letter-spacing: -0.005em;
  text-decoration: none;
  border: 0;
  cursor: pointer;
  transition: background 0.15s, transform 0.15s, box-shadow 0.15s, color 0.15s;
  white-space: nowrap;
}
.btn-primary {
  background: var(--gf-blue);
  color: #fff;
  box-shadow: 0 1px 0 rgba(255,255,255,0.1) inset, 0 6px 20px rgba(30,58,138,0.18);
}
.btn-primary:hover { background: var(--gf-blue-deep); color: #fff; transform: translateY(-1px); box-shadow: 0 1px 0 rgba(255,255,255,0.1) inset, 0 10px 28px rgba(30,58,138,0.28); }
.btn-ghost {
  background: transparent;
  color: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--line);
}
.btn-ghost:hover { background: var(--soft); color: var(--ink); box-shadow: inset 0 0 0 1.5px var(--gf-blue); }
.btn-light {
  background: #fff;
  color: var(--gf-blue);
}
.btn-light:hover { background: var(--soft); color: var(--gf-blue-deep); transform: translateY(-1px); }
/* Large button variant. Used by the dev templates off JP's 11 Sep content
   drop; absent from this prototype's markup, which is why it was dropped
   as dead CSS on 17 Sep. Restored verbatim — the class vocabulary is a
   contract, so a selector one lineage still uses stays in the system. */
.btn-lg { padding: 16px 28px; font-size: 1.02rem; }
.btn .arr { transition: transform 0.18s; }
.btn:hover .arr { transform: translateX(3px); }

.hero-cta-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }

/* ============================================================
   HERO — the brand statement piece
   ============================================================ */
.hero {
  position: relative;
  background: linear-gradient(170deg, var(--gf-blue) 0%, var(--gf-blue-deep) 100%);
  color: #fff;
  overflow: hidden;
  padding: 120px 0 130px;
}
.hero::before {
  /* The swirl backdrop */
  content: '';
  position: absolute;
  inset: 0;
  background-image: url('patterns/pattern1.svg');
  background-size: cover;
  background-position: center;
  opacity: 1;
  z-index: 0;
}
.hero::after {
  /* Subtle vignette to anchor copy on the left */
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(95deg, rgba(15,30,80,0.55) 0%, rgba(15,30,80,0.15) 55%, rgba(15,30,80,0) 100%);
  z-index: 1;
}
.hero > .container { position: relative; z-index: 2; max-width: var(--container); }
.hero h1, .hero h2, .hero h3 { color: #fff; }
.hero .lede { color: rgba(255,255,255,0.88); max-width: 56ch; }
.hero h1 .accent { color: var(--gf-cyan); font-style: italic; }
.hero strong { color: #fff; }
.hero .hero-cta-row { margin-top: 40px; }
.hero .btn-ghost {
  color: #fff;
  background: rgba(255,255,255,0.06);
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,0.7);
  backdrop-filter: blur(2px);
}
.hero .btn-ghost:hover { background: rgba(255,255,255,0.18); box-shadow: inset 0 0 0 1.5px #fff; color: #fff; }

.hero-question h1 {
  font-size: clamp(2.6rem, 5.4vw, 4.6rem);
  max-width: 18ch;
  font-weight: 600;
}

/* Page hero — for inner pages */
.page-hero {
  position: relative;
  background: linear-gradient(160deg, var(--gf-blue) 0%, var(--gf-blue-deep) 100%);
  color: #fff;
  overflow: hidden;
  padding: 90px 0 100px;
}
.page-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url('patterns/pattern1.svg');
  background-size: cover;
  background-position: right center;
  opacity: 0.85;
  z-index: 0;
}
.page-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(15,30,80,0.7) 0%, rgba(15,30,80,0.25) 60%, rgba(15,30,80,0) 100%);
  z-index: 1;
}
.page-hero > .container { position: relative; z-index: 2; }
.page-hero h1 { color: #fff; max-width: 22ch; }
.page-hero .lede { color: rgba(255,255,255,0.9); max-width: 60ch; }

/* Article hero — slightly tighter */
.article-hero {
  position: relative;
  background: linear-gradient(160deg, var(--gf-blue) 0%, var(--gf-blue-deep) 100%);
  color: #fff;
  overflow: hidden;
  padding: 80px 0 80px;
}
.article-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url('patterns/pattern1.svg');
  background-size: cover;
  background-position: right center;
  opacity: 0.7;
  z-index: 0;
}
.article-hero > .container { position: relative; z-index: 1; }
.article-hero h1 { color: #fff; max-width: 24ch; }
.article-hero .lede { color: rgba(255,255,255,0.88); max-width: 60ch; }

/* ============================================================
   SUBNAV (sticky chapter links inside long pages)
   ============================================================ */
.subnav {
  position: sticky;
  /* The header's height is measured at runtime into --header-h (script.js).
     It used to be hardcoded at 70px, which silently went stale when the
     brand lock-up dropped from 46px to 44px and left the strip parked a
     pixel low — page content bled through the seam on scroll. */
  top: var(--header-h, 69px);
  z-index: 40;
  background: rgba(255,255,255,0.86);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.subnav .links {
  display: flex;
  gap: 6px;
  justify-content: space-between;
  align-items: center;
  overflow-x: auto;
  padding: 12px 0;
  -ms-overflow-style: none;
  scrollbar-width: none;
}
.subnav .links::-webkit-scrollbar { display: none; }
.subnav a {
  /* Content-sized, not equal-width tracks. `flex: 1 1 0` gave every link the
     same track and centred the label inside it, so a short label like
     "Boundaries" floated in ~85px of slack per side while a long one nearly
     filled its track — the gaps between labels came out up to 102px apart.
     Sizing to content lets the `space-between` above divide the free space
     evenly, which is the thing the eye actually reads as even. */
  flex: 0 0 auto;
  white-space: nowrap;
  padding: 9px 14px;
  font-size: 0.86rem;
  font-weight: 500;
  color: var(--muted);
}
/* Hover and the scrolled-to section share one treatment: the label takes the
   accent, nothing else moves. No pill, no weight change — the strip must not
   reflow while the page is scrolling under it. */
.subnav a:hover,
.subnav a.active { color: var(--gf-blue); }
@media (max-width: 720px) {
  /* Too narrow to spread: pack from the left and let the strip scroll. */
  .subnav .links { justify-content: flex-start; }
}

/* ============================================================
   PERSONA / OUTCOME ROUTING
   ============================================================ */
.persona-band { padding: 96px 0; }
.persona-band-head {
  text-align: center;
  max-width: 64ch;
  margin: 0 auto 56px;
}
.persona-cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px;
}
.persona-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 36px 36px 32px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  color: var(--ink);
  transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s;
  overflow: hidden;
}
.persona-card[data-outcome="working-capital"] {
  background: linear-gradient(155deg, #EEF2FF 0%, #FFFFFF 55%);
  border-top: 4px solid var(--gf-royal);
}
.persona-card[data-outcome="ebitda"] {
  background: linear-gradient(155deg, #EFF6FF 0%, #FFFFFF 55%);
  border-top: 4px solid var(--gf-blue);
}
.persona-card::before {
  content: '';
  position: absolute;
  width: 280px; height: 280px;
  right: -90px; top: -90px;
  background-image: url('patterns/pattern1.svg');
  background-size: cover;
  background-position: center;
  border-radius: 50%;
  opacity: 0.07;
  transform: rotate(-18deg);
  transition: opacity 0.3s, transform 0.4s;
  z-index: 0;
  pointer-events: none;
}
.persona-card[data-outcome="ebitda"]::before {
  transform: rotate(165deg) scale(1.1);
  filter: hue-rotate(20deg);
  right: auto; top: auto; left: -90px; bottom: -90px;
}
.persona-card > * { position: relative; z-index: 1; }
.persona-card:hover {
  border-color: var(--gf-blue);
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  color: var(--ink);
}
.persona-card:hover::before { opacity: 0.13; transform: rotate(0deg); }
.persona-card[data-outcome="ebitda"]:hover::before { transform: rotate(180deg) scale(1.15); }

/* Swirl treatment variations — body-level data attribute switches the global feel */
body[data-swirl="muted"] .lever::after,
body[data-swirl="muted"] .persona-card::before { opacity: 0.025; }
body[data-swirl="muted"] .hero::before,
body[data-swirl="muted"] .callout::before { opacity: 0.18; }
body[data-swirl="bold"] .lever::after,
body[data-swirl="bold"] .persona-card::before { opacity: 0.12; }
body[data-swirl="off"] .lever::after,
body[data-swirl="off"] .persona-card::before,
body[data-swirl="off"] .bg-swirl-decoration::before { display: none; }
body[data-accent="warm"] .lever:nth-child(2),
body[data-accent="warm"] .persona-card[data-outcome="ebitda"] {
  background: linear-gradient(180deg, #FFF6EE 0%, #FFFFFF 60%);
  border-top-color: #C2410C;
}
body[data-accent="warm"] .lever:nth-child(2) .lever-q,
body[data-accent="warm"] .persona-card[data-outcome="ebitda"] .pc-icon { color: #C2410C; }
body[data-accent="teal"] .lever:nth-child(2),
body[data-accent="teal"] .persona-card[data-outcome="ebitda"] {
  background: linear-gradient(180deg, #ECFDF5 0%, #FFFFFF 60%);
  border-top-color: #047857;
}
body[data-accent="teal"] .lever:nth-child(2) .lever-q,
body[data-accent="teal"] .persona-card[data-outcome="ebitda"] .pc-icon { color: #047857; }

.persona-card .pc-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: linear-gradient(140deg, var(--gf-blue), var(--gf-royal));
  color: #fff;
}
.persona-card .pc-role {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--gf-royal);
}
.persona-card h3 { margin: 4px 0 6px; font-size: 1.5rem; }
.persona-card p { color: var(--ink-2); margin: 0; }
.persona-card .pc-cta {
  margin-top: auto;
  padding-top: 14px;
  font-weight: 500;
  color: var(--gf-royal);
}
@media (max-width: 880px) {
  .persona-cards { grid-template-columns: 1fr !important; }
}

/* ============================================================
   LEVERS (the two-method cards)
   ============================================================ */
.lever-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 28px;
}
.lever {
  position: relative;
  padding: 44px 38px 38px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  border-top: 5px solid var(--gf-royal);
}
.lever:nth-child(2) {
  border-top-color: var(--gf-blue);
  background: linear-gradient(180deg, #F6F4FF 0%, #FFFFFF 60%);
}
.lever:nth-child(1) {
  background: linear-gradient(180deg, #EEF2FF 0%, #FFFFFF 60%);
}
.lever::after {
  content: '';
  position: absolute;
  top: -30%;
  right: -25%;
  width: 70%;
  height: 90%;
  background-image: url('patterns/pattern1.svg');
  background-size: cover;
  background-position: center;
  opacity: 0.05;
  transform: rotate(-12deg);
  z-index: 0;
  filter: hue-rotate(0deg);
}
.lever:nth-child(2)::after {
  transform: rotate(160deg) scale(1.1);
  top: auto; bottom: -30%; right: auto; left: -20%;
  filter: hue-rotate(35deg);
  opacity: 0.04;
}
.lever > * { position: relative; z-index: 1; }
.lever-tag {
  display: inline-block;
  padding: 5px 12px;
  border-radius: 999px;
  background: rgba(39,64,222,0.10);
  color: var(--gf-royal);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}
.lever:nth-child(2) .lever-tag {
  background: rgba(30,58,138,0.10);
  color: var(--gf-blue);
}
.lever-q {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 1.1rem;
  color: var(--gf-royal);
  margin: 14px 0 6px;
}
.lever:nth-child(2) .lever-q { color: var(--gf-blue); }
.lever h3 { font-size: 2rem; margin: 4px 0 14px; letter-spacing: -0.025em; color: var(--gf-blue-ink); }
.lever ul { margin: 18px 0; padding: 0; list-style: none; }
.lever ul li {
  position: relative;
  padding: 10px 0 10px 28px;
  border-top: 1px solid var(--line-soft);
  font-size: 0.95rem;
  color: var(--ink-2);
}
.lever ul li::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 18px;
  width: 8px; height: 8px;
  border-radius: 2px;
  background: var(--gf-royal);
  transform: rotate(45deg);
}
.lever:nth-child(2) ul li::before { background: var(--gf-blue); }
@media (max-width: 880px) { .lever-grid { grid-template-columns: 1fr; } }

/* ============================================================
   GUARDRAILS (boundary cards)
   ============================================================ */
.guardrail-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
.guardrail {
  padding: 28px 26px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color 0.2s, transform 0.2s;
}
.guardrail:hover { border-color: var(--gf-blue); transform: translateY(-2px); }
.guardrail .g-label {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--gf-blue);
  color: #fff;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  margin-bottom: 14px;
}
/* Title variant used by the dev templates in place of the h4 below.
   Restored with .btn-lg and .info-icon — see the note on .btn-lg. */
.guardrail .g-title {
  font-family: var(--font-display);
  font-size: 1.02rem; font-weight: 700; color: var(--gf-blue-ink);
  letter-spacing: -0.01em; line-height: 1.2;
}
.guardrail h4 { margin: 0 0 8px; font-size: 1.05rem; }
.guardrail p { margin: 0; font-size: 0.93rem; color: var(--ink-2); line-height: 1.55; }
@media (max-width: 880px) { .guardrail-grid { grid-template-columns: 1fr; } }

.section-cool .guardrail {
  background: rgba(255,255,255,0.04);
  border-color: rgba(255,255,255,0.12);
}
.section-cool .guardrail:hover { border-color: var(--gf-cyan); }
.section-cool .guardrail .g-label { background: var(--gf-cyan); color: var(--gf-blue-ink); }
.section-cool .guardrail p { color: rgba(255,255,255,0.78); }

/* ============================================================
   FLOW (numbered steps)
   ============================================================ */
.flow {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px;
  gap: 14px;
  position: relative;
}
/* ---- ROUND 2026-09-24: the connector links cards at their middle ----
   The line sat at top: 26px — level with the number circles — but runs
   behind the cards (z-index 0 under the cards' 1), so all that ever showed
   was a 14px stub in each gap, at circle height, reading as broken rather
   than as a link. It now sits at the cards' vertical middle, still behind
   them, so each gap carries one centred link from card to card.

   The span is now measured rather than guessed: calc((100% - 56px) / 10)
   is half of one column in the five-up grid (four 14px gaps = 56px), so
   the line starts and ends at the first and last card's centre and never
   pokes out past either end. It is solid rather than the old faded
   gradient, since only the gaps show and a fade had nothing to fade.

   Only the Visy page shows it. .section-cool hides it (how-it-works,
   pace) and it is off below 1000px, where the grid wraps. */
.flow::before {
  content: '';
  position: absolute;
  top: 50%;
  left: calc((100% - 56px) / 10);
  right: calc((100% - 56px) / 10);
  height: 2px;
  margin-top: -1px;
  background: var(--gf-royal);
  opacity: 0.35;
  z-index: 0;
}
.flow-step {
  position: relative;
  padding: 14px 16px 18px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-align: center;
  z-index: 1;
}
.flow-step .fs-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--line);
  color: var(--ink);
  font-weight: 600;
  font-size: 0.85rem;
  margin: -32px auto 12px;
  position: relative;
  z-index: 2;
}
.flow-step h4 { margin: 0 0 6px; font-size: 0.98rem; }
.flow-step p { margin: 0; font-size: 0.84rem; color: var(--muted); line-height: 1.45; }
.flow-step.flow-key { background: var(--gf-blue); color: #fff; border-color: var(--gf-blue); }
.flow-step.flow-key h4 { color: #fff; }
.flow-step.flow-key p { color: rgba(255,255,255,0.82); }
.flow-step.flow-key .fs-num { background: var(--gf-blue); color: #fff; border-color: rgba(255,255,255,0.4); }
.section-cool .flow-step { background: rgba(255,255,255,0.04); border-color: rgba(255,255,255,0.14); color: rgba(255,255,255,0.88); }
.section-cool .flow-step h4 { color: #fff; }
.section-cool .flow-step p { color: rgba(255,255,255,0.7); }
.section-cool .flow-step .fs-num { background: var(--gf-blue-deep); border-color: rgba(255,255,255,0.3); color: #fff; }
.section-cool .flow-step.flow-key { background: var(--gf-royal); border-color: var(--gf-royal); }
.section-cool .flow::before { display: none; }

@media (max-width: 1000px) {
  .flow { grid-template-columns: repeat(2, 1fr); }
  .flow::before { display: none; }
}
@media (max-width: 600px) { .flow { grid-template-columns: 1fr; } }

/* ============================================================
   CALLOUT (final CTA banner)
   ============================================================ */
.callout {
  position: relative;
  padding: 64px 56px;
  background: linear-gradient(135deg, var(--gf-blue) 0%, var(--gf-blue-deep) 100%);
  color: #fff;
  border-radius: var(--radius-lg);
  text-align: center;
  overflow: hidden;
}
.callout::before { display: none; }
.callout > * { position: relative; z-index: 1; }
.callout h2 { color: #fff; margin: 0 0 12px; max-width: 22ch; margin-left: auto; margin-right: auto; }
.callout p { color: rgba(255,255,255,0.88); max-width: 60ch; margin: 0 auto 28px; font-size: 1.05rem; }
@media (max-width: 700px) { .callout { padding: 48px 28px; } }

/* ============================================================
   QUOTE / PULL-QUOTE
   ============================================================ */
.pull-quote {
  position: relative;
  padding: 36px 32px;
  background: var(--white);
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  border-left: 3px solid var(--gf-royal);
}
.pull-quote::before {
  content: '"';
  position: absolute;
  top: -22px;
  left: 18px;
  font-family: var(--font-serif);
  font-size: 7rem;
  line-height: 1;
  color: var(--gf-royal);
  opacity: 0.18;
}
.quote-text {
  font-family: var(--font-serif);
  font-size: 1.4rem;
  line-height: 1.4;
  letter-spacing: -0.012em;
  color: var(--ink);
  margin: 0 0 24px;
  font-style: italic;
  font-weight: 400;
  text-wrap: pretty;
}
.quote-attr { display: flex; align-items: center; gap: 14px; padding-top: 18px; border-top: 1px solid var(--line); }
.quote-attr-name { font-weight: 600; color: var(--ink); }
.quote-attr-role { font-size: 0.88rem; color: var(--muted); }

.quote {
  font-family: var(--font-serif);
  font-size: 1.3rem;
  line-height: 1.4;
  font-style: italic;
  color: var(--gf-blue);
  padding: 18px 0 18px 22px;
  border-left: 3px solid var(--gf-royal);
  margin: 24px 0;
}

article blockquote {
  font-family: var(--font-serif);
  font-size: 1.3rem;
  line-height: 1.45;
  font-style: italic;
  color: var(--ink);
  padding: 14px 0 14px 24px;
  border-left: 3px solid var(--gf-royal);
  margin: 32px 0;
}

/* ============================================================
   CARDS — generic
   ============================================================ */
.card {
  padding: 28px 26px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.card-soft { background: var(--soft); border-color: var(--line-soft); }
.card-feature {
  background: linear-gradient(160deg, #fff 0%, var(--soft) 100%);
  border-color: var(--line);
}
.card h3 { margin: 0 0 12px; font-size: 1.15rem; }
.card p { color: var(--ink-2); margin: 0 0 0.6em; font-size: 0.96rem; }

.tag {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(39,64,222,0.08);
  color: var(--gf-royal);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}
.tag-green { background: rgba(13,138,95,0.12); color: var(--green); }

/* ============================================================
   ARCH DIAGRAM (epayment)
   ============================================================ */
.arch-diagram {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 36px;
  margin-top: 16px;
}
.arch-grid {
  display: grid;
  grid-template-columns: 1fr 80px 1.1fr 80px 1fr;
  gap: 12px;
  align-items: stretch;
}
.arch-col { display: flex; flex-direction: column; gap: 10px; padding: 14px 12px 16px; border-radius: 14px; border: 1px solid transparent; }
.arch-col-buyer {
  background: linear-gradient(180deg, #EEF2FF 0%, rgba(238,242,255,0) 100%);
  border-color: rgba(67,56,202,0.18);
}
.arch-col-buyer .arch-col-label { color: var(--gf-royal); }
.arch-col-gfx {
  background: linear-gradient(180deg, rgba(30,58,138,0.06) 0%, rgba(30,58,138,0) 100%);
  border-color: rgba(30,58,138,0.20);
}
.arch-col-gfx .arch-col-label { color: var(--gf-blue); }
.arch-col-sup {
  background: linear-gradient(180deg, #ECFEFF 0%, rgba(236,254,255,0) 100%);
  border-color: rgba(8,145,178,0.20);
}
.arch-col-sup .arch-col-label { color: #0E7490; }
/* Default 'arch-card' inside buyer/supplier cols — give it visible body */
.arch-col-buyer .arch-card:not(.is-gfx):not(.is-sup) { background: #fff; border-color: rgba(67,56,202,0.18); }
.arch-col-buyer .arch-card .arch-icon { background: var(--gf-royal); }
.arch-col-sup .arch-card.is-sup { background: #fff; border-color: rgba(8,145,178,0.22); }
.arch-col-sup .arch-card .arch-icon { background: #0E7490; }
.arch-col-label {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--muted);
  padding-bottom: 6px;
  text-align: center;
}
.arch-card {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 16px;
  background: var(--soft);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.arch-card.is-gfx { background: linear-gradient(155deg, var(--gf-blue), var(--gf-blue-deep)); border-color: var(--gf-blue); color: #fff; }
.arch-card.is-gfx .arch-name { color: #fff; }
.arch-card.is-gfx .arch-note { color: rgba(255,255,255,0.78); }
.arch-card.is-sup { background: #fff; }
.arch-icon {
  flex-shrink: 0;
  width: 30px; height: 30px;
  border-radius: 8px;
  background: var(--gf-royal);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.arch-card.is-gfx .arch-icon { background: rgba(255,255,255,0.18); }
.arch-name { font-weight: 600; font-size: 0.95rem; color: var(--ink); margin-bottom: 3px; }
.arch-note { font-size: 0.82rem; color: var(--muted); line-height: 1.45; }
.arch-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.arch-arrow::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 0; right: 0;
  height: 2px;
  background: linear-gradient(to right, transparent 0%, var(--gf-blue) 50%, transparent 100%);
}
.arch-arrow::after {
  content: '';
  position: absolute;
  top: calc(50% - 6px);
  right: 6px;
  width: 0; height: 0;
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  border-left: 9px solid var(--gf-blue);
}
.arch-arrow .arrow-label {
  position: relative;
  background: #fff;
  padding: 3px 8px;
  font-size: 0.74rem;
  font-weight: 500;
  color: var(--gf-blue);
  border-radius: 999px;
  border: 1px solid var(--line);
  z-index: 1;
}
.arch-flow-row {
  display: grid;
  grid-template-columns: 1fr 80px 1.1fr 80px 1fr;
  gap: 12px;
}
@media (max-width: 1000px) {
  .arch-grid, .arch-flow-row { grid-template-columns: 1fr; }
  .arch-arrow { display: none; }
}

/* ============================================================
   BEFORE / AFTER (epayment)
   ============================================================ */
.before-after {
  display: grid;
  grid-template-columns: 1fr 60px 1fr;
  gap: 16px;
  align-items: stretch;
}
.ba-col {
  padding: 28px 24px;
  border-radius: var(--radius-lg);
}
.ba-col.before { background: var(--soft); border: 1px solid var(--line); }
.ba-col.after  { background: linear-gradient(155deg, var(--gf-blue), var(--gf-blue-deep)); color: #fff; position: relative; overflow: hidden; }
.ba-col.after::before { display: none; }
.ba-col.after > * { position: relative; z-index: 1; }
.ba-head {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  font-size: 0.95rem;
  margin-bottom: 18px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.ba-col.after .ba-head { border-bottom-color: rgba(255,255,255,0.2); color: #fff; }
.ba-step {
  padding: 11px 14px;
  margin-bottom: 8px;
  background: #fff;
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  font-size: 0.92rem;
}
.ba-col.before .ba-step.friction {
  background: #fff5ed;
  border-color: #fbcdaa;
  color: #8a4517;
}
.ba-col.after .ba-step {
  background: rgba(255,255,255,0.1);
  border-color: rgba(255,255,255,0.2);
  color: #fff;
}
.ba-divider {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 1.4rem;
  color: var(--muted);
}
@media (max-width: 880px) {
  .before-after { grid-template-columns: 1fr; }
  .ba-divider { padding: 8px 0; }
}

/* ============================================================
   FEATURE LIST with info icons
   ============================================================ */
.feature-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.feature-list li {
  display: flex;
  gap: 14px;
  padding: 14px 0;
  border-top: 1px solid var(--line-soft);
}
.feature-list li:first-child { border-top: 0; padding-top: 0; }
.fl-icon {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--gf-blue);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.78rem;
  font-weight: 700;
  font-family: var(--font-serif);
  font-style: italic;
}
.fl-body { font-size: 0.96rem; color: var(--ink-2); line-height: 1.55; }

/* ============================================================
   TRUST STRIP (badges)
   ============================================================ */
.trust-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  padding: 28px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
.section-cool .trust-strip { background: rgba(255,255,255,0.04); border-color: rgba(255,255,255,0.12); }
.trust-badge {
  display: flex;
  align-items: center;
  gap: 14px;
}
.tb-icon {
  flex-shrink: 0;
  width: 44px; height: 44px;
  border-radius: 12px;
  background: linear-gradient(140deg, var(--gf-blue), var(--gf-royal));
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.tb-name { font-weight: 600; color: var(--ink); font-size: 0.96rem; }
.section-cool .tb-name { color: #fff; }
.tb-desc { font-size: 0.82rem; color: var(--muted); line-height: 1.4; }
.section-cool .tb-desc { color: rgba(255,255,255,0.65); }
@media (max-width: 880px) { .trust-strip { grid-template-columns: 1fr 1fr; } }
@media (max-width: 540px) { .trust-strip { grid-template-columns: 1fr; } }

/* ============================================================
   GROUP STRIP (B2BE parent)
   ============================================================ */
/* Soft, editorial parent-company strip — not a CTA */
.group-strip {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 56px;
  align-items: center;
  padding: 40px 48px;
  background: #FFFFFF;
  color: var(--ink-2);
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  position: relative;
}
.group-strip h3 { color: var(--gf-blue-ink); margin: 0 0 10px; font-size: 1.25rem; letter-spacing: -0.01em; }
.group-strip p { margin: 0; max-width: 64ch; font-size: 0.95rem; color: var(--ink-2); line-height: 1.6; }
.group-strip a { color: var(--gf-blue); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.group-strip a:hover { color: var(--gf-blue-deep); }
.b2be-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 8px 0 24px;
  background: transparent;
  border: none;
  box-shadow: none;
  min-width: 200px;
  border-left: 1px solid var(--line);
}
.b2be-mark img {
  display: block;
  width: 100%;
  max-width: 180px;
  height: auto;
}
/* Parent-company section gets its own breathing room */
.section-group-strip { padding-top: 32px; padding-bottom: 80px; }
@media (max-width: 700px) {
  .group-strip { grid-template-columns: 1fr; padding: 28px 24px; gap: 24px; }
  .b2be-mark { padding: 16px 0 0; border-left: none; border-top: 1px solid var(--line); padding-top: 24px; min-width: 0; }
}

/* ============================================================
   PLACEHOLDERS (image slots)
   ============================================================ */
.placeholder {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  gap: 6px;
  min-height: 280px;
  padding: 36px 32px;
  background:
    repeating-linear-gradient(135deg, rgba(30,58,138,0.04) 0 1px, transparent 1px 12px),
    var(--soft);
  border: 1px dashed var(--gf-blue);
  border-radius: var(--radius-lg);
  color: var(--ink-2);
}
.placeholder-tall { min-height: 380px; }
.ph-tag {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--gf-royal);
  padding: 4px 10px;
  background: rgba(39,64,222,0.08);
  border-radius: 999px;
}
.ph-label { font-weight: 600; font-size: 1.05rem; color: var(--ink); margin-top: 6px; }
.ph-note { font-size: 0.86rem; color: var(--muted); max-width: 50ch; line-height: 1.5; }

/* ============================================================
   COMPARISON / ALT TABLE
   ============================================================ */
.comp-table, .alt-table {
  width: 100%;
  border-collapse: collapse;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.comp-table th, .comp-table td,
.alt-table th, .alt-table td {
  padding: 16px 18px;
  text-align: left;
  border-bottom: 1px solid var(--line-soft);
  font-size: 0.93rem;
  vertical-align: top;
}
.comp-table thead th, .alt-table thead th {
  background: var(--soft);
  font-weight: 600;
  font-size: 0.82rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.comp-table tbody tr:last-child td, .alt-table tbody tr:last-child td { border-bottom: 0; }
.comp-table tbody tr:hover, .alt-table tbody tr:hover { background: var(--softer); }

/* ============================================================
   OUTCOME HIGHLIGHT (banner card)
   ============================================================ */
.outcome-highlight {
  position: relative;
  padding: 36px 40px;
  /* 2026-09-22: this declaration used to read --gf-royal -> --gf-blue, which
     is not a gradient. Both aliases resolve to --blue-500 (lines 59 and 63),
     so the banner rendered as one flat #1C39BB from edge to edge - measured
     8.93:1 at every sample point across the panel. The design-system page
     has documented it as a 140deg ramp since it was written; it never was
     one. It is now the house anchor the other two banners already use. */
  background: linear-gradient(140deg, var(--blue-800) 0%, var(--blue-500) 100%);
  color: #fff;
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.outcome-highlight::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url('patterns/pattern1.svg');
  background-size: cover;
  background-position: right center;
  opacity: 0.35;
  z-index: 0;
}
.outcome-highlight > * { position: relative; z-index: 1; }
.outcome-highlight h2 { color: #fff; }
.outcome-highlight p { color: rgba(255,255,255,0.9); }
.o-badge {
  display: inline-block;
  padding: 5px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
  color: #fff;
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  margin-bottom: 14px;
}

/* ============================================================
   ARTICLE BODY (case study, blog)
   ============================================================ */
/* ---- ROUND 2026-09-22: the articles join the site's container ----
   blog-the-gap-nobody-manages.html and case-study-visy.html were the
   last two pages off the 1240px grid. The hero sat on .container-narrow
   (880px) and .article-body centred separately on a hardcoded 720px, so
   the page ran three left edges down its length: nav, footer and More to
   read at 121px, the h1 at 301px, and the first paragraph at 381px.

   Both now take .container, the same width the homepage and every other
   page use. The hero div drops .container-narrow in the two HTML files
   and .article-body swaps its hardcoded cap for --container, so hero and
   prose share the one edge the rest of the site is built on.

   This completes ROUND 2026-09-15b rather than contradicting it. That
   round moved eighteen prose blocks to the full container and held these
   two back as "heroes, not body sections" — the hold was pending review,
   not an argument against, and this is that review. As there, the cap is
   removed explicitly rather than by omission: .lede carries 60ch and
   .section-lede 64ch from further up this file, and a bare container
   swap would leave those capped while the plain paragraphs ran wide. */
.article-body {
  max-width: var(--container);
  margin: 0 auto;
  padding: 80px 28px 64px;
  font-size: 1.06rem;
  line-height: 1.7;
  color: var(--ink-2);
}
.article-body > * { max-width: none; }
.article-body h2 {
  font-size: 1.7rem;
  margin: 56px 0 16px;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.article-body h3 {
  font-size: 1.18rem;
  margin: 32px 0 10px;
  color: var(--ink);
}
.article-body p { margin: 0 0 1.2em; }
.article-body strong { color: var(--ink); }
.article-cta-card {
  margin: 36px 0;
  padding: 28px 28px;
  background: var(--soft);
  border: 1px solid var(--line);
  border-left: 3px solid var(--gf-royal);
  border-radius: var(--radius);
}
.article-cta-card .eyebrow { margin-bottom: 10px; }

/* ============================================================
   BLOG / CASE GRID
   ============================================================ */
.blog-card, .case-card {
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s;
  color: var(--ink);
}
.blog-card:hover, .case-card:hover {
  transform: translateY(-4px);
  border-color: var(--gf-blue);
  box-shadow: var(--shadow);
  color: var(--ink);
}
.bc-image {
  position: relative;
  height: 180px;
  background: linear-gradient(140deg, var(--gf-blue), var(--gf-blue-deep));
  color: rgba(255,255,255,0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.bc-image::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url('patterns/pattern1.svg');
  background-size: cover;
  background-position: center;
  opacity: 0.55;
}
.bc-image > * { position: relative; }
.bc-body { padding: 24px 24px 22px; flex: 1; display: flex; flex-direction: column; }
.bc-meta {
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--gf-royal);
  margin-bottom: 10px;
}
.bc-body h3 { font-size: 1.18rem; margin: 0 0 8px; }
.bc-body p { font-size: 0.94rem; color: var(--ink-2); line-height: 1.55; flex: 1; }
.bc-cta { font-weight: 500; color: var(--gf-royal); margin-top: 14px; font-size: 0.92rem; }

/* ============================================================
   FORMS (contact, readiness check)
   ============================================================ */
.fs-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 40px;
  box-shadow: var(--shadow);
}
.fs-progress {
  display: flex;
  gap: 8px;
  margin-bottom: 28px;
}
.fs-progress span {
  flex: 1;
  height: 4px;
  background: var(--line);
  border-radius: 999px;
  transition: background 0.2s;
}
.fs-progress span.current,
.fs-progress span.done { background: var(--gf-royal); }
.fs-step { display: none; }
.fs-step.active { display: block; animation: fadeIn 0.3s ease; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.fs-q-help { color: var(--muted); font-size: 0.95rem; }
.fs-options { display: flex; flex-direction: column; gap: 10px; margin-top: 24px; }
.fs-opt {
  display: block;
  padding: 16px 18px;
  background: #fff;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.fs-opt:hover { border-color: var(--gf-royal); background: var(--softer); }
.fs-opt.is-selected { border-color: var(--gf-royal); background: rgba(39,64,222,0.04); }
.fs-opt input { display: none; }
.fs-opt-body strong { display: block; font-weight: 600; color: var(--ink); margin-bottom: 4px; }
.fs-opt-body span { display: block; font-size: 0.9rem; color: var(--muted); line-height: 1.5; }
.fs-actions {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-top: 32px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}
.fs-result { display: none; }
.fs-result.is-visible { display: block; }
.fs-result-band {
  padding: 24px 28px;
  border-radius: var(--radius);
  margin-bottom: 24px;
}
.fs-band-strong { background: rgba(13,138,95,0.08); border: 1px solid rgba(13,138,95,0.3); }
.fs-band-mid    { background: rgba(183,121,31,0.08); border: 1px solid rgba(183,121,31,0.3); }
.fs-band-low    { background: var(--soft); border: 1px solid var(--line); }
.band-tag { font-size: 0.78rem; font-weight: 600; letter-spacing: var(--track-label); text-transform: uppercase; color: var(--ink-2); margin-bottom: 8px; }
.fs-form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.fs-form-grid label, .contact-form label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-weight: 500;
  font-size: 0.88rem;
  color: var(--ink-2);
}
.fs-form-grid label.full, .contact-form label.full { grid-column: 1 / -1; }
.fs-form-grid input,
.fs-form-grid select,
.fs-form-grid textarea,
.contact-form input,
.contact-form select,
.contact-form textarea {
  padding: 12px 14px;
  font: inherit;
  font-size: 0.96rem;
  background: #fff;
  border: 1.5px solid var(--line);
  border-radius: 10px;
  transition: border-color 0.15s;
  color: var(--ink);
}
.fs-form-grid input:focus,
.fs-form-grid select:focus,
.fs-form-grid textarea:focus,
.contact-form input:focus,
.contact-form select:focus,
.contact-form textarea:focus {
  outline: 0;
  border-color: var(--gf-royal);
}
.fs-form-grid select,
.contact-form select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%234A4F66' stroke-width='1.6' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px 8px;
}
.fs-disclaimer { font-size: 0.78rem; color: var(--muted); margin-top: 16px; }
@media (max-width: 700px) { .fs-form-grid { grid-template-columns: 1fr; } }

/* ============================================================
   FOOTER — A2, consolidated 2026-09-15
   ------------------------------------------------------------
   Replaces four passes that had accumulated on this block: the
   base rules, the regulatory band (round 12 & 13), the rhythm
   tidy-up, and the divider inset. Consolidated rather than
   appended because the grid is re-tracked and `.foot-legal`
   changes from a flex row to a grid — an appended round would be
   writing overrides to cancel round four rather than adding a
   corrected value. The earlier declarations are in git.

   Three changes from what shipped before:

   1. The link columns were 1.6fr + three tracks carrying 5, 11
      and 7 links. The eleven-link column ran to the depth of the
      brand block while the other two stopped short, so the
      bottom edge read as ragged rather than as a hierarchy.
      "Use cases" now splits into Use cases (6) and By role (5),
      giving 5 · 6 · 5 · 7 across four tracks. No link left the
      footer; they are the same 23 in a different order.

   2. The entity block and the AUSTRAC registration sat in a flex
      row at near-identical weight — 0.84rem against 0.82rem,
      both at 72-86% white — so neither led, and `.foot-austrac`
      carried a 42ch cap that wrapped it to three lines against a
      four-line block.

   3. ALIGNMENT. This is the reason `.foot-legal` is a grid and
      not a two-track one of its own. It now declares the SAME
      five tracks and the SAME 32px column gap as `.foot-grid`,
      and its two children span those tracks — entity across 1-2,
      registration across 3-5. So the entity's left edge sits on
      the brand column, and the registration's cyan rule sits
      exactly on the "Use cases" column edge above it. A separate
      1.25fr / 1fr grid looked close but landed on nothing, which
      is the kind of near-miss that reads as sloppy at full
      width. If you change `.foot-grid`'s tracks or gap, change
      them here too — the two are one system.

   Spacing is on the 8pt grid throughout. The values that were
   off it (36, 22, 18, 14, 10, 6) are snapped; nothing here is a
   one-off.

   Both dividers carry 24px of clear space on each side — the
   grid's padding-bottom, the legal block's padding-block on both
   edges, and the bottom row's padding-top are all one value, so
   the two rules sit in even air rather than being pushed toward
   the block above or below them. They had been 40/24 and 8/16.
   Change one of those four and change all four.

   Carried forward from the four earlier passes:
   - logo at 52px (arrived at over three rounds: 38 → 54 → 52)
   - one divider between sections, not two drawn 28px apart
   - dividers inset with ::after, because `.container` carries
     28px of padding and a plain border overhangs the columns by
     that much on each side
   - link colour at 0.7 white, which measures 8.9:1 on
     --gf-blue-ink; `.foot-certs` at 0.5 measures 5.1:1. Both
     clear the 4.5:1 floor. Do not lower either.
   ============================================================ */

.site-footer {
  background: var(--gf-blue-ink);
  color: rgba(255,255,255,0.7);
  padding: 80px 0 24px;
  position: relative;
  overflow: hidden;
}
.site-footer::before { display: none; }
.site-footer > * { position: relative; z-index: 1; }

/* The shared track definition. `.foot-grid` and `.foot-legal` both
   use it so their edges line up; see note 3 above. */
.site-footer .foot-grid,
.site-footer .foot-legal {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 0.9fr 1fr;
  column-gap: 32px;
  position: relative;
}

/* Four link tracks at 5 · 6 · 5 · 7. At five tracks on a 1280px
   container the 32px gap leaves ~205px per column, which holds every
   label but "Flow & Pace: Combined Solution", which wraps to two. */
.site-footer .foot-grid {
  row-gap: 32px;
  padding-bottom: 24px;
}
.site-footer .foot-grid::after,
.site-footer .foot-legal::after {
  content: "";
  position: absolute;
  left: 28px; right: 28px; bottom: 0;
  border-bottom: 1px solid rgba(255,255,255,0.1);
}

.foot-brand img { height: 52px; width: auto; margin-bottom: 24px; }
.foot-brand p { font-size: 0.92rem; line-height: 1.6; max-width: 38ch; color: rgba(255,255,255,0.65); margin: 0; }
.foot-certs { margin: 16px 0 0; font-size: 0.78rem; line-height: 1.6; color: rgba(255,255,255,0.5); }

.site-footer h4 {
  color: #fff;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  margin: 0 0 16px;
}
.site-footer ul { list-style: none; padding: 0; margin: 0; }
.site-footer ul li { margin-bottom: 8px; }
.site-footer ul li:last-child { margin-bottom: 0; }
.site-footer a { color: rgba(255,255,255,0.7); font-size: 0.92rem; transition: color 0.15s; }
.site-footer a:hover { color: #fff; }

/* The regulatory record, spanning the tracks declared above. */
.site-footer .foot-legal {
  row-gap: 24px;
  align-items: start;
  /* padding-block, NOT the padding shorthand: `.container` supplies the
     28px inline padding that puts this block's left edge on the brand
     column, and a shorthand here would zero it and pull the address 28px
     left of the logo. */
  padding-block: 24px;
}
.foot-entity  { grid-column: 1 / 3; }
.foot-austrac { grid-column: 3 / -1; }

.foot-entity { margin: 0; font-size: 0.84rem; line-height: 1.6; color: rgba(255,255,255,0.72); }
.foot-entity strong { color: #fff; font-weight: 700; letter-spacing: 0.01em; }
.foot-entity a { color: rgba(255,255,255,0.72); text-decoration: underline; text-underline-offset: 3px; }
.foot-entity a:hover { color: #fff; }
.foot-austrac {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.6;
  color: rgba(255,255,255,0.86);
  border-left: 3px solid var(--gf-cyan);
  padding-left: 16px;
}

.foot-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  padding-top: 24px;
  font-size: 0.84rem;
}
.b2be-credit { display: inline-flex; align-items: center; gap: 8px; }
.b2be-credit img { height: 22px; width: auto; display: inline-block; vertical-align: middle; opacity: 0.95; }

/* Below full width the five tracks stop being readable, so both grids
   re-track together and the legal children stop spanning. */
@media (max-width: 1080px) {
  .site-footer .foot-grid,
  .site-footer .foot-legal { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .foot-entity  { grid-column: 1 / 2; }
  .foot-austrac { grid-column: 2 / -1; }
}
@media (max-width: 880px) {
  .site-footer .foot-grid,
  .site-footer .foot-legal { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .foot-entity  { grid-column: 1 / -1; }
  .foot-austrac { grid-column: 1 / -1; }
}
@media (max-width: 540px) {
  .site-footer .foot-grid,
  .site-footer .foot-legal { grid-template-columns: 1fr; }
}

/* ============================================================
   SUBTLE BRAND DECORATION
   ============================================================ */
.bg-swirl-decoration {
  position: relative;
  overflow: hidden;
}
.bg-swirl-decoration::before { display: none; }
.bg-swirl-decoration > * { position: relative; z-index: 1; }

/* ============================================================
   LEVER + OUTCOME COLOR & SHAPE IDENTITY (non-blue, distinctive)
   ============================================================
   Lever 1 / Method / Working Capital → Emerald + circles (cycle/flow)
   Lever 2 / Timing / EBITDA          → Amber  + squares (settled tile)
   Swirls are removed from these surfaces and replaced with
   shape-based geometric patterns in the lever's own colour.
   ============================================================ */

/* The emerald / amber lever palette that used to be declared here was
   dead: every one of its eight tokens is redeclared from the accent
   ramps further down the file, so only that later block was ever live.
   Removed rather than left as a trap for anyone reading top-down. */

/* ---- Page-level theme (epayment / dyn-disc / outcome-wc / outcome-ebitda) ---- */
body[data-theme="lever-method"],
body[data-theme="outcome-wc"] {
  --theme-accent: var(--lv-method);
  --theme-accent-deep: #065F46;
  --theme-accent-bright: var(--lv-method-bright);
  --theme-tint-50:  var(--lv-method-tint);
  --theme-tint-100: var(--lv-method-tint-2);
}
body[data-theme="lever-timing"],
body[data-theme="outcome-ebitda"] {
  --theme-accent: var(--lv-timing);
  --theme-accent-deep: #92400E;
  --theme-accent-bright: var(--lv-timing-bright);
  --theme-tint-50:  var(--lv-timing-tint);
  --theme-tint-100: var(--lv-timing-tint-2);
}

/* Page hero: drop the blue swirl image, replace with a flat
   accent-coloured wash + the page's signature shape pattern.        */
body[data-theme="lever-method"] .page-hero::before,
body[data-theme="outcome-wc"]   .page-hero::before,
body[data-theme="lever-timing"] .page-hero::before,
body[data-theme="outcome-ebitda"] .page-hero::before {
  background-image: none;
  opacity: 1;
}
body[data-theme="lever-method"] .page-hero::after,
body[data-theme="outcome-wc"]   .page-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'><g fill='none' stroke='white' stroke-width='1.4' opacity='0.18'><circle cx='40' cy='40' r='26'/><circle cx='40' cy='40' r='14'/><circle cx='120' cy='120' r='26'/><circle cx='120' cy='120' r='14'/></g></svg>");
  background-size: 160px 160px;
  background-position: right -40px top -40px;
  background-repeat: repeat;
  mask-image: linear-gradient(95deg, transparent 0%, transparent 35%, black 100%);
  -webkit-mask-image: linear-gradient(95deg, transparent 0%, transparent 35%, black 100%);
}
body[data-theme="lever-timing"]  .page-hero::after,
body[data-theme="outcome-ebitda"] .page-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140' viewBox='0 0 140 140'><g fill='none' stroke='white' stroke-width='1.4' opacity='0.20'><rect x='14' y='14' width='40' height='40'/><rect x='26' y='26' width='16' height='16'/><rect x='86' y='86' width='40' height='40'/><rect x='98' y='98' width='16' height='16'/></g></svg>");
  background-size: 140px 140px;
  background-position: right -30px top -30px;
  background-repeat: repeat;
  mask-image: linear-gradient(95deg, transparent 0%, transparent 35%, black 100%);
  -webkit-mask-image: linear-gradient(95deg, transparent 0%, transparent 35%, black 100%);
}
/* A chip fill used to sit here — translucent white, so the label stayed
   readable over the pattern this pass introduced. It was silently overriding
   the accent fill declared 1600 lines above it. Hero eyebrows are plain text
   now, and the cyan reads cleanly over the pattern without a fill behind it. */

/* ---- Index + how-it-works LEVER cards: drop the swirl, apply colour+shape ---- */
.lever-grid .lever:nth-child(1) {
  background: linear-gradient(180deg, var(--lv-method-tint) 0%, #FFFFFF 60%);
  border-top-color: var(--lv-method);
}
.lever-grid .lever:nth-child(2) {
  background: linear-gradient(180deg, var(--lv-timing-tint) 0%, #FFFFFF 60%);
  border-top-color: var(--lv-timing);
}
.lever::after {
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 120 120'><g fill='none' stroke='%23047857' stroke-width='1.6' opacity='0.55'><circle cx='30' cy='30' r='20'/><circle cx='30' cy='30' r='10'/><circle cx='90' cy='90' r='20'/><circle cx='90' cy='90' r='10'/></g></svg>");
  background-size: 120px 120px;
  background-repeat: repeat;
  background-position: right -20px bottom -20px;
  width: 60%;
  height: 75%;
  filter: none;
  opacity: 0.75;
  transform: none;
  top: auto; right: 0; bottom: 0; left: auto;
}
.lever-grid .lever:nth-child(2)::after {
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'><g fill='none' stroke='%23B45309' stroke-width='1.6' opacity='0.55'><rect x='14' y='14' width='32' height='32'/><rect x='22' y='22' width='16' height='16'/><rect x='66' y='66' width='32' height='32'/><rect x='74' y='74' width='16' height='16'/></g></svg>");
  background-size: 110px 110px;
  background-repeat: repeat;
  background-position: left -20px bottom -20px;
  transform: none;
  top: auto; bottom: 0; right: auto; left: 0;
  filter: none;
  opacity: 0.7;
}

/* Lever 1 (Method) typography accents → emerald */
.lever-grid .lever:nth-child(1) .lever-tag {
  background: var(--lv-method-tint-2);
  color: var(--lv-method);
}
.lever-grid .lever:nth-child(1) .lever-q { color: var(--lv-method); }
.lever-grid .lever:nth-child(1) ul li::before {
  background: var(--lv-method);
  border-radius: 999px;       /* circle */
  transform: none;
  width: 10px; height: 10px;
  top: 17px;
}
/* Lever 2 (Timing) typography accents → amber + square bullet */
.lever-grid .lever:nth-child(2) .lever-tag {
  background: var(--lv-timing-tint-2);
  color: var(--lv-timing);
}
.lever-grid .lever:nth-child(2) .lever-q { color: var(--lv-timing); }
.lever-grid .lever:nth-child(2) ul li::before {
  background: var(--lv-timing);
  border-radius: 1px;         /* sharp square */
  transform: none;
  width: 9px; height: 9px;
  top: 18px;
}

/* ---- Index PERSONA CARDS (Working Capital / EBITDA): same identity ---- */
.persona-card[data-outcome="working-capital"] {
  background: linear-gradient(155deg, var(--lv-method-tint) 0%, #FFFFFF 55%);
  border-top: 4px solid var(--lv-method);
}
.persona-card[data-outcome="ebitda"] {
  background: linear-gradient(155deg, var(--lv-timing-tint) 0%, #FFFFFF 55%);
  border-top: 4px solid var(--lv-timing);
}
/* Replace swirl with shape-pattern decoration */
.persona-card[data-outcome="working-capital"]::before,
.persona-card[data-outcome="ebitda"]::before {
  filter: none;
  opacity: 0.65;
  transform: none;
  background-size: 110px 110px;
  background-repeat: repeat;
  width: 320px; height: 320px;
}
.persona-card[data-outcome="working-capital"]::before {
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'><g fill='none' stroke='%23047857' stroke-width='1.5' opacity='0.55'><circle cx='28' cy='28' r='18'/><circle cx='28' cy='28' r='9'/><circle cx='82' cy='82' r='18'/><circle cx='82' cy='82' r='9'/></g></svg>");
  right: -100px; top: -100px;
  left: auto; bottom: auto;
}
.persona-card[data-outcome="ebitda"]::before {
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'><g fill='none' stroke='%23B45309' stroke-width='1.5' opacity='0.55'><rect x='12' y='12' width='32' height='32'/><rect x='20' y='20' width='16' height='16'/><rect x='66' y='66' width='32' height='32'/><rect x='74' y='74' width='16' height='16'/></g></svg>");
  left: -100px; bottom: -100px;
  right: auto; top: auto;
}
.persona-card:hover::before { opacity: 0.85; }
.persona-card[data-outcome="working-capital"] .pc-icon {
  background: var(--lv-method);
}
.persona-card[data-outcome="ebitda"] .pc-icon {
  background: var(--lv-timing);
  border-radius: 6px;          /* squared icon for the 'square' identity */
}
.persona-card[data-outcome="working-capital"] .pc-role { color: var(--lv-method); }
.persona-card[data-outcome="ebitda"] .pc-role { color: var(--lv-timing); }
.persona-card[data-outcome="working-capital"] .pc-cta { color: var(--lv-method); }
.persona-card[data-outcome="ebitda"] .pc-cta { color: var(--lv-timing); }
.persona-card[data-outcome="working-capital"]:hover { border-color: var(--lv-method); }
.persona-card[data-outcome="ebitda"]:hover { border-color: var(--lv-timing); }

/* ---- Themed page accents (quote borders / list bullets / callouts) ---- */
body[data-theme="lever-method"]  .quote,
body[data-theme="outcome-wc"]    .quote,
body[data-theme="lever-timing"]  .quote,
body[data-theme="outcome-ebitda"] .quote {
  border-left-color: var(--theme-accent);
}
body[data-theme] .feature-list li::before { background: var(--theme-accent); }
body[data-theme] .callout {
  background: linear-gradient(140deg, var(--theme-accent-deep) 0%, var(--theme-accent) 100%);
}

/* ---- BLOG GRID (was missing — restore 3-column responsive grid) ---- */
.blog-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}
@media (max-width: 1080px) {
  .blog-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 720px) {
  .blog-grid { grid-template-columns: 1fr; }
}
.case-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px;
}
@media (max-width: 880px) {
  .case-grid { grid-template-columns: 1fr; }
}
/* drop the swirl from blog/case card hero strips — keep clean colour band */
.bc-image::before { display: none; }
.blog-card .bc-image,
.case-card .bc-image {
  background: linear-gradient(140deg, var(--gf-blue) 0%, var(--gf-blue-deep) 100%);
}
/* meta colour stays brand blue (was royal) for consistency */
.bc-meta, .bc-cta { color: var(--gf-blue); }


/* ============================================================
   v3 → BRAND SYSTEM BRIDGE
   ------------------------------------------------------------
   The pages carry components built after this stylesheet was
   written (calculator, events, role cards, timelines, matrices).
   Below: the tokens those components reference, remapped onto
   the brand palette above, then the components themselves.
   Nothing here overrides the brand system — it extends it.
   ============================================================ */

:root {
  /* Colour aliases used by the carried-forward components */
  --gf-indigo:      var(--gf-royal);
  --gf-indigo-soft: #EEF2FF;
  --gf-indigo-line: #C7D2FE;
  --gf-blue-dark:   var(--gf-blue-deep);
  --ink-3:          var(--ink-2);
  --muted-2:        var(--muted);
  --bg:             var(--white);
  --bg-soft:        var(--soft);
  --bg-cool:        #E4E9F4;
  --bg-cool-2:      var(--softer);
  --line-2:         var(--line-soft);

  --green-soft:     rgba(13,138,95,0.08);
  --green-line:     rgba(13,138,95,0.30);
  --amber-soft:     rgba(183,121,31,0.08);
  --amber-line:     rgba(183,121,31,0.30);
  --red:            #B42318;
  --red-soft:       #FEE4E2;

  --radius-sm:      10px;
  --radius-xl:      var(--radius-lg);
  --shadow-blue:    0 8px 28px rgba(30,58,138,0.22);
}

/* ------------------------------------------------------------
   BRAND LOCK-UP
   The supplied GlobalFinex asset is a stacked 2:1 lock-up, not a
   horizontal one, so 38px tall left the wordmark unreadable.
   ------------------------------------------------------------ */
.nav-brand img { height: 46px; }
.site-header .nav { padding-top: 12px; padding-bottom: 12px; }
.b2be-credit img { height: 22px; }
.b2be-mark img { max-width: 190px; }

/* ------------------------------------------------------------
   HERO FOOTNOTE — the heroes here are dark, so the v3 muted
   grey was unreadable against the swirl.
   ------------------------------------------------------------ */
.hero .hero-foot,
.page-hero .hero-foot {
  margin-top: 20px;
  font-size: 0.86rem;
  color: rgba(255,255,255,0.62);
}
.hero .hero-foot strong, .page-hero .hero-foot strong { color: rgba(255,255,255,0.85); }


/* ---------- Components carried forward from v3 ---------- */

/* -------- Stats / proof strip -------- */
.stat-row {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 24px; padding: 32px; background: #fff;
  border-radius: var(--radius-lg); border: 1px solid var(--line);
}
@media (max-width: 900px) {
   .stat-row { grid-template-columns: repeat(2, 1fr); }
}
.stat .stat-num { font-size: 2rem; font-weight: 800; color: var(--gf-blue); letter-spacing: -0.02em; }
.stat .stat-label { font-size: 0.85rem; color: var(--muted); }
.feature-list.list-info .fl-icon { background: var(--gf-indigo-soft); color: var(--gf-blue); }
.comp-table .check { color: var(--green); font-weight: 700; }

.blog-card.placeholder-slot {
  border-style: dashed;
  border-color: var(--gf-indigo-line);
  background: var(--bg-soft);
}
.blog-card.placeholder-slot .bc-image::before { content: 'Future article slot'; }
.blog-card.placeholder-slot .bc-body p { color: var(--muted); font-style: italic; }
.article-hero .meta {
  display: flex; gap: 16px; align-items: center;
  font-size: 0.85rem; color: var(--muted); margin-bottom: 20px; flex-wrap: wrap;
}
.article-hero .meta span { display: inline-flex; align-items: center; gap: 6px; }
.case-card .cc-logo {
  height: 56px; margin-bottom: 20px;
  display: flex; align-items: center;
  font-weight: 800; font-size: 1.6rem; color: var(--ink); letter-spacing: -0.02em;
}
.case-card .cc-tag {
  display: inline-block; font-size: 0.7rem; font-weight: 700;
  letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--gf-blue); margin-bottom: 8px;
}
.case-card .cc-stats {
  display: flex; gap: 24px; margin: 16px 0;
  padding: 14px 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.case-card .cc-stats .stat-num { font-size: 1.4rem; }
.case-card.placeholder-slot {
  border-style: dashed;
  border-color: var(--gf-indigo-line);
  background: var(--bg-soft);
}
.case-card.placeholder-slot .cc-logo { color: var(--muted-2); }
.case-card.placeholder-slot p { color: var(--muted); font-style: italic; }
.alt-table .alt-name, .comp-table .alt-name { font-weight: 700; color: var(--ink); }
.alt-table .alt-where, .comp-table .alt-where { color: var(--muted); font-size: 0.85rem; margin-top: 4px; }
/* -------- Contact form -------- */
.contact-grid { display: grid; grid-template-columns: 5fr 4fr; gap: 56px; align-items: start; }
@media (max-width: 900px) {
   .contact-grid { grid-template-columns: 1fr; gap: 32px; }
}
/* Icon tile beside each contact row in the dev templates.
   Restored with .btn-lg and .g-title — see the note on .btn-lg. */
.contact-info .info-icon {
  flex-shrink: 0; width: 40px; height: 40px;
  background: var(--gf-indigo-soft); color: var(--gf-blue);
  border-radius: 8px; display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
.contact-info .info-row {
  display: flex; gap: 16px; margin-bottom: 24px;
}
.contact-info h4 { margin-bottom: 4px; font-size: 0.95rem; }
.contact-info p { color: var(--muted); font-size: 0.92rem; margin: 0; }
.lever-mini .lm-tag {
  font-size: 0.7rem; font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--gf-blue); margin-bottom: 8px;
  display: block;
}
/* -------- Hero foot note -------- */
.hero-foot {
  margin-top: 18px; font-size: 0.85rem; color: var(--muted);
}
/* -------- Reversibility-as-rhythm strip (homepage + how-it-works) -------- */
.rhythm-strip {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
  margin-top: 32px;
}
@media (max-width: 800px) {
   .rhythm-strip { grid-template-columns: 1fr; }
}
.rhythm-step {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 22px; position: relative;
  transition: transform .15s ease, box-shadow .15s ease;
}
.rhythm-step.is-on {
  background: linear-gradient(160deg, var(--gf-indigo-soft), #fff);
  border-color: var(--gf-blue);
  box-shadow: 0 8px 24px rgba(28,56,196,0.10);
}
.rhythm-step .rs-tag {
  display: inline-block; font-size: 0.7rem; font-weight: 700;
  letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--muted); margin-bottom: 10px;
}
.rhythm-step.is-on .rs-tag { color: var(--gf-blue); }
.rhythm-step .rs-body { color: var(--ink-2); font-size: 0.95rem; line-height: 1.45; }
/* -------- Role grid (homepage routing) -------- */
.role-grid {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px;
  margin-top: 16px;
}
@media (max-width: 1024px) {
   .role-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
   .role-grid { grid-template-columns: 1fr; }
}
.role-card {
  display: flex; flex-direction: column; gap: 6px;
  padding: 18px; background: #fff;
  border: 1px solid var(--line); border-radius: var(--radius);
  text-decoration: none; color: var(--ink);
  transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease;
}
.role-card:hover {
  border-color: var(--gf-blue); transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(28,56,196,0.10);
  text-decoration: none;
}
.role-card .rc-tag {
  font-size: 0.72rem; font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--gf-blue);
}
.role-card .rc-line {
  font-size: 0.95rem; font-weight: 600; color: var(--ink-2); line-height: 1.35;
}
/* -------- Ghost button on dark backgrounds (used inside callouts) -------- */
.btn.ghost-on-dark {
  background: transparent; color: #fff;
  border: 1.5px solid rgba(255,255,255,0.4);
}
.btn.ghost-on-dark:hover {
  background: rgba(255,255,255,0.08);
  border-color: rgba(255,255,255,0.7);
  color: #fff; text-decoration: none;
}
/* ============================================================
   LEVER CALCULATOR
   ============================================================ */
.calc-frame {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-xl);
  padding: 32px; box-shadow: var(--shadow); display: grid;
  grid-template-columns: 1fr 1.4fr; gap: 32px; align-items: stretch;
}
@media (max-width: 900px) {
   .calc-frame { grid-template-columns: 1fr; gap: 24px; padding: 22px; }
}
.calc-controls {
  background: var(--bg-soft); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 22px;
}
.calc-controls h3 { font-size: 1rem; margin-bottom: 18px; }
.calc-field { margin-bottom: 18px; }
.calc-field label {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 0.85rem; font-weight: 600; color: var(--ink-2); margin-bottom: 8px;
}
.calc-field label .calc-value {
  font-weight: 700; color: var(--gf-blue); font-variant-numeric: tabular-nums;
}
.calc-field input[type="range"] {
  width: 100%; -webkit-appearance: none; appearance: none;
  height: 6px; background: var(--line);
  border-radius: 999px; outline: none; cursor: pointer;
}
.calc-field input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--gf-blue); cursor: pointer; border: 2px solid #fff;
  box-shadow: 0 2px 6px rgba(28,56,196,0.35);
}
.calc-field input[type="range"]::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--gf-blue); cursor: pointer; border: 2px solid #fff;
  box-shadow: 0 2px 6px rgba(28,56,196,0.35);
}
.calc-field input[type="number"] {
  width: 100%; padding: 10px 12px; border: 1px solid var(--line);
  border-radius: 8px; font-size: 0.95rem; font-family: inherit;
  background: #fff;
}
.calc-field input[type="number"]:focus { outline: none; border-color: var(--gf-blue); box-shadow: 0 0 0 3px rgba(28,56,196,0.15); }
.calc-field .calc-helper {
  font-size: 0.78rem; color: var(--muted); margin-top: 6px; line-height: 1.4;
}
.calc-output { display: flex; flex-direction: column; gap: 14px; }
.calc-headline {
  background: linear-gradient(135deg, var(--gf-blue), var(--gf-blue-deep));
  color: #fff; border-radius: var(--radius-lg); padding: 24px;
}
.calc-headline .ch-tag {
  display: inline-block; font-size: 0.7rem; font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; color: rgba(255,255,255,0.7); margin-bottom: 14px;
}
.calc-headline .ch-value {
  font-size: clamp(1.8rem, 4vw, 2.6rem); font-weight: 800; line-height: 1.1;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.calc-headline .ch-sub { font-size: 0.88rem; color: rgba(255,255,255,0.78); margin-top: 6px; }
/* Three-lens output layout inside calc-headline */
.calc-headline .ch-row {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
  align-items: stretch;
}
@media (max-width: 700px) {
   .calc-headline .ch-row { grid-template-columns: 1fr; }
}
.calc-headline .ch-cell {
  padding: 10px 14px;
  border-left: 2px solid rgba(255,255,255,0.18);
}
.calc-headline .ch-cell:first-child { border-left: 0; padding-left: 0; }
.calc-headline .ch-cell-label {
  font-size: 0.72rem; font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; color: rgba(255,255,255,0.7);
  margin-bottom: 6px;
}
.calc-headline .ch-cell-value {
  font-size: clamp(1.6rem, 3.6vw, 2.2rem); font-weight: 800; line-height: 1.05;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em; color: #fff;
}
.calc-headline .ch-cell-sub {
  font-size: 0.78rem; color: rgba(255,255,255,0.6); margin-top: 6px;
}
/* Lever toggle buttons */
.lever-toggle-row {
  display: grid; grid-template-columns: 1fr; gap: 10px;
}
.lever-toggle {
  display: grid;
  grid-template-columns: 22px 1fr;
  grid-template-rows: auto auto;
  gap: 2px 12px;
  align-items: center;
  background: #fff; border: 1.5px solid var(--line); border-radius: 10px;
  padding: 14px 16px;
  font-family: inherit; cursor: pointer;
  text-align: left;
  transition: border-color .15s ease, background .15s ease, transform .1s ease;
}
.lever-toggle:hover { border-color: var(--gf-indigo-line); }
.lever-toggle .lt-state {
  grid-row: 1 / 3; grid-column: 1;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--line); border: 2px solid var(--line);
  transition: background .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.lever-toggle .lt-name {
  grid-row: 1; grid-column: 2;
  font-weight: 700; color: var(--ink-2); font-size: 0.95rem;
}
.lever-toggle .lt-sub {
  grid-row: 2; grid-column: 2;
  font-size: 0.78rem; color: var(--muted);
}
.lever-toggle.is-on {
  border-color: var(--gf-blue);
  background: linear-gradient(160deg, var(--gf-indigo-soft), #fff);
}
.lever-toggle.is-on .lt-state {
  background: var(--gf-blue);
  border-color: var(--gf-blue);
  box-shadow: 0 0 0 4px rgba(28,56,196,0.12);
}
.lever-toggle.is-on .lt-name { color: var(--gf-blue-deep); }
/* Calculator floor + summary */
.calc-floor {
  margin: 14px 0 0; line-height: 1.5;
}
.calc-summary {
  margin-top: 14px;
  background: var(--gf-indigo-soft); border: 1px solid var(--gf-indigo-line);
  border-radius: var(--radius); padding: 14px 18px;
  font-size: 0.92rem; color: var(--gf-blue-deep); font-weight: 500;
}
/* ePayment money-and-days timeline */
.timeline-frame {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  padding: 32px 28px 28px;
  box-shadow: var(--shadow);
}
.timeline-head {
  font-size: 1.1rem; font-weight: 700; color: var(--ink);
  text-align: center; margin: 0 0 6px;
}
.timeline-sub {
  text-align: center; font-size: 0.92rem; margin: 0 0 36px;
}
.timeline-row {
  position: relative; padding: 0 24px;
}
.timeline-track {
  position: relative; height: 110px;
}
.timeline-line {
  position: absolute; left: 0; right: 0; top: 28px;
  height: 4px;
  background: linear-gradient(90deg, var(--gf-indigo-line) 0%, var(--gf-indigo-line) 35%, var(--gf-blue) 35%, var(--gf-blue) 100%);
  border-radius: 999px;
}
.timeline-extension {
  position: absolute; top: 14px; left: 35%; right: 0;
  height: 32px;
  border: 1.5px dashed var(--gf-blue);
  border-bottom: 0;
  border-radius: 8px 8px 0 0;
  pointer-events: none;
}
.timeline-marker {
  position: absolute; top: 0;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center;
  text-align: center; min-width: 130px;
}
.timeline-marker::before {
  content: ''; display: block;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--gf-blue); border: 4px solid #fff;
  box-shadow: 0 0 0 2px var(--gf-blue);
  margin-top: 18px; margin-bottom: 12px;
}
.timeline-marker.is-mid::before { background: var(--gf-indigo); box-shadow: 0 0 0 2px var(--gf-indigo); }
.timeline-marker.is-end::before { background: var(--gf-blue-deep); box-shadow: 0 0 0 2px var(--gf-blue-deep); }
.timeline-marker .tm-day {
  font-weight: 700; color: var(--gf-blue-deep); font-size: 0.92rem;
  letter-spacing: 0.04em; margin-bottom: 4px;
}
.timeline-marker .tm-event {
  font-size: 0.78rem; color: var(--ink-3); line-height: 1.35;
  max-width: 160px;
}
.timeline-summary {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
  margin-top: 32px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}
@media (max-width: 720px) {
  
  .timeline-summary { grid-template-columns: 1fr; }
  
  .timeline-marker .tm-event { max-width: 100px; font-size: 0.7rem; }
  
  .timeline-frame { padding: 22px 16px; }
  
  .timeline-row { padding: 0 8px; }
}
.ts-cell {
  display: flex; flex-direction: column; gap: 4px;
  padding: 12px 14px;
  background: var(--bg-soft); border: 1px solid var(--line);
  border-radius: var(--radius);
}
.ts-cell.is-headline {
  background: linear-gradient(135deg, var(--gf-blue), var(--gf-blue-deep));
  border-color: var(--gf-blue);
  color: #fff;
}
.ts-cell .ts-label {
  font-size: 0.72rem; font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--muted);
}
.ts-cell.is-headline .ts-label { color: rgba(255,255,255,0.7); }
.ts-cell .ts-value {
  font-size: 1rem; font-weight: 700; color: var(--ink-2);
}
.ts-cell.is-headline .ts-value { color: #fff; font-size: 1.15rem; }
/* Lever-and-outcome 2x2 matrix */
.lever-matrix {
  background: #fff; border: 1px solid var(--line);
  border-radius: var(--radius-xl); overflow: hidden;
  box-shadow: var(--shadow);
}
.lever-matrix-row {
  display: grid;
  grid-template-columns: 200px 1fr 1fr;
  border-top: 1px solid var(--line);
}
.lever-matrix-row:first-child { border-top: 0; }
.lever-matrix-row.is-head {
  background: var(--bg-soft);
}
.lever-matrix-cell {
  padding: 22px 24px;
  border-left: 1px solid var(--line);
}
.lever-matrix-cell:first-child { border-left: 0; }
.lever-matrix-cell.is-axis {
  background: var(--gf-indigo-soft);
  font-weight: 700; color: var(--gf-blue-deep);
  display: flex; flex-direction: column; justify-content: center;
}
.lever-matrix-cell.is-head {
  font-weight: 700; color: var(--ink); font-size: 0.92rem;
  letter-spacing: 0.04em; text-transform: uppercase;
}
.lever-matrix-cell .lm-name {
  font-size: 1.05rem;
}
.lever-matrix-cell .lm-tag {
  font-size: 0.72rem; font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--gf-blue);
  margin-bottom: 4px;
}
.lever-matrix-cell .lm-contribution {
  font-weight: 600; color: var(--ink-2); font-size: 0.95rem;
  margin-bottom: 4px;
}
.lever-matrix-cell .lm-detail {
  font-size: 0.85rem; color: var(--muted); line-height: 1.4;
}
.lever-matrix-cell .lm-none {
  font-size: 0.85rem; color: var(--muted); font-style: italic;
}
/* The per-cell outcome label exists only once the column heads are gone.
   Above the breakpoint the head row says it, and repeating it in every
   cell would be noise. See the mobile block below. */
.lever-matrix-cell .lm-outcome { display: none; }
@media (max-width: 720px) {
  /* The matrix stops being a matrix. The shell unwraps and each lever row
     becomes its own card. The column heads cannot survive the collapse —
     stacked, they orphan at the top above an empty spacer cell and every
     cell below reads unlabelled — so they are hidden here and each content
     cell carries its own .lm-outcome label instead. Outcome order is
     fixed, working capital then EBITDA, so the cards stay comparable
     top-to-bottom the way the columns were. See round 2026-09-21a. */
  .lever-matrix {
    background: transparent; border: 0; border-radius: 0;
    box-shadow: none; overflow: visible;
    display: grid; gap: 16px;
  }
  .lever-matrix-row.is-head { display: none; }
  .lever-matrix-row {
    grid-template-columns: 1fr;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--white);
    box-shadow: var(--shadow);
    overflow: hidden;
  }
  .lever-matrix-cell {
    border-left: 0; border-top: 0;
    padding: 16px;
  }
  .lever-matrix-cell.is-axis {
    /* desktop centres this cell vertically in a tall row; as a card header
       strip the same rule would centre it horizontally against a
       left-aligned card, so the flex axis is reset alongside the direction */
    flex-direction: row; justify-content: flex-start;
    align-items: baseline; gap: 8px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--line);
  }
  .lever-matrix-cell.is-axis .lm-tag { margin-bottom: 0; }
  .lever-matrix-cell:not(.is-axis) + .lever-matrix-cell:not(.is-axis) {
    border-top: 1px solid var(--line-soft);
  }
  /* The outcome label is the small uppercase label above a statement, which
     is what .eyebrow is, so the cell carries the component rather than a
     private copy of it: size, weight, tracking and the light/dark ink pair
     all come from the one eyebrow definition, and a page that tints its
     eyebrow ink tints this too. Only the spacing is local — .eyebrow ships
     a 14px bottom margin for use above a heading, and this label sits
     tighter to the line it introduces. See round 2026-09-21a. */
  .lever-matrix-cell .lm-outcome {
    display: inline-block;
    margin-bottom: 8px;
  }
}
/* Calculator maths accordion */
.calc-maths {
  margin-top: 24px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.calc-maths summary {
  list-style: none;
  cursor: pointer;
  padding: 14px 18px;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--gf-blue);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.calc-maths summary::-webkit-details-marker { display: none; }
.calc-maths summary::after {
  content: '+';
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--gf-indigo-soft);
  color: var(--gf-blue);
  font-weight: 700;
  font-size: 0.95rem;
  transition: transform .15s ease;
}
.calc-maths[open] summary::after { content: '−'; }
.calc-maths summary:hover { background: var(--bg-soft); }
.calc-maths-body {
  padding: 18px 18px 20px;
  border-top: 1px solid var(--line);
}
.calc-maths-body h4 {
  margin: 18px 0 8px;
  font-size: 0.88rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.calc-maths-body p {
  font-size: 0.9rem;
  color: var(--ink-3);
  line-height: 1.55;
  margin: 0 0 10px;
}
.calc-maths-body ul {
  margin: 0 0 12px;
  padding-left: 18px;
}
.calc-maths-body li {
  font-size: 0.88rem;
  color: var(--ink-3);
  line-height: 1.5;
  margin-bottom: 4px;
}
.calc-card .cc-tag {
  display: block; font-size: 0.7rem; font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--gf-blue); margin-bottom: 8px;
}
.calc-rhythm .rh-bar.is-active { background: var(--gf-blue); }
.calc-mode-toggle {
  display: inline-flex; background: var(--bg-soft); border: 1px solid var(--line);
  border-radius: 999px; padding: 4px; gap: 0;
}
.calc-mode-toggle button {
  border: 0; background: transparent; padding: 6px 14px; border-radius: 999px;
  font-size: 0.82rem; font-weight: 600; color: var(--muted); cursor: pointer;
  font-family: inherit;
}
.calc-mode-toggle button.is-active { background: var(--gf-blue); color: #fff; }
/* ============================================================
   COMPARISON / ALTERNATIVES — category cards
   ============================================================ */
.cat-grid {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px;
}
@media (max-width: 800px) {
   .cat-grid { grid-template-columns: 1fr; }
}
.cat-card {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 24px; display: flex; flex-direction: column; gap: 14px;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.cat-card:hover { border-color: var(--gf-indigo-line); box-shadow: var(--shadow); }
.cat-card .cat-head {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 16px;
}
.cat-card .cat-name { font-size: 1.1rem; font-weight: 700; color: var(--ink); margin: 0; line-height: 1.25; }
.cat-card .cat-tag {
  font-size: 0.65rem; font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--muted); white-space: nowrap;
  background: var(--bg-soft); border: 1px solid var(--line);
  padding: 4px 10px; border-radius: 999px;
}
.cat-card .cat-body { font-size: 0.9rem; color: var(--ink-3); line-height: 1.5; margin: 0; }
.cat-card .cat-row {
  display: grid; grid-template-columns: auto 1fr; gap: 8px 14px; align-items: baseline;
  font-size: 0.85rem;
}
.cat-card .cat-row dt {
  font-weight: 700; color: var(--ink-2); white-space: nowrap;
}
.cat-card .cat-row dd { margin: 0; color: var(--ink-3); }
.cat-card .cat-foot {
  font-size: 0.85rem; color: var(--gf-blue); font-weight: 600;
  padding-top: 10px; border-top: 1px solid var(--line);
}
/* ============================================================
   EVENTS placeholder
   ============================================================ */
.events-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
}
@media (max-width: 900px) {
   .events-grid { grid-template-columns: 1fr; }
}
.event-card {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 24px; display: flex; flex-direction: column; gap: 12px;
  position: relative; min-height: 200px;
}
.event-card .ev-type {
  font-size: 0.7rem; font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--gf-blue);
}
.event-card .ev-title { font-size: 1.05rem; font-weight: 700; color: var(--ink); }
.event-card .ev-meta { font-size: 0.85rem; color: var(--muted); }
.event-card .ev-body { font-size: 0.9rem; color: var(--ink-3); line-height: 1.5; flex: 1; }
.event-card.is-coming-soon {
  background: linear-gradient(160deg, var(--gf-indigo-soft), #fff);
  border-color: var(--gf-indigo-line);
}
.event-card.is-coming-soon::after {
  content: 'Coming soon'; position: absolute; top: 14px; right: 14px;
  background: var(--gf-blue); color: #fff;
  font-size: 0.65rem; font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; padding: 4px 10px; border-radius: 999px;
}
/* ============================================================
   FEATURED EVENT
   ============================================================ */
.featured-event {
  display: grid; grid-template-columns: 1.6fr 1fr; gap: 28px;
  background: linear-gradient(160deg, var(--gf-indigo-soft), #fff 65%);
  border: 1px solid var(--gf-indigo-line); border-radius: var(--radius-lg);
  padding: 36px; margin-top: 8px;
}
@media (max-width: 900px) {
   .featured-event { grid-template-columns: 1fr; padding: 24px; }
}
.fe-body h3 {
  font-size: 1.5rem; line-height: 1.25; margin: 8px 0 14px; color: var(--ink);
}
.fe-tag {
  display: inline-block; font-size: 0.72rem; font-weight: 700;
  letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--gf-blue); background: #fff;
  padding: 5px 12px; border-radius: 999px; border: 1px solid var(--gf-indigo-line);
}
.fe-body p { color: var(--ink-3); line-height: 1.6; margin: 0 0 18px; }
.fe-meta {
  list-style: none; padding: 0; margin: 0 0 22px;
  display: grid; gap: 8px; font-size: 0.92rem; color: var(--ink-2);
}
.fe-meta li { padding-left: 0; }
.fe-meta strong {
  display: inline-block; min-width: 110px; color: var(--gf-blue);
  font-weight: 700; font-size: 0.78rem; letter-spacing: var(--track-label);
  text-transform: uppercase;
}
.fe-cta-row { display: flex; flex-wrap: wrap; gap: 12px; }
.fe-side { align-self: stretch; }
.fe-side-card {
  background: #fff; border: 1px solid var(--line);
  border-radius: var(--radius); padding: 22px;
  height: 100%; display: flex; flex-direction: column; gap: 10px;
}
.fe-side-label {
  font-size: 0.7rem; font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--gf-blue);
}
.fe-side-card p { color: var(--ink-3); line-height: 1.55; font-size: 0.95rem; margin: 0; }
/* ============================================================
   AGENDA TIMELINE
   ============================================================ */
.agenda-frame {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-lg);
  overflow: hidden;
}
.agenda-row {
  display: grid; grid-template-columns: 160px 1fr; gap: 24px;
  padding: 18px 24px; border-bottom: 1px solid var(--line);
}
.agenda-row:last-child { border-bottom: none; }
.agenda-time {
  font-weight: 700; color: var(--gf-blue); font-size: 0.92rem;
  letter-spacing: 0.02em; padding-top: 2px;
}
.agenda-title {
  font-weight: 700; color: var(--ink); font-size: 1rem; line-height: 1.4;
}
.agenda-body {
  margin-top: 6px; color: var(--ink-3); font-size: 0.92rem; line-height: 1.55;
}
@media (max-width: 720px) {
  
  .agenda-row { grid-template-columns: 1fr; gap: 4px; padding: 16px 18px; }
}
/* ============================================================
   LOCATION CARDS
   ============================================================ */
.location-grid {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; margin-top: 24px;
}
@media (max-width: 720px) {
   .location-grid { grid-template-columns: 1fr; }
}
.location-card {
  background: #fff; border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 24px;
}
.loc-city {
  display: inline-block; font-size: 1.25rem; font-weight: 700;
  color: var(--ink); margin-bottom: 14px;
}
.loc-line {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 8px 0; border-bottom: 1px dashed var(--line);
  font-size: 0.92rem;
}
.loc-line:last-of-type { border-bottom: none; }
.loc-line span {
  color: var(--muted); font-size: 0.78rem; font-weight: 700;
  letter-spacing: var(--track-label); text-transform: uppercase;
}
.loc-line strong { color: var(--ink); font-weight: 600; }
/* ============================================================
   CHECKLIST + CALLOUT-SOFT + CONTACT FORM
   ============================================================ */
.checklist {
  list-style: none; padding: 0; margin: 16px 0 0;
  display: grid; gap: 10px;
}
.checklist li {
  position: relative; padding-left: 30px;
  color: var(--ink-2); font-size: 1rem; line-height: 1.5;
}
.checklist li::before {
  content: ''; position: absolute; left: 0; top: 6px;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--gf-indigo-soft);
}
/* The tick is optically centred in the circle: the old 1px border was
   carrying part of that centring, and a round marker shows an off-centre
   tick far more than a square one did. */
.checklist li::after {
  content: ''; position: absolute; left: 6px; top: 9.5px;
  width: 4px; height: 8px;
  border: solid var(--gf-blue); border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* ---- ROUND 2026-09-16e: a paragraph after a checklist gets a gap ----
   .checklist is margin: 16px 0 0 — bottom zero — so it leans on the
   next element's top margin for its clearance. .callout-soft brings
   18px of its own and looks correct; a plain <p> brings nothing, and
   the last list item sat flush against the paragraph under it on
   event-finance-roundtable-oct-2026.html.

   18px matches what .callout-soft already contributes after a
   checklist, so a section closing on a paragraph and one closing on a
   callout are separated on the same terms.

   Written as a component rule rather than scoped to that page: the
   adjacency appears nowhere else in the site today, so nothing else
   moves, and the gap belongs to the checklist rather than to the one
   section that happened to expose it. */
.checklist + p { margin-top: 18px; }
/* On a filled surface the indigo-tint dot lands on near-identical ground
   (.section-soft is #F4F5FC, the dot #EEF2FF), so the marker reverses to
   white. The drawn tick stays --gf-blue throughout. */
.section-soft  .checklist li::before,
.section-cool  .checklist li::before,
.callout-soft  .checklist li::before,
.card          .checklist li::before,
.card-feature  .checklist li::before {
  background: #fff;
}
.callout-soft {
  background: var(--gf-indigo-soft); border-left: 3px solid var(--gf-blue);
  border-radius: var(--radius); padding: 18px 22px; margin: 18px 0 0;
}
.field-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 18px;
}
@media (max-width: 720px) {
   .field-row { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------------
   CARRIED-FORWARD COMPONENTS ON DARK SECTIONS
   The v3 components assume a white page. .section-cool is the
   near-black brand blue, so they need their dark variants —
   the same treatment the brand system already gives .guardrail
   and .flow-step.
   ------------------------------------------------------------ */
.section-cool .rhythm-step,
.section-cool .role-card,
.section-cool .card,
.section-cool .card-feature {
  background: rgba(255,255,255,0.04);
  border-color: rgba(255,255,255,0.14);
  color: rgba(255,255,255,0.88);
}
.section-cool .rhythm-step.is-on {
  background: rgba(111,182,255,0.10);
  border-color: var(--gf-cyan);
  box-shadow: none;
}
.section-cool .rhythm-step .rs-tag { color: rgba(255,255,255,0.55); }
.section-cool .rhythm-step.is-on .rs-tag { color: var(--gf-cyan); }
.section-cool .rhythm-step .rs-body { color: rgba(255,255,255,0.80); }

.section-cool .role-card { color: rgba(255,255,255,0.88); }
.section-cool .role-card:hover {
  border-color: var(--gf-cyan);
  box-shadow: none;
  color: #fff;
}
.section-cool .role-card .rc-tag  { color: var(--gf-cyan); }
.section-cool .role-card .rc-line { color: rgba(255,255,255,0.88); }

.section-cool .card p,
.section-cool .card li { color: rgba(255,255,255,0.78); }
.section-cool .feature-list li { border-top-color: rgba(255,255,255,0.12); }
.section-cool .fl-body { color: rgba(255,255,255,0.82); }
.section-cool .fl-icon { background: var(--gf-cyan); color: var(--gf-blue-ink); }
.section-cool strong { color: #fff; }
.section-cool .tag { background: rgba(111,182,255,0.15); color: var(--gf-cyan); }
.section-cool .stat-num, .section-cool .stat .stat-num { color: #fff; }
.section-cool .stat-label, .section-cool .stat .stat-label { color: rgba(255,255,255,0.6); }
.section-cool .checklist .check { color: var(--gf-cyan); }
.section-cool .pull-quote {
  background: rgba(255,255,255,0.04);
  border-color: rgba(255,255,255,0.14);
  border-left-color: var(--gf-cyan);
}
.section-cool .quote-text { color: #fff; }
.section-cool .quote-attr { border-top-color: rgba(255,255,255,0.14); }
.section-cool .quote-attr-name { color: #fff; }
.section-cool .quote-attr-role { color: rgba(255,255,255,0.6); }
.section-cool .pull-quote::before { color: var(--gf-cyan); opacity: 0.22; }


/* ------------------------------------------------------------
   FIXES
   ------------------------------------------------------------ */

/* Article hero is dark here, so its meta line and any inline
   emphasis need the light treatment the other heroes get. */
.article-hero .meta,
.article-hero .meta span { color: rgba(255,255,255,0.72); }
.article-hero strong { color: #fff; }
.article-hero .muted { color: rgba(255,255,255,0.65); }

/* Timeline card sitting inside a dark section */
.section-cool .timeline-frame {
  background: rgba(255,255,255,0.05);
  border-color: rgba(255,255,255,0.14);
  box-shadow: none;
}
.section-cool .timeline-head { color: #fff; }
.section-cool .timeline-sub,
.section-cool .timeline-summary { color: rgba(255,255,255,0.72); }
.section-cool .timeline-line { background: rgba(255,255,255,0.22); }
.section-cool .timeline-marker .tm-day { color: rgba(255,255,255,0.62); }
.section-cool .timeline-marker .tm-event { color: rgba(255,255,255,0.9); }

/* .hero got the light ghost-button treatment but .page-hero and
   .article-hero never did, so a secondary CTA on an inner page
   rendered dark-on-dark. Same treatment, all three heroes. */
.page-hero .btn-ghost,
.article-hero .btn-ghost {
  color: #fff;
  background: rgba(255,255,255,0.06);
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,0.7);
  backdrop-filter: blur(2px);
}
.page-hero .btn-ghost:hover,
.article-hero .btn-ghost:hover {
  background: rgba(255,255,255,0.18);
  box-shadow: inset 0 0 0 1.5px #fff;
  color: #fff;
}

/* Inline links inside the dark heroes — the base link colour is
   royal blue, which disappears against the hero gradient. */
.hero a:not(.btn),
.page-hero a:not(.btn),
.article-hero a:not(.btn) {
  color: var(--gf-cyan);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.hero a:not(.btn):hover,
.page-hero a:not(.btn):hover,
.article-hero a:not(.btn):hover { color: #fff; }

/* .hero styles its <strong> white; .page-hero and .article-hero
   never did, so emphasised words fell back to near-black ink. */
.page-hero strong, .article-hero strong { color: #fff; }
.page-hero em, .article-hero em { color: inherit; }

/* ---- Dark surfaces: overrides that the theme rules were beating ---- */

/* Muted body copy on dark surfaces */
.section-cool .muted,
.page-hero .muted,
.hero .muted,
.article-hero .muted { color: rgba(255,255,255,0.65); }
.page-hero .lede .muted { color: inherit; }

/* Carried-forward timeline summary cells inside a dark section.
   The cells keep their own light surface, so recolour the cell —
   not the text — or the label/value go white-on-white. */
.section-cool .ts-cell:not(.is-headline) {
  background: rgba(255,255,255,0.06);
  border-color: rgba(255,255,255,0.14);
}
.section-cool .ts-cell:not(.is-headline) .ts-label { color: rgba(255,255,255,0.6); }
.section-cool .ts-cell:not(.is-headline) .ts-value { color: #fff; }

/* Emphasis inside the gradient outcome banner */
.outcome-highlight strong,
.calc-headline strong,
.ba-col.after strong,
.arch-card.is-gfx strong,
.flow-step.flow-key strong,
.callout strong { color: #fff; }

/* Footer B2BE credit is now a text link out to b2be.com */
.b2be-credit a { color: rgba(255,255,255,0.7); text-decoration: none; }
.b2be-credit a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }


/* ============================================================
   PRODUCT COLOUR — FLOW / PACE
   ------------------------------------------------------------
   Taken from the GlobalFinex Working Capital Levers deck:
     Flow (settlement method) → magenta  #AF126B → #EF007B
     Pace (settlement timing) → teal     #388DA1 → #60DFF1
   Replaces the earlier emerald-circles / amber-squares identity.
   Colour wash only — the shape patterns are removed.
   ============================================================ */

/* The deck's magenta / teal values that used to be declared here were
   likewise dead — superseded by the accent-ramp block further down.
   Their near-miss hexes (#AF126B, #2F7C8F, #60DFF1) were the reason the
   product colour looked almost-but-not-quite on-system. */

body[data-theme="lever-method"],
body[data-theme="outcome-wc"] {
  --theme-accent: var(--lv-method);
  --theme-accent-deep: #7A0C4A;
  --theme-accent-bright: var(--lv-method-bright);
  --theme-tint-50:  var(--lv-method-tint);
  --theme-tint-100: var(--lv-method-tint-2);
}
body[data-theme="lever-timing"],
body[data-theme="outcome-ebitda"] {
  --theme-accent: var(--lv-timing);
  --theme-accent-deep: color-mix(in srgb, var(--cyan-900) 70%, #000);
  --theme-accent-bright: var(--lv-timing-bright);
  --theme-tint-50:  var(--lv-timing-tint);
  --theme-tint-100: var(--lv-timing-tint-2);
}

/* Drop the shape-pattern overlays on the themed heroes — wash only. */
body[data-theme="lever-method"] .page-hero::after,
body[data-theme="outcome-wc"]   .page-hero::after,
body[data-theme="lever-timing"] .page-hero::after,
body[data-theme="outcome-ebitda"] .page-hero::after {
  background-image: none;
  background: linear-gradient(95deg, rgba(0,0,0,0.28) 0%, rgba(0,0,0,0.10) 55%, rgba(0,0,0,0) 100%);
  mask-image: none;
  -webkit-mask-image: none;
}

/* Lever cards: colour wash, no circles or squares. */
.lever::after,
.lever-grid .lever:nth-child(2)::after { background-image: none; content: none; }
.lever-grid .lever:nth-child(1) {
  background: linear-gradient(180deg, var(--lv-method-tint) 0%, #FFFFFF 62%);
  border-top-color: var(--lv-method);
}
.lever-grid .lever:nth-child(2) {
  background: linear-gradient(180deg, var(--lv-timing-tint) 0%, #FFFFFF 62%);
  border-top-color: var(--lv-timing);
}
.lever-grid .lever:nth-child(1) .lever-tag { background: var(--lv-method-tint-2); color: var(--lv-method); }
.lever-grid .lever:nth-child(2) .lever-tag { background: var(--lv-timing-tint-2); color: var(--lv-timing); }
.lever-grid .lever:nth-child(1) ul li::before { background: var(--lv-method); border-radius: 999px; transform: none; width: 9px; height: 9px; top: 17px; }
.lever-grid .lever:nth-child(2) ul li::before { background: var(--lv-timing); border-radius: 999px; transform: none; width: 9px; height: 9px; top: 17px; }

/* Outcome routing cards: same wash, no pattern. */
.persona-card[data-outcome="working-capital"]::before,
.persona-card[data-outcome="ebitda"]::before { content: none; background-image: none; }
.persona-card[data-outcome="working-capital"] {
  background: linear-gradient(155deg, var(--lv-method-tint) 0%, #FFFFFF 58%);
  border-top: 4px solid var(--lv-method);
}
.persona-card[data-outcome="ebitda"] {
  background: linear-gradient(155deg, var(--lv-timing-tint) 0%, #FFFFFF 58%);
  border-top: 4px solid var(--lv-timing);
}
.persona-card[data-outcome="ebitda"] .pc-icon { border-radius: 12px; }

/* Role routing boxes carry a visible link to each use case */
.role-card { justify-content: flex-start; }
.role-card .rc-cta {
  margin-top: auto; padding-top: 10px;
  font-size: 0.86rem; font-weight: 500; color: var(--gf-royal);
}
.role-card:hover .rc-cta { color: var(--gf-blue-deep); }
.section-cool .role-card .rc-cta { color: var(--gf-cyan); }

/* 'A cleaner alternative for suppliers' — header and body share one left edge,
   and the list text is justified so the box reads as a single block. */
/* The icon column pushes the list text 38px in (24px icon + 14px gap) while the
   heading sat flush to the card padding. Align the heading to the same column
   and justify the body so the block reads as one edge. */
/* Only cards that actually carry an icon list need the heading indent —
   otherwise the heading gets pushed in on plain cards and reads as centred. */
.card-feature:has(.feature-list) > h3 { padding-left: 38px; }
.card-feature .feature-list li { align-items: flex-start; }
.card-feature .feature-list .fl-body { text-align: justify; text-justify: inter-word; hyphens: auto; }
@media (max-width: 700px) {
  .card-feature:has(.feature-list) > h3 { padding-left: 0; }
  .card-feature .feature-list .fl-body { text-align: left; }
}


/* ============================================================
   NAV DROPDOWNS — forgiving hover
   ------------------------------------------------------------
   The panel sat 8px below the trigger, so the pointer crossed a
   dead gap on its way down and the menu closed. Two fixes: an
   invisible bridge across the gap, and a short grace period on
   hover-out so diagonal movement onto the panel survives.
   ============================================================ */
@media (min-width: 1081px) {
  .nav-links > li > .nav-dropdown {
    display: block;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(-6px);
    transition: opacity .15s ease, transform .15s ease, visibility 0s linear .28s;
  }
  /* Bridge the gap between trigger and panel */
  .nav-links > li > .nav-dropdown::before {
    content: '';
    position: absolute;
    left: 0; right: 0; top: -14px; height: 14px;
  }
  .nav-links > li:hover > .nav-dropdown,
  .nav-links > li:focus-within > .nav-dropdown,
  .nav-links > li > .nav-dropdown.is-open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateY(0);
    transition: opacity .15s ease, transform .15s ease, visibility 0s;
  }
  /* Keep the trigger looking active while its panel is open */
  .nav-links > li:hover > .nav-trigger,
  .nav-links > li:focus-within > .nav-trigger { background: var(--soft); color: var(--gf-blue); }
  .nav-links > li:hover .nav-trigger .caret,
  .nav-links > li:focus-within .nav-trigger .caret { transform: rotate(180deg); }
}

/* ---- Calculator: currency picker ---- */
.calc-cur-label {
  display: block; font-size: 0.78rem; font-weight: 600; letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--muted); margin-bottom: 8px;
}
.calc-currency { display: flex; gap: 6px; }
.calc-currency .cur-opt {
  flex: 1; padding: 9px 10px;
  background: #fff; border: 1.5px solid var(--line); border-radius: 999px;
  font: inherit; font-size: 0.86rem; font-weight: 500; color: var(--ink-2);
  transition: border-color .15s, background .15s, color .15s;
}
.calc-currency .cur-opt:hover { border-color: var(--gf-royal); color: var(--gf-royal); }
.calc-currency .cur-opt.is-on {
  background: var(--gf-blue); border-color: var(--gf-blue); color: #fff;
}

/* ---- Calculator: three output lenses share a baseline grid ----
   Label, value and sub-line each occupy their own row, so the three
   figures line up even when a label wraps to two lines. ---- */
/* Subgrid so label / value / sub-line share three rows across all three
   cells — the figures line up even when one label or value wraps. */
.calc-headline .ch-row {
  grid-template-rows: auto auto auto;
  align-items: stretch;
  row-gap: 0;
}
.calc-headline .ch-cell {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  row-gap: 6px;
}
.calc-headline .ch-cell-label { margin: 0; align-self: start; }
.calc-headline .ch-cell-value { margin: 0; align-self: start; }
.calc-headline .ch-cell-sub   { margin: 0; align-self: start; }
@supports not (grid-template-rows: subgrid) {
  .calc-headline .ch-cell { grid-template-rows: 2.6em auto 1fr; }
}
@media (max-width: 700px) {
  .calc-headline .ch-row { grid-template-rows: none; }
  .calc-headline .ch-cell { grid-row: auto; grid-template-rows: auto auto auto; }
}

/* ---- Combined page: both product colours in one wash ---- */
body[data-theme="combined"] {
  --theme-accent: var(--lv-method);
  --theme-accent-deep: #7A0C4A;
  --theme-accent-bright: var(--lv-timing-bright);
  --theme-tint-50:  #FBF4FA;
  --theme-tint-100: var(--lv-method-tint-2);
}
body[data-theme="combined"] .page-hero::before { background-image: none; opacity: 1; }
body[data-theme="combined"] .page-hero::after {
  content: '';
  background: linear-gradient(95deg, rgba(0,0,0,0.30) 0%, rgba(0,0,0,0.10) 55%, rgba(0,0,0,0) 100%);
  background-image: none;
  mask-image: none; -webkit-mask-image: none;
}
body[data-theme="combined"] .callout {
  background: linear-gradient(120deg, #7A0C4A 0%, var(--lv-method) 45%, #2F7C8F 100%);
}

/* About page: six group figures in one row */
.stat-row.stat-row-6 { grid-template-columns: repeat(6, 1fr); gap: 18px; }
.stat-row.stat-row-6 .stat-num { font-size: 1.7rem; }
@media (max-width: 1024px) { .stat-row.stat-row-6 { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px)  { .stat-row.stat-row-6 { grid-template-columns: repeat(2, 1fr); } }

/* The two company cards on the About page are B2BE and GlobalFinex, not
   Flow and Pace — keep the product colours off them. */
body[data-active-nav="about"] .lever-grid .lever:nth-child(1),
body[data-active-nav="about"] .lever-grid .lever:nth-child(2) {
  background: linear-gradient(180deg, var(--soft) 0%, #FFFFFF 60%);
  border-top-color: var(--gf-blue);
}
body[data-active-nav="about"] .lever-grid .lever:nth-child(2) { border-top-color: var(--gf-royal); }
body[data-active-nav="about"] .lever-grid .lever:nth-child(1) .lever-tag { background: rgba(30,58,138,0.10); color: var(--gf-blue); }
body[data-active-nav="about"] .lever-grid .lever:nth-child(2) .lever-tag { background: rgba(39,64,222,0.10); color: var(--gf-royal); }
body[data-active-nav="about"] .lever-grid .lever:nth-child(1) .lever-q { color: var(--gf-blue); }
body[data-active-nav="about"] .lever-grid .lever:nth-child(2) .lever-q { color: var(--gf-royal); }
body[data-active-nav="about"] .lever-grid .lever:nth-child(1) ul li::before { background: var(--gf-blue); }
body[data-active-nav="about"] .lever-grid .lever:nth-child(2) ul li::before { background: var(--gf-royal); }

/* White paper cover artwork (page 1 of the PDF, cropped to 4:5) */
.wp-cover { display: block; border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-lg); transition: transform .2s ease, box-shadow .2s ease; }
.wp-cover:hover { transform: translateY(-3px); box-shadow: 0 2px 4px rgba(11,23,51,0.08), 0 30px 70px rgba(11,23,51,0.16); }
.wp-cover img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover; }


/* ============================================================
   PRODUCT GRADIENTS — the full spectrum, not a single stop
   ------------------------------------------------------------
   The deck fills every product surface with a left-to-right
   two-stop fade, not a flat colour:
     Flow  #AF126B → #EF007B
     Pace  #388DA1 → #5ED6E8
   Applied here to every surface that carried a flat swatch:
   top rules, chips, bullets, icons, heroes and callouts.
   ============================================================ */
:root {
  --grad-flow: linear-gradient(90deg, #AF126B 0%, #EF007B 100%);
  --grad-pace: linear-gradient(90deg, #388DA1 0%, #5ED6E8 100%);
  --grad-flow-135: linear-gradient(135deg, #AF126B 0%, #EF007B 100%);
  --grad-pace-135: linear-gradient(135deg, #388DA1 0%, #5ED6E8 100%);
}

/* ---- Lever cards: gradient top rule, chip, bullets ---- */
.lever-grid .lever:nth-child(1),
.lever-grid .lever:nth-child(2) { border-top: 0; padding-top: 44px; position: relative; }
.lever-grid .lever:nth-child(1)::before,
.lever-grid .lever:nth-child(2)::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 5px; z-index: 2;
}
.lever-grid .lever:nth-child(1)::before { background: var(--grad-flow); }
.lever-grid .lever:nth-child(2)::before { background: var(--grad-pace); }
.lever-grid .lever:nth-child(1) .lever-tag { background: var(--grad-flow); color: #fff; }
.lever-grid .lever:nth-child(2) .lever-tag { background: var(--grad-pace); color: #06323C; }
.lever-grid .lever:nth-child(1) ul li::before { background: var(--grad-flow); }
.lever-grid .lever:nth-child(2) ul li::before { background: var(--grad-pace); }

/* ---- Outcome routing cards ---- */
.persona-card[data-outcome="working-capital"],
.persona-card[data-outcome="ebitda"] { border-top: 0; padding-top: 40px; }
.persona-card[data-outcome="working-capital"]::after,
.persona-card[data-outcome="ebitda"]::after {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; z-index: 2;
}
.persona-card[data-outcome="working-capital"]::after { background: var(--grad-flow); }
.persona-card[data-outcome="ebitda"]::after { background: var(--grad-pace); }
.persona-card[data-outcome="working-capital"] .pc-icon { background: var(--grad-flow-135); }
.persona-card[data-outcome="ebitda"] .pc-icon { background: var(--grad-pace-135); color: #06323C; }

/* ---- Themed pages: hero wash across the full fade ---- */
body[data-theme="lever-method"] .callout,
body[data-theme="outcome-wc"]   .callout { background: linear-gradient(120deg, #7A0C4A 0%, #AF126B 45%, #EF007B 100%); }
body[data-theme="lever-timing"]  .callout,
body[data-theme="outcome-ebitda"] .callout { background: linear-gradient(120deg, #1B4F5D 0%, #388DA1 45%, #5ED6E8 100%); }

/* Themed chips, bullets and labels take the fade too */
body[data-theme="lever-method"] .fl-icon,
body[data-theme="outcome-wc"]   .fl-icon,
body[data-theme="lever-method"] .g-label,
body[data-theme="outcome-wc"]   .g-label { background: var(--grad-flow-135); color: #fff; }
body[data-theme="lever-timing"]  .fl-icon,
body[data-theme="outcome-ebitda"] .fl-icon,
body[data-theme="lever-timing"]  .g-label,
body[data-theme="outcome-ebitda"] .g-label { background: var(--grad-pace-135); color: #06323C; }
body[data-theme="lever-method"] .tag,
body[data-theme="outcome-wc"]   .tag { background: var(--grad-flow); color: #fff; }
body[data-theme="lever-timing"]  .tag,
body[data-theme="outcome-ebitda"] .tag { background: var(--grad-pace); color: #06323C; }

/* ---- Combined page: Flow's fade running into Pace's ---- */
body[data-theme="combined"] .callout {
  background: linear-gradient(120deg, #AF126B 0%, #EF007B 38%, #388DA1 80%, #5ED6E8 100%);
}
body[data-theme="combined"] .fl-icon,
body[data-theme="combined"] .g-label { background: linear-gradient(135deg, #AF126B 0%, #EF007B 55%, #388DA1 100%); color: #fff; }
body[data-theme="combined"] .tag { background: linear-gradient(90deg, #AF126B 0%, #EF007B 60%, #388DA1 100%); color: #fff; }

/* ---- Architecture diagram: arrow labels and the remittance chip ---- */
/* The 80px arrow columns forced "Approved invoices" and "EFT settlement"
   to wrap into two lines, which buried the arrow beneath the label. */
.arch-grid, .arch-flow-row { grid-template-columns: 1fr 128px 1.12fr 128px 1fr; }
.arch-arrow .arrow-label {
  white-space: nowrap;
  font-size: 0.72rem;
  padding: 4px 10px;
  line-height: 1.2;
  box-shadow: 0 0 0 4px #fff;
}
.arch-return { margin-top: 20px; }
.arch-return-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 16px;
  border-radius: 999px;
  background: #fff;
  border: 1px dashed var(--gf-blue);
  color: var(--gf-blue);
  font-size: 0.74rem; font-weight: 600;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
@media (max-width: 1000px) {
  .arch-grid, .arch-flow-row { grid-template-columns: 1fr; }
  .arch-return-chip { white-space: normal; }
}

/* Four currencies now — two per row rather than a cramped single line */
.calc-currency { flex-wrap: wrap; }
.calc-currency .cur-opt { flex: 1 1 calc(50% - 3px); padding: 9px 8px; }


/* ============================================================
   DESIGN SYSTEM ALIGNMENT
   Type scale, product ramps, patterns and logo, applied over the
   token remap above. This section is the authority — anything
   earlier in the file that contradicts it is superseded.
   ============================================================ */

/* ---- Type ---- */
body { font-family: var(--font-sans); font-size: 16px; line-height: 1.55; color: var(--ink); }
h1, h2, h3, h4, h5 { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.015em; }
h1 { font-size: clamp(2.4rem, 4.4vw, 4rem);  line-height: 1.05; letter-spacing: -0.025em; }
h2 { font-size: clamp(1.8rem, 2.9vw, 2.6rem); line-height: 1.1; letter-spacing: -0.02em; }
h3 { font-size: 1.375rem; line-height: 1.3; font-family: var(--font-sans); }
h4 { font-size: 1.06rem;  line-height: 1.35; font-family: var(--font-sans); }
.lede { font-size: clamp(1.05rem, 1.3vw, 1.15rem); line-height: 1.55; color: var(--ink-2); }
.mono, .ph-tag { font-family: var(--font-mono); }
/* The old sheet used a serif italic for accents; Roboto has no serif,
   so the accent is carried by colour and weight instead. */
.accent, .lever-q, .quote-text, .quote, article blockquote, .ba-divider, .serif {
  font-family: var(--font-display);
  font-style: normal;
}
.accent { color: var(--cyan-500); font-weight: 700; }
.quote-text, .quote, article blockquote { font-weight: 400; }
.fl-icon { font-family: var(--font-sans); font-style: normal; font-weight: 700; }
.pull-quote::before { font-family: var(--font-display); font-style: normal; }

/* ---- Brand lock-up: the supplied SVG ---- */
.nav-brand img { height: 44px; }

/* ---- Product ramps, straight off the accent palettes ---- */
:root {
  --lv-method:        var(--magenta-700);   /* Flow */
  --lv-method-bright: var(--magenta-500);
  --lv-method-tint:   #FEF4F9;
  --lv-method-tint-2: var(--magenta-100);

  --lv-timing:        var(--cyan-900);      /* Pace */
  --lv-timing-bright: var(--cyan-500);
  --lv-timing-tint:   #F2FCFE;
  --lv-timing-tint-2: var(--cyan-100);

  --grad-flow:     linear-gradient(90deg,  #690037 0%, #E9007B 100%);
  --grad-pace:     linear-gradient(90deg,  #2D6870 0%, #63E7F8 100%);
  --grad-flow-135: linear-gradient(135deg, #A30056 0%, #E9007B 100%);
  --grad-pace-135: linear-gradient(135deg, #2D6870 0%, #45A2AE 100%);
}
/* Cyan is light: ink on it, per --cyan-ink */
.lever-grid .lever:nth-child(2) .lever-tag { background: var(--grad-pace); color: var(--cyan-ink); }
.persona-card[data-outcome="ebitda"] .pc-icon { background: var(--grad-pace-135); color: #fff; }
/* .fl-icon dropped from this rule 2026-09-16; .g-label keeps the Pace
   gradient, which is a guardrail label and not a numeral. */
body[data-theme="lever-timing"] .g-label,
body[data-theme="outcome-ebitda"] .g-label { background: var(--grad-pace-135); color: #fff; }
body[data-theme="lever-timing"] .tag,
body[data-theme="outcome-ebitda"] .tag { background: var(--grad-pace); color: var(--cyan-ink); }

/* ---- Themed heroes: site blue into the product accent ----
   Both heroes now open on --blue-800 and hand over to the product ramp,
   so a themed page reads as GlobalFinex first and Flow / Pace second.
   The accent still owns the right-hand side, which is where it carries
   the product identity; only the anchor and the run-up changed.

   Hero copy is left-aligned and runs out at ~56% (h1 is max-width:22ch,
   the lede 60ch), and .page-hero::after lays rgba(0,0,0,.28) over the
   left edge fading to nothing at the right.

   CONTRAST, DECLARED, measured on the wash ALONE — the ::after overlay
   only darkens, so these are the floor and the rendered figure is better:

                    was (worst under copy)   now
     Flow / WC          7.60:1               9.66:1
     Pace / EBITDA      4.80:1               ~7.2:1

   Pace is the one that mattered. Its old 4.80:1 was flagged in this very
   comment as passing with little margin and needing re-measurement on any
   change; opening on blue retires that caveat rather than re-inheriting it.

   Past ~72% both ramps fall under AA — Flow reaches 4.42:1 at the far
   edge, Pace 1.47:1 — exactly as they did before. That region is open
   space beyond the copy on all four pages. It is not a text surface and
   must not become one without re-measuring.

   Both anchors are ramp tokens. The old Pace anchor was a color-mix of
   cyan-900 with black, invented rather than picked; --blue-800 replaces
   it and is the same anchor Flow uses, which is the point. */

/* ---- Themed callouts ----
   A callout is not a hero. Its copy is CENTRED (h2 22ch, p 60ch, auto
   margins) so it sits over roughly the middle 28-72% of the wash rather
   than the safe left, and .callout carries no darkening overlay.

   2026-09-21, MEASURED RATHER THAN ASSUMED. The rule used to be "one step
   short of the hero on each ramp", applied to both. Re-measured on the
   rendered pages, that is right for cyan and wrong for magenta:

     Flow, hero ramp ending magenta-500   7.93:1 worst under copy   PASS
     Pace, hero ramp ending cyan-500      3.50:1 worst under copy   FAIL

   cyan-500 is a far lighter endpoint than magenta-500, which is the whole
   of the difference. So Flow and outcome-working-capital now take their
   hero's ramp exactly - same stops, same 105deg, same interpolation - and
   the visible mismatch goes with it: the callout used to end on a dull
   #932266 where its hero ends on #c00065.

   Pace, outcome-ebitda and combined keep the 700 endpoint. That is not an
   oversight and not an inconsistency to tidy away later - it is 3.50:1
   versus 4.5:1. Re-measure before changing it. */
body[data-theme="lever-method"] .callout,
body[data-theme="outcome-wc"]   .callout {
  background: linear-gradient(105deg,
    var(--blue-800) 0%, var(--blue-500) 34%,
    var(--magenta-700) 72%, var(--magenta-500) 100%);
  background: linear-gradient(105deg in oklab,
    var(--blue-800) 0%, var(--blue-500) 32%,
    var(--magenta-700) 70%, var(--magenta-500) 100%);
}
body[data-theme="lever-timing"]  .callout,
body[data-theme="outcome-ebitda"] .callout {
  background: linear-gradient(120deg,
    var(--blue-800) 0%, var(--blue-500) 40%, var(--cyan-700) 100%);
  background: linear-gradient(120deg in oklab,
    var(--blue-800) 0%, var(--blue-500) 38%, var(--cyan-700) 100%);
}
/* ---- Combined: site blue through Flow into Pace ----
   2026-09-16. combined.html was the one themed hero the "open on site
   blue" pass above missed. It opened on --magenta-900 with no blue in it
   at all, and it was the last hero on the site still written in raw hex
   rather than ramp tokens. Both are fixed here: three brand colours in
   one wash, primary blue -> magenta-500 -> cyan-500, tokens throughout.

   INTERPOLATED IN OKLAB, NOT sRGB. Five stops in sRGB read as bands
   rather than a fade, for two measured reasons:
     - blue-500 -> magenta-700 moves OKLab lightness only +0.041 while
       the hue swings 93 degrees. Near-flat lightness over a long run is
       what the eye reads as a plateau, and the fade appears to restart
       after it.
     - magenta-500 -> cyan-700 collapses chroma 0.245 -> 0.089, so the
       crossing greys out.
   oklab paces both smoothly. --cyan-700 is also dropped as a stop: it
   was the dull colour, and the wash now passes through that region
   instead of parking on it.

   STOP POSITIONS ARE PACED TO OKLAB LIGHTNESS, not picked by eye. The
   stops sit where equal lightness travel puts them, which is why they
   are not evenly spaced.

   CONTRAST, white on the wash, measured on the wash ALONE - .page-hero
   ::after only darkens, so the rendered figure is better than this:

     hero,    worst under copy (0-56%)   7.84:1    was 7.80:1
     callout, worst under copy (0-72%)   7.82:1    was ~6.6:1

   Hero copy is left-aligned and runs out at ~56% (h1 22ch, lede 60ch).
   Callout copy is CENTRED and carries no darkening overlay, so it sits
   over roughly 28-72% and stops one step short of the hero, ending on
   --cyan-700 rather than --cyan-500 - the same rule the Flow and Pace
   callouts above already follow.

   PAST THE COPY, BOTH RAMPS GO PALE AND DESATURATED. The oklab blend
   from magenta to cyan bottoms out at chroma 0.037 (hero, ~92%,
   #A7C0D7) and 0.029 (callout, ~92%, #83768B), and contrast falls to
   1.47:1 and 2.99:1 at the far edge. That region is open space beyond
   the copy on this page. It is not a text surface and must not become
   one without re-measuring.

   The sRGB first declaration is the fallback for Safari <16.2 and
   Chrome <111, which drop the `in oklab` line as invalid. It keeps
   --cyan-700 as a stop because without oklab pacing the jump straight
   to --cyan-500 is worse. */
body[data-theme="combined"] .callout {
  background: linear-gradient(120deg,
    var(--blue-800) 0%, var(--blue-500) 34%,
    var(--magenta-700) 72%, var(--cyan-700) 100%);
  background: linear-gradient(120deg in oklab,
    var(--blue-800) 0%, var(--blue-500) 32%,
    var(--magenta-700) 74%, var(--cyan-700) 100%);
}

/* ---- Brand patterns replace the swirl photo on every dark hero ---- */
.hero, .page-hero, .article-hero { background: linear-gradient(150deg, var(--blue-700) 0%, var(--blue-900) 100%); }
.hero::before        { background-image: url('patterns/pattern7.svg'); background-size: cover; background-position: right center; opacity: 1; }
.page-hero::before   { background-image: url('patterns/pattern1.svg'); background-size: cover; background-position: right center; opacity: 0.95; }
.article-hero::before{ background-image: url('patterns/pattern6.svg'); background-position: right center; opacity: 0.95; }
.callout { background: linear-gradient(135deg, var(--blue-600) 0%, var(--blue-900) 100%); position: relative; overflow: hidden; }
.callout::before {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background-image: url('patterns/pattern5.svg');
  background-size: cover; background-position: center right;
  opacity: 0.55; display: block;
}
.section-cool { background: var(--navy); }
.bc-image::before { display: none; }
.blog-card .bc-image, .case-card .bc-image {
  background: linear-gradient(140deg, var(--blue-500) 0%, var(--blue-900) 100%);
  position: relative;
}
.blog-card .bc-image::after, .case-card .bc-image::after {
  content: ''; position: absolute; inset: 0;
  background-image: url('patterns/pattern8.svg'); background-size: cover; background-position: center;
  opacity: 0.5;
}
.blog-card .bc-image > *, .case-card .bc-image > * { position: relative; z-index: 1; }

/* ---- OUTCOME BANNER, THE DEFAULT: built like the small hero it is ----
   2026-09-22

   This line used to read, in full:

     .outcome-highlight::before { background-image: url('patterns/pattern4
       .svg'); background-size: cover; opacity: 0.5; }

   Both banners that carry a variant - .outcome-highlight.is-flow and the
   outcome-ebitda one - were rebuilt on 2026-09-21 as small heroes: artwork
   in its own 38% right-hand column, masked off the left, copy capped at
   24ch / 62ch so it clears. alternatives.html is the only page left on the
   unthemed default, so it is the one instance that never got that pass. It
   gets it here, and the treatment lives on the default rather than behind a
   third modifier - the component should be built one way.

   THE FAULT IS THE ONE THE 45% PLACEMENT RULE ALREADY DOCUMENTS. cover is
   width-driven, so on a square or portrait asset it magnifies until the
   figure spans the panel and crops whatever height that implies. pattern4
   is 963x963, so the fan ran straight through all four lines of the lede
   with its tail clipping out of the bottom-left corner. Worst point in the
   copy band measured 6.59:1, where the magenta tail crossed the badge row.
   Not an AA failure - a legibility one, and exactly what the is-flow note
   meant by "without the caps there is no clear zone".

   ARTWORK IS pattern1, following this page's own hero the way the other two
   follow theirs (.page-hero::before is pattern1 at 0.95, thirty lines up).
   The white recolour, not the coloured original: the original is a blue fan
   with a magenta tail and reads as almost nothing against a blue-800 ->
   blue-500 ramp. Compared side by side before choosing. White is
   ground-agnostic, which is why both sibling banners use a recolour too.

   NO ::after SCRIM HERE, unlike the outcome-ebitda variant. That one needs
   one because its wash runs into --cyan-500 and falls to 4.08:1 past the
   copy. This wash ends on --blue-500 at 8.93:1, so there is nothing to
   rescue and a scrim would only mute the artwork.

   CONTRAST, measured on the rendered background at 1440 with the copy
   hidden, across the copy column:

     2%   14.15:1      50%  11.23:1   <- copy ends here, worst case
     25%  13.04:1      62%  11.11:1   <- the cap
     40%  12.11:1      98%   9.40:1   <- artwork only, no text

   Worst case under the copy is 11.23:1, against 8.93:1 flat before. The
   right-hand column is artwork, not a text surface; the white strokes
   themselves reach 1.19:1 there and no text sits on them. If the lede ever
   grows past 62ch, re-measure first.

   ---- SECOND PASS, SAME DAY: MORE COVERAGE, AND REAL FADES ----
   The 38% column read as a small object parked in the corner of a
   1184x412 panel, and it was cut square by the top and right edges of the
   card. Asked for more coverage without the artwork touching the copy.
   Three changes:

   1. 38% -> 72%, positioned `right -60px`, so the figure is now larger
      than the panel and runs out past the right edge instead of sitting
      inside it. It stops being a whole object and reads as a field.

   2. THE FADE IS ANCHORED IN PIXELS, NOT PER CENT, and this is the part
      that took two passes to get right.

      A percentage stop cannot do this job. THE COPY'S RIGHT EDGE IS AT A
      FIXED 574px FROM THE CARD'S LEFT EDGE AT EVERY WIDTH - the 62ch cap
      binds all the way down to ~720px, below which the container itself is
      narrower than the cap. So the copy's edge is a constant in px and a
      moving target in per cent: measured 48.5% of the panel at 1440,
      55.0% at 1100, 63.5% at 960, 71.4% at 860 and 80.6% at 768. A 56%
      stop clears the copy by 86px at 1440 and OVERLAPS IT BY 186px at 768.
      The first version of this pass shipped that mistake; it was caught by
      measuring four more widths rather than only the one in front of me.

      700px is 574px plus 126px of nominal clearance, and the nominal
      figure is not the one that matters: the mask axis is 100deg rather
      than 90deg, so the boundary is tilted and sits about 36px further
      LEFT at the top of the card than at its middle (tan(10deg) over a
      409px height). The artwork has to clear the copy at its worst height,
      not its average one, which is why the stop is set well past the copy
      rather than just past it. An earlier draft of this used 660px on the
      arithmetic alone and measured out at 46px of real clearance.

      MEASURED BY DIFFING, NOT BY EYE: each candidate was rendered against
      an otherwise identical banner with `::before { display: none }`, and
      the leftmost pixel that differed from that wash-only control is what
      the clearance figures record. A mask stop is not the same thing as
      where the artwork becomes visible - the artwork has to have ink there
      too - so the stop cannot be read off the CSS.

      MEASURED, copy edge -> leftmost visible artwork, card-left-relative:

        1024px   574 -> 664   +90px
        1100px   574 -> 664   +90px
        1280px   574 -> 662   +88px
        1440px   574 -> 661   +87px
        1920px   574 -> 661   +87px

      Below 1024 the artwork is a full-bleed texture and these figures do
      not apply; see the breakpoint note below.

   3. A SECOND MASK, INTERSECTED. The horizontal one keeps the copy clear;
      a `to bottom` one fades the top and bottom 14% so the fan dissolves
      into the panel instead of being sliced by the card edge. That slice
      was the worst thing about the 38% version and it is not fixable by
      size alone. `mask-composite: intersect` with the `-webkit-` prefix
      `source-in` ahead of it for Safari.

   The wash, the opacity, the caps and the contrast figures above are all
   unchanged - the copy column is still wash-only, so nothing there moved.

   THE COLLAPSE BREAKPOINT FOR THIS BANNER IS 1000px, NOT 720px, and it is
   its own media query further down rather than the shared one. With the
   fade anchored at 700px, the artwork column is whatever is left of the
   panel past that point: 484px at 1440, 344px at 1100, and 12px at 768,
   which is nothing at all. 1000px is where the column stops being worth
   drawing (panel ~944px, column ~244px). The
   two product variants keep the shared 720px breakpoint - their columns
   are 38%, not 72%, so they thin out differently. See the note on that
   block for the defect they still carry in this band. */
.outcome-highlight::before {
  background-image: url('patterns/pattern1-white.svg');
  background-size: 72% auto;
  background-position: right -60px center;
  background-repeat: no-repeat;
  opacity: 0.9;
  -webkit-mask-image:
    linear-gradient(100deg, transparent 0, transparent 700px, rgba(0,0,0,0.18) 800px, rgba(0,0,0,0.60) 940px, #000 1080px),
    linear-gradient(to bottom, transparent 0%, #000 14%, #000 86%, transparent 100%);
  mask-image:
    linear-gradient(100deg, transparent 0, transparent 700px, rgba(0,0,0,0.18) 800px, rgba(0,0,0,0.60) 940px, #000 1080px),
    linear-gradient(to bottom, transparent 0%, #000 14%, #000 86%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
/* The caps are what create the clear zone. Without them the copy runs
   full-bleed underneath the artwork, which is the state above. */
.outcome-highlight h2 { max-width: 24ch; }
.outcome-highlight p  { max-width: 62ch; }

/* ---- Buttons on the new primary ---- */
.btn-primary { background: var(--blue-500); box-shadow: 0 1px 0 rgba(255,255,255,0.10) inset, 0 6px 20px rgba(28,57,187,0.20); }
.btn-primary:hover { background: var(--blue-600); box-shadow: 0 1px 0 rgba(255,255,255,0.10) inset, 0 10px 28px rgba(28,57,187,0.30); }
.nav-cta { background: var(--blue-500); }
.nav-cta:hover { background: var(--blue-600); }
.btn-light { color: var(--blue-600); }
.btn-light:hover { color: var(--blue-700); }

/* ============================================================
   BRAND ICON SET
   The supplied icons are three-colour (blue / cyan / magenta) on
   transparent, so they need a light tile rather than the solid
   gradient chips the generic line icons used.
   ============================================================ */
.pc-icon, .tb-icon, .arch-icon { overflow: hidden; }
.pc-icon img, .tb-icon img, .arch-icon img {
  width: 100%; height: 100%; object-fit: contain; display: block;
}
.persona-card .pc-icon,
.persona-card[data-outcome="working-capital"] .pc-icon,
.persona-card[data-outcome="ebitda"] .pc-icon {
  background: #fff;
  border: 1px solid var(--blue-100);
  padding: 8px;
  width: 52px; height: 52px;
  border-radius: var(--radius);
  color: inherit;
}
.trust-strip .tb-icon {
  background: var(--blue-50);
  border: 1px solid var(--blue-100);
  padding: 9px;
  width: 46px; height: 46px;
  border-radius: var(--radius);
}
.section-cool .trust-strip .tb-icon { background: #fff; border-color: transparent; }
.arch-card .arch-icon {
  background: #fff;
  border: 1px solid var(--blue-100);
  padding: 5px;
  width: 34px; height: 34px;
  border-radius: 8px;
}
.arch-card.is-gfx .arch-icon { background: #fff; border-color: transparent; }
/* Pull-quote mark uses the brand quotes icon */
.pull-quote::before {
  content: '';
  top: -18px; left: 20px;
  width: 42px; height: 32px;
  background: url('icons/quotes.svg') no-repeat center / contain;
  opacity: 0.9;
}
.section-cool .pull-quote::before { opacity: 1; filter: brightness(1.6); }

/* The per-column icon tints from the original sheet outrank the generic
   .arch-card rule, so restate them at matching specificity. */
.arch-col-buyer .arch-card .arch-icon,
.arch-col-sup   .arch-card .arch-icon,
.arch-col-gfx   .arch-card .arch-icon,
.arch-card.is-gfx .arch-icon {
  background: #fff;
  border: 1px solid var(--blue-100);
  padding: 5px;
  width: 34px; height: 34px;
  border-radius: 8px;
}
.arch-card.is-gfx .arch-icon { border-color: transparent; }

/* Give both arrow labels room for the line and the head */
.arch-grid, .arch-flow-row { grid-template-columns: 1fr 152px 1.1fr 152px 1fr; }
.arch-arrow .arrow-label { font-size: 0.68rem; padding: 4px 8px; }
/* ...and restore the stack, because the line above just broke it again.
   The single-column reset is declared twice already (with the base grid and
   again with the arrow-label pass), but both sit EARLIER in this file than
   the widened track list above, and a media query carries no extra
   specificity — so each pass that widened the arrow columns for desktop
   silently un-stacked mobile. The first time it was caught and re-fixed;
   the second time it was not, leaving five tracks live at 390px: the arrows
   are display:none but their two 152px columns are still reserved, which
   squeezed the supplier column to 0 and pushed 140px of overflow onto the
   page. This reset must stay after the last rule that sets these tracks. */
@media (max-width: 1000px) {
  .arch-grid, .arch-flow-row { grid-template-columns: 1fr; }
  /* The remittance row is five cells, four of them spacers holding the
     desktop column positions. Stacked, they are four empty gaps. */
  .arch-flow-row > div:empty { display: none; }
}


/* ============================================================
   PAGE ADJUSTMENTS — 2026-08-26
   ============================================================ */

/* ---- Home: "Why?" upright, not italic ---- */
.accent, .hero h1 .accent, .hero-question h1 .accent { font-style: normal; }

/* ---- Lever cards: every row lines up across both columns ----
   Rows: tag / question / name / paragraph / 3 bullets / button. Subgrid
   makes each row the height of the taller card, so bullets and the
   overview buttons sit on the same line in both. ---- */
.lever-grid-sync { grid-template-rows: repeat(8, auto); }
.lever-grid-sync > .lever {
  display: grid;
  grid-row: span 8;
  grid-template-rows: subgrid;
  align-content: start;
}
.lever-grid-sync > .lever > * { min-width: 0; }
.lever-grid-sync > .lever > ul {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  margin: 18px 0 0;
}
.lever-grid-sync > .lever > ul > li { align-content: center; }
.lever-grid-sync > .lever > .btn { align-self: end; justify-self: start; margin-top: 22px; }
@supports not (grid-template-rows: subgrid) {
  .lever-grid-sync > .lever { display: block; }
  .lever-grid-sync > .lever > ul { display: block; }
}
@media (max-width: 880px) {
  .lever-grid-sync { grid-template-rows: none; }
  .lever-grid-sync > .lever { grid-row: auto; grid-template-rows: none; display: block; }
  .lever-grid-sync > .lever > ul { display: block; }
}

/* Lever 2 chip: white text, so the fade sits at the deep end of the cyan ramp */
.lever-grid .lever:nth-child(2) .lever-tag {
  background: linear-gradient(90deg, color-mix(in srgb, var(--cyan-900) 70%, #000) 0%, var(--cyan-900) 100%);
  color: #fff;
}
.lever-grid .lever:nth-child(1) .lever-tag {
  background: linear-gradient(90deg, var(--magenta-900) 0%, var(--magenta-700) 100%);
  color: #fff;
}

/* ---- Home: quote box sits on the same baseline as the button beside it ---- */
.two-col:has(.pull-quote) { align-items: end; }

/* ---- Home: white-paper cover matches the height of the copy beside it ---- */
@media (min-width: 861px) {
  .two-col:has(.wp-cover) { align-items: stretch; }
  /* the cover cell is taken out of flow so the copy column alone sets the row
     height. Scoped to whichever cell actually holds the cover: it sits left on
     white-paper.html and right on index.html. */
  .two-col > *:has(> .wp-cover) { position: relative; min-height: 320px; }
  .two-col > *:has(> .wp-cover) > .wp-cover { position: absolute; inset: 0; height: auto; width: 100%; }
  .two-col > *:has(> .wp-cover) > .wp-cover img { height: 100%; width: 100%; aspect-ratio: auto; object-fit: cover; object-position: top center; }
}
@media (max-width: 860px) {
  .wp-cover { position: static; }
  .wp-cover img { height: auto; aspect-ratio: 4 / 5; object-fit: cover; object-position: top center; }
}

/* ---- Generic row-sync for card grids (Flow core, Pace core, alternatives) ---- */
.grid-sync > .card,
.grid-sync > .card-soft,
.grid-sync > .cat-card {
  display: grid;
  grid-template-rows: subgrid;
  align-content: start;
}
.grid-sync.grid-2 { grid-template-rows: repeat(2, auto); }
.grid-sync.grid-2 > .card { grid-row: span 2; }
.grid-sync.grid-3 { grid-template-rows: repeat(3, auto); }
.grid-sync.grid-3 > .card { grid-row: span 3; }
.grid-sync.cat-grid { grid-template-rows: repeat(4, auto); }
.grid-sync.cat-grid > .cat-card { grid-row: span 4; }
.grid-sync > .card > *, .grid-sync > .cat-card > * { margin-top: 0; }
@supports not (grid-template-rows: subgrid) {
  .grid-sync > .card, .grid-sync > .cat-card { display: block; }
}
@media (max-width: 880px) {
  .grid-sync { grid-template-rows: none; }
  .grid-sync > .card, .grid-sync > .cat-card { grid-row: auto; display: block; }
}

/* ---- Pace: chips inside the core cards read white on the deep cyan ---- */
#core .grid-sync .tag {
  background: linear-gradient(90deg, color-mix(in srgb, var(--cyan-900) 70%, #000) 0%, var(--cyan-900) 100%);
  color: #fff;
}
body[data-theme="lever-method"] #core .grid-sync .tag {
  background: linear-gradient(90deg, var(--magenta-900) 0%, var(--magenta-700) 100%);
}

/* ---- Themed heroes: keep the colour wash, lay the pattern over it in white ---- */
body[data-theme="lever-method"] .page-hero::before,
body[data-theme="outcome-wc"]   .page-hero::before,
/* ---- Which artwork each themed hero uses. Nothing else. ----
   Sizing, position and opacity are set ONCE for every themed hero, in the
   artwork rule further down next to the wash block. They used to be set
   here too - cover, right center, and opacities of 0.26 / 0.28 / 0.30 -
   and were silently overridden by it. Removed rather than left to mislead
   the next reader, which is the same fault the wash consolidation fixed.

   Flow / outcome-working-capital take pattern3-white, Pace /
   outcome-ebitda take pattern4-white. Both are open and linear, so the set
   reads at one weight; which pair gets which is a preference, swapped here
   from the first assignment. What matters is that the two levers stay
   distinguishable, because combined.html depends on that to make its
   "both levers together" argument. pattern1-white, the densest of the
   five, is what made the magenta pair read heavier and is now unused.
   pattern1.svg, the coloured original, is untouched and is still the
   default artwork on all twenty plain navy .page-hero pages. */
body[data-theme="lever-method"]   .page-hero::before,
body[data-theme="outcome-wc"]     .page-hero::before { background-image: url('patterns/pattern3-white.svg'); }
body[data-theme="lever-timing"]   .page-hero::before,
body[data-theme="outcome-ebitda"] .page-hero::before { background-image: url('patterns/pattern4-white.svg'); }
body[data-theme="combined"]       .page-hero::before { background-image: url('patterns/pattern7-white.svg'); }
body[data-theme] .callout::before { background-image: url('patterns/pattern5-white.svg'); opacity: 0.22; }

/* ---- Feature lists: numbered squares in the page's own colour ---- */
.feature-list { counter-reset: fl; }
.feature-list li { counter-increment: fl; }
.fl-icon { font-size: 0; border-radius: 8px; width: 26px; height: 26px; }
.fl-icon::before {
  content: counter(fl);
  font-size: 0.8rem; font-weight: 700; font-style: normal;
  font-family: var(--font-sans); color: inherit;
}
/* REMOVED 2026-09-16: the three themed numeral gradients. All themed pages
   now take base .fl-icon — --gf-blue on #fff. .section-cool .fl-icon still
   overrides to cyan on the navy band, which is the navy exception holding. */
.feature-list.list-info .fl-icon { background: var(--blue-500); color: #fff; }

/* ---- Timeline markers: give the label room instead of letting it spill ---- */
.timeline-marker { width: 150px; }
.timeline-marker .tm-event {
  display: block;
  white-space: normal;
  overflow-wrap: anywhere;
  hyphens: auto;
  line-height: 1.3;
  max-width: 150px;
}
.timeline-marker[style*="left:0%"]   { text-align: left; }
.timeline-marker[style*="left:100%"] { text-align: right; }

/* ---- Before / after: the GlobalFinex column takes the page's own colour ---- */
/* The two rules below are a controlled vertical wash, not a diagonal one.
   A diagonal same-hue ramp over this column leaves the middle rows grey and
   muddy. The Flow rule no longer follows this — see its own note. */
.ba-col.after { background: linear-gradient(180deg, #24409E 0%, #142A6E 60%, #0B174B 100%); }
/* UPDATED 2026-09-16: Flow's column takes the themed hero's ramp exactly —
   same four stops, same 105deg, same sRGB interpolation. They render on the
   same page, so any divergence in stops or pacing shows as two different
   magentas. An earlier pass closed this on magenta-900, which darkened into
   plum where the hero brightens into pink; that is the muddiness this
   replaces.

   2026-09-21: the hero gained an oklab interpolation, so this gained one
   too. The sentence that stood here - "no oklab line here, because the
   hero has none" - was true when written and stopped being true the
   moment the hero changed. Same stops, same angle, same interpolation:
   that is the whole point of this rule, and it only holds if both move
   together.

   105deg, not the siblings' 180deg. The vertical-wash note above applies to
   a same-hue darkening ramp; this one crosses blue -> magenta, where
   magenta-700 at 72% is what keeps the middle clean. The column is also
   wider than tall (~534x440), so the diagonal runs mostly across it.

   THE HERO'S PAST-72% CAVEAT DOES NOT CARRY HERE. In the hero, magenta-500
   at the far edge is 4.42:1 and open space. Here .ba-step lays
   rgba(8,4,20,0.24) over it, worth ~2.4 stops: white holds 6.78:1 at the
   far edge, 10.61:1 at magenta-700. Measured, not assumed.

   The one .ba-note in this block — "(unchanged)" on the first step — is
   3.97:1 if it reached 100%. It sits at ~55% along the ramp, where it is
   near 6:1. Do not extend .ba-note to a full-width row without remeasuring. */
body[data-theme="lever-method"] .ba-col.after {
  background: linear-gradient(105deg,
    var(--blue-800) 0%, var(--blue-500) 34%,
    var(--magenta-700) 72%, var(--magenta-500) 100%);
  background: linear-gradient(105deg in oklab,
    var(--blue-800) 0%, var(--blue-500) 32%,
    var(--magenta-700) 70%, var(--magenta-500) 100%);
}
body[data-theme="lever-timing"] .ba-col.after { background: linear-gradient(180deg, #357983 0%, #285C64 60%, #1D454B 100%); }
.ba-col.after .ba-step {
  background: rgba(8, 4, 20, 0.24);
  border-color: rgba(255,255,255,0.22);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.07);
}
.ba-note { color: rgba(255,255,255,0.72); font-style: normal; font-size: 0.86rem; }
.ba-col.before .ba-step.friction { background: var(--orange-100); border-color: #F3C7A8; color: var(--orange-700); }

/* ---- for-AP: nil cell and a chip that stays on one line ---- */
.comp-table td.td-nil, .alt-table td.td-nil, .td-nil { text-align: center; color: var(--muted); font-size: 1.1rem; }
.tag-nowrap { white-space: nowrap; }

/* ---- Role routing grid: centre the row when it holds fewer than five ---- */
.role-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; }
.role-grid > .role-card { flex: 1 1 190px; max-width: 260px; }
@media (max-width: 600px) { .role-grid > .role-card { flex: 1 1 100%; max-width: none; } }

/* ---- Case studies: the Visy card carries the page on its own ---- */
.case-grid { grid-template-columns: repeat(2, 1fr); align-items: start; }
.case-card-feature {
  background: linear-gradient(160deg, var(--blue-50) 0%, #fff 55%);
  border-color: var(--blue-200);
  padding: 32px 30px 30px;
}
.case-card-feature .cc-tag { margin-bottom: 14px; }
.case-card-feature .cc-logo { height: auto; font-size: 2rem; margin-bottom: 2px; }
.case-card-feature .cc-sector {
  font-size: 0.86rem; color: var(--muted); margin-bottom: 16px;
}
.case-card-feature .cc-stats { grid-template-columns: repeat(3, 1fr); display: grid; gap: 16px; }
.case-card-feature .cc-cta { color: var(--gf-blue); font-weight: 600; font-size: 0.92rem; margin-top: 4px; display: inline-flex; align-items: center; gap: 6px; }
@media (max-width: 880px) { .case-grid { grid-template-columns: 1fr; } }

/* ---- Alternatives: "vs GlobalFinex" as a marked block, copy beneath ---- */
.cat-foot {
  display: flex; flex-direction: column; gap: 8px; align-items: flex-start;
}
.cat-foot-mark {
  display: inline-flex; align-items: center;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  background: var(--blue-500); color: #fff;
  font-size: 0.72rem; font-weight: 700; letter-spacing: var(--track-label); text-transform: uppercase;
}
.cat-foot-body { font-size: 0.92rem; color: var(--ink-2); line-height: 1.5; }

/* ---- Calculator: an unused lens shows a centred dash ---- */
.calc-headline .ch-cell-value.is-nil { text-align: center; color: rgba(255,255,255,0.5); }

/* Subgrid inherits the parent's 28px gap on rows as well as columns —
   keep the column gutter, drop the row gutter. */
.lever-grid-sync { column-gap: 28px; row-gap: 0; }
.lever-grid-sync > .lever { row-gap: 0; }
.lever-grid-sync > .lever > .lever-tag { justify-self: start; }
.lever-grid-sync > .lever > ul { row-gap: 0; }
/* Below 880px the grid drops to a single column, so the zeroed row-gap
   above (meant only for the subgrid's internal rows) collapses the space
   between the two stacked cards — restore it for that layout. */
@media (max-width: 880px) {
  .lever-grid-sync { row-gap: 28px; }
}
.grid-sync { row-gap: 0; column-gap: 24px; }
.grid-sync > .card, .grid-sync > .cat-card { row-gap: 0; }
/* Same collapse as .lever-grid-sync above: the zeroed row-gap exists for the
   desktop subgrid's internal rows, but below 880px the grid drops to a single
   column and it closes the space between the stacked cards instead. Restored
   at the .grid base gap, which is what the column-gap beside it already uses.
   .grid-sync.cat-grid carries its own copy of this restore further down. */
@media (max-width: 880px) {
  .grid-sync { row-gap: 24px; }
}
.grid-sync > .card > .tag { justify-self: start; }
.grid-sync.cat-grid { column-gap: 24px; }

/* The first and last timeline markers are centred on 0% and 100%, so half
   their label hangs outside the frame. Anchor the end ones to their own
   edge and give the row room for them. */
.timeline-row { padding: 0 84px; }
.timeline-marker[style*="left:0%"] {
  transform: none; align-items: flex-start; text-align: left;
}
.timeline-marker[style*="left:100%"] {
  transform: translateX(-100%); align-items: flex-end; text-align: right;
}
.timeline-marker[style*="left:0%"]::before   { margin-left: 0; }
.timeline-marker[style*="left:100%"]::before { margin-right: 0; }
@media (max-width: 720px) { .timeline-row { padding: 0 24px; } }
.timeline-marker { width: 152px; }
.tm-event { text-wrap: balance; }
.timeline-marker .tm-event { max-width: 152px; font-size: 0.76rem; }
.cat-foot-body { font-weight: 400; letter-spacing: 0; text-transform: none; }

/* ---- Events: a single featured event takes the full row ---- */
.case-grid.case-grid-single { grid-template-columns: 1fr; }

/* ---- ROUND 2026-09-16a: the single featured card stops hanging ----
   The card filled the full 1240px container while its stats row was
   capped at 640px, so at 1440px the paragraph ran to 1194px and the
   three stats plus the CTA stopped barely past halfway. The right
   third of the panel was empty, and the cap was the cause: it narrowed
   one child instead of the box around it.

   The card now centres on --container-narrow (880px) and the cap comes
   off, so the stats span the full inner width and every row inside the
   panel ends on the same right edge. 880 is the token the prose
   sections below already use, so the page reads on one narrow measure
   rather than a third width invented for this card.

   max-width: none rather than deleting the declaration, because
   .case-card-feature .cc-stats is a grid from further up this file and
   a bare removal would inherit whatever that rule later grows.

   The centred .section-head above it is deliberate and stays — this
   section is the page's one centred block, reviewed and kept. */
.case-grid.case-grid-single { max-width: var(--container-narrow); margin-inline: auto; }
.case-grid.case-grid-single .case-card-feature .cc-stats { max-width: none; }

/* ---- Event request form: even spacing, and the submit gets its own room ---- */
.contact-form { display: flex; flex-direction: column; gap: 18px; }
.contact-form > button[type="submit"] { margin-top: 14px; align-self: flex-start; }
.contact-form > .muted { margin-top: 0; }

/* ============================================================
   COOKIE CONSENT: banner, preferences modal
   ============================================================ */
.gf-cc-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 900;
  background: var(--navy, #0C1F3A); color: #fff;
  border-top: 3px solid var(--blue-500, #1C39BB);
  box-shadow: 0 -12px 40px rgba(11,23,51,0.28);
}
.gf-cc-banner-in {
  max-width: var(--container); margin: 0 auto; padding: 20px 28px;
  display: flex; align-items: center; gap: 28px; flex-wrap: wrap;
}
.gf-cc-copy { flex: 1 1 420px; font-size: 0.92rem; line-height: 1.55; color: rgba(255,255,255,0.86); }
.gf-cc-copy strong { color: #fff; }
.gf-cc-copy a { color: var(--cyan-500, #63E7F8); text-decoration: underline; text-underline-offset: 2px; }
.gf-cc-actions { display: flex; gap: 10px; flex-wrap: wrap; flex: 0 0 auto; }
.gf-cc-banner .btn-ghost {
  background: transparent; color: #fff; border: 1.5px solid rgba(255,255,255,0.4);
}
.gf-cc-banner .btn-ghost:hover { border-color: #fff; background: rgba(255,255,255,0.08); }

/* [hidden] must win: this element is fixed and full-screen, so a display
   rule that overrides it would swallow every click on the page. */
.gf-cc-modal { position: fixed; inset: 0; z-index: 950; display: none; align-items: center; justify-content: center; padding: 24px; }
.gf-cc-modal:not([hidden]) { display: flex; }
.gf-cc-banner[hidden], .gf-cc-modal[hidden] { display: none !important; }
.gf-cc-backdrop { position: absolute; inset: 0; background: rgba(11,23,51,0.62); backdrop-filter: blur(2px); }
.gf-cc-panel {
  position: relative; background: #fff; border-radius: var(--radius-lg, 18px);
  width: 100%; max-width: 640px; max-height: 86vh; overflow-y: auto;
  box-shadow: 0 30px 80px rgba(11,23,51,0.34); padding: 28px 30px 26px;
}
.gf-cc-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.gf-cc-head h2 { margin: 0; font-size: 1.4rem; }
.gf-cc-x {
  border: 0; background: transparent; font-size: 1.7rem; line-height: 1; cursor: pointer;
  color: var(--ink-3); padding: 0 4px;
}
.gf-cc-x:hover { color: var(--ink); }
.gf-cc-intro p { font-size: 0.92rem; color: var(--ink-2); margin: 12px 0 4px; }

.gf-cc-cat { border-top: 1px solid var(--line-soft); padding: 16px 0 4px; }
.gf-cc-cat-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.gf-cc-cat-name { font-weight: 700; font-size: 0.97rem; color: var(--ink); }
.gf-cc-cat-desc { font-size: 0.87rem; color: var(--ink-3); line-height: 1.5; margin: 6px 0 0; }
.gf-cc-always {
  font-size: 0.72rem; font-weight: 700; letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--blue-500, #1C39BB); background: var(--gf-indigo-soft, #EEF1FE);
  padding: 5px 12px; border-radius: var(--radius-pill, 999px); white-space: nowrap;
}

.gf-cc-switch { position: relative; display: inline-flex; align-items: center; cursor: pointer; flex: 0 0 auto; }
.gf-cc-switch .gf-cc-swtext {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.gf-cc-switch input {
  position: absolute; opacity: 0; width: 46px; height: 26px; margin: 0; cursor: pointer;
}
.gf-cc-track { pointer-events: none;
  width: 46px; height: 26px; border-radius: 999px; background: #C9CEDD;
  position: relative; transition: background 0.18s ease; display: block;
}
.gf-cc-track::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(11,23,51,0.3);
  transition: transform 0.18s ease;
}
.gf-cc-switch input:checked + .gf-cc-track { background: var(--blue-500, #1C39BB); }
.gf-cc-switch input:checked + .gf-cc-track::after { transform: translateX(20px); }
.gf-cc-switch input:focus-visible + .gf-cc-track { outline: 2px solid var(--gf-royal); outline-offset: 2px; }

.gf-cc-foot {
  display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end;
  border-top: 1px solid var(--line-soft); margin-top: 20px; padding-top: 20px;
}
.gf-cc-note { font-size: 0.8rem; color: var(--muted); margin: 14px 0 0; text-align: right; }
body.gf-cc-locked { overflow: hidden; }

@media (max-width: 720px) {
  .gf-cc-banner-in { padding: 18px 20px; gap: 16px; }
  .gf-cc-actions { width: 100%; }
  .gf-cc-actions .btn { flex: 1 1 auto; justify-content: center; }
  .gf-cc-panel { padding: 22px 20px 20px; max-height: 90vh; }
  .gf-cc-foot { justify-content: stretch; }
  .gf-cc-foot .btn { flex: 1 1 auto; justify-content: center; }
  .gf-cc-note { text-align: left; }
}

/* ---- Legal pages: readable long-form body ---- */
.legal-body h2 { font-size: 1.3rem; margin: 40px 0 12px; }
.legal-body h2:first-of-type { margin-top: 28px; }
.legal-body h3 { font-size: 1.02rem; margin: 24px 0 8px; }
.legal-body p { font-size: 0.95rem; line-height: 1.7; }
.legal-body .checklist { margin: 12px 0 0; }
.legal-body .table-wrap { overflow-x: auto; margin: 14px 0 8px; }
.legal-body .comp-table { min-width: 520px; }
.legal-body .comp-table td:first-child { font-family: var(--font-mono, monospace); font-size: 0.86rem; white-space: nowrap; }

/* ---- Product hero: lever label paired with the market name for it ----
   Both labels are plain eyebrows. See the HERO EYEBROW PAIR block near the
   end of this file for how the two are told apart without a chip. */
.eyebrow-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 4px; }
.eyebrow-row > .eyebrow { margin-bottom: 0; }

/* ---- Use Cases menu: a third column once payment types were added ---- */
.nav-dropdown.three-col { min-width: 780px; }
.nav-dropdown.three-col .cols { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 980px) {
  .nav-dropdown.three-col { min-width: 0; }
  .nav-dropdown.three-col .cols { grid-template-columns: 1fr; }
}

/* ---- Co-branded partner landing page ----
   ROUND 2026-09-24: both sides are now real marks. Visy's own logo
   (logos/visy-mark.svg — the supplied visy.svg without its "For a better
   world" line, which is near-black and vanishes on the navy hero) replaces
   the white "Visy" text chip, and GlobalFinex is the mark alone
   (logo-globalfinex-mark-white.svg), without the wordmark: the nav directly
   above already says GlobalFinex B2B. .cobrand-partner, the chip, is gone
   with it. Height stepped down 20% (46 → 37, 38 → 30 on mobile) so the pair
   introduces the headline rather than competing with it. */
.cobrand { display: flex; align-items: center; gap: 18px; margin-bottom: 22px; flex-wrap: wrap; }
.cobrand-mark { height: 37px; width: auto; display: block; }
.cobrand-x { color: rgba(255,255,255,0.5); font-size: 1.4rem; line-height: 1; }
@media (max-width: 560px) { .cobrand { gap: 12px; } .cobrand-mark { height: 30px; } }

/* ---- ROUND 2026-10-01: the Visy co-brand is the text chip ----
   Supersedes the 24 Sep logo pair above for the Visy page. JP's version of
   the page, signed off by Visy on 1 Oct, keeps the white "Visy" text chip
   and the full GlobalFinex logo, so these rules are the design now, not a
   compatibility shim (they were one from 29 Sep). Don't delete them.

   Sizes are as signed off: the chip at the 37px cobrand height (30px on
   mobile), the full logo at 46px (38px). The 24 Sep marks,
   logos/visy-mark.svg and logo-globalfinex-mark-white.svg, are unused and
   kept in case the logo pair comes back. */
.cobrand .cobrand-partner {
  display: inline-flex; align-items: center; height: 37px; padding: 0 16px;
  background: var(--white); color: var(--navy); border-radius: 8px;
  font-family: var(--font-display); font-weight: 700; font-size: 1.3rem; letter-spacing: -0.02em;
}
.cobrand-mark[src$="logo-globalfinex-white.svg"] { height: 46px; }
@media (max-width: 560px) {
  .cobrand .cobrand-partner { height: 30px; font-size: 1.1rem; padding: 0 12px; }
  .cobrand-mark[src$="logo-globalfinex-white.svg"] { height: 38px; }
}

/* ---- ROUND 2026-09-24: FAQ accordion ----
   Questions only, all closed. The Visy page is reached from an invoice
   link by someone with one question in mind, so the list is for scanning
   and the answer is one click away. Native <details>/<summary>: no script,
   keyboard and screen-reader support built in.

   The look is the calculator's maths accordion (.calc-maths) — bordered
   row, +/- in a soft circle — so the site has one accordion, not two.
   Stacked rows 8px apart; 16/24px padding and a 16px question-to-answer
   step, all on the 8pt grid. Answers keep a 70ch measure inside the full
   container row.

   Supersedes the provisional .faq-list <dl> rules in app.css. */
.faq-list { display: flex; flex-direction: column; gap: 8px; }
.faq-item { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.faq-item > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 16px 24px; font-weight: 600; color: var(--ink);
}
.faq-item > summary::-webkit-details-marker { display: none; }
.faq-item > summary::after {
  content: '+'; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--gf-indigo-soft); color: var(--gf-blue); font-weight: 700;
}
.faq-item[open] > summary::after { content: '\2212'; }
.faq-item > summary:hover { background: var(--bg-soft); }
.faq-item > summary:focus-visible { outline: 2px solid var(--gf-royal); outline-offset: -2px; }
.faq-answer { padding: 16px 24px 24px; }
.faq-answer p { margin: 0; max-width: 70ch; color: var(--ink-2); }

/* ---- ROUND 2026-09-24: Visy registration form, centred ----
   Same treatment as the roundtable's #request: the head centres, the form
   centres as a block at its 824px measure, and nothing inside it does. */
.sn-page #register .contact-form { max-width: calc(var(--container-narrow) - 56px); margin-inline: auto; margin-top: 32px; }

/* ---- ROUND 2026-09-28: web portal screenshots, one per row ----
   The mobile app is not launched, so "What you will see" shows three web
   portal screens instead of the phone previews. They are landscape desktop
   captures: in a three-up grid their text was unreadable, so each takes a
   row, screen left and caption right, and the caption drops under the
   screen below 860px.

   No card around the screen. The .app-frame card's rounded border and
   overflow:hidden clipped the screenshot's own corners and edges; the screen
   now sits on the section background with its own border and shadow.

   Own classes, so nothing here depends on the provisional .app-gallery /
   .app-frame rules in app.css. Those stay, unused, for when the app ships. */
.portal-gallery { display: grid; gap: 40px; }
.portal-shot {
  display: grid; grid-template-columns: 2.2fr 1fr; gap: 32px; align-items: center;
  margin: 0;
}
.portal-shot-body h4 { margin: 0 0 8px; }
.portal-shot-body p { margin: 0; color: var(--ink-2); font-size: 0.95rem; }
@media (max-width: 860px) { .portal-shot { grid-template-columns: 1fr; gap: 16px; } }

/* ---- ROUND 2026-09-28: tap to enlarge ----
   Each screen is a link to its own image, so it opens full size with no
   script; script.js turns it into the #shot-viewer <dialog>. The Enlarge
   label is always shown, not on hover, because touch screens have no hover. */
.shot-zoom { display: block; position: relative; cursor: zoom-in; border-radius: var(--radius-sm); }
.shot-zoom img {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); transition: box-shadow .2s ease;
}
.shot-zoom:hover img { box-shadow: var(--shadow-md); }
.shot-zoom:focus-visible { outline-offset: 4px; }
.shot-zoom-badge {
  position: absolute; right: 12px; bottom: 12px;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: var(--radius-pill);
  background: rgba(11, 23, 75, .82);   /* --blue-900 at 82% */
  color: #fff; font-size: .8rem; font-weight: 600; line-height: 1;
}
.shot-zoom-badge svg { width: 14px; height: 14px; }

/* The enlarged view: a full-screen <dialog>, the image fitted to the window.
   Below 860px a fitted landscape screen is barely larger than the thumbnail,
   so it shows at 1100px and the pane scrolls sideways, with a hint. */
.shot-viewer {
  position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none;
  margin: 0; padding: 0; border: 0; background: transparent; color: #fff;
}
.shot-viewer::backdrop { background: rgba(11, 23, 75, .9); }
.shot-viewer-pane { position: absolute; inset: 64px 24px 72px; overflow: auto; display: grid; place-items: center; }
.shot-viewer-pane img {
  max-width: 100%; max-height: 100%; width: auto; height: auto;
  border-radius: var(--radius-sm); background: #fff;
}
.shot-viewer-close {
  position: absolute; top: 12px; right: 12px; width: 44px; height: 44px;
  border: 0; border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, .14); color: #fff;
  font-size: 26px; line-height: 1; cursor: pointer;
}
.shot-viewer-close:hover { background: rgba(255, 255, 255, .26); }
.shot-viewer-caption { position: absolute; left: 24px; right: 24px; bottom: 24px; margin: 0; text-align: center; font-weight: 600; }
.shot-viewer-hint { display: none; }
@media (max-width: 860px) {
  .shot-viewer-pane { inset: 64px 0 88px; place-items: start; }
  .shot-viewer-pane img { width: 1100px; max-width: none; max-height: none; border-radius: 0; }
  .shot-viewer-hint { display: block; margin-top: 4px; font-size: .85rem; font-weight: 400; opacity: .8; }
}

/* ---- ROUND 2026-10-01: JP's Visy page, signed off by the client ----
   Moved here from the page's own <style> block, unchanged except that
   every selector is scoped to .sn-page: combined.html also has a #why
   section. The 28 Sep .portal-gallery rows above are unused while this
   holds; they stay for now. */

/* Money-flow diagram: the return arrow, Visy back to GlobalFinex B2B */
.sn-page .arch-return-span { grid-column: 3 / 6; position: relative; display: flex; justify-content: center; align-items: center; min-height: 34px; }
.sn-page .arch-return-span::before {
  content: ''; position: absolute; top: 50%; left: 25%; right: 25%; height: 2px;
  background: var(--gf-blue);
}
.sn-page .arch-return-span::after {
  content: ''; position: absolute; top: calc(50% - 6px); left: calc(25% - 6px);
  width: 0; height: 0; border-top: 6px solid transparent; border-bottom: 6px solid transparent; border-right: 9px solid var(--gf-blue);
}
.sn-page .arch-return-span .arch-return-chip { position: relative; z-index: 1; background: var(--white); }
@media (max-width: 1000px) {
  .sn-page .arch-return-span { grid-column: 1; }
  .sn-page .arch-return-span::before, .sn-page .arch-return-span::after { display: none; }
}
/* A tighter frame; every column the same height, its two cards splitting it equally */
.sn-page #why .arch-diagram { padding: 20px; }
.sn-page #why .arch-col { padding: 10px 10px 12px; display: grid; grid-template-rows: auto 1fr 1fr; }
.sn-page #why .arch-col .arch-card { align-items: center; }

/* Portal screens: one screen, a tab list beside it at the screen's height.
   The active tab shows its description; the others show a +. script.js
   swaps the screen and handles the arrow keys. */
.shot-tabs { display: grid; grid-template-columns: 2.2fr 1fr; gap: 24px; align-items: stretch; }
.shot-tabs-screen .shot-zoom img { margin: 0; }
.shot-tabs-list { display: flex; flex-direction: column; gap: 10px; min-height: 0; }
.shot-tab {
  flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; justify-content: center;
  text-align: left; font: inherit; cursor: pointer;
  padding: 12px 24px; background: var(--white); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius);
  transition: background .15s;
}
.shot-tab:hover { background: var(--bg-soft); }
.shot-tab:focus-visible { outline: 2px solid var(--gf-royal); outline-offset: -2px; }
.shot-tab-name { display: flex; align-items: center; justify-content: space-between; gap: 16px; font-weight: 600; }
.shot-tab-name::after {
  content: '+'; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--gf-indigo-soft); color: var(--gf-blue); font-weight: 700;
}
.shot-tab.is-active .shot-tab-name::after { content: none; }
.shot-tab-desc { display: none; margin-top: 4px; font-size: 0.88rem; color: var(--ink-2); line-height: 1.4; }
.shot-tab.is-active .shot-tab-desc { display: block; }
@media (max-width: 860px) {
  .shot-tabs { grid-template-columns: 1fr; gap: 16px; }
  .shot-tab { flex: none; }
}

/* "What it costs": the copy spread to the height of the card beside it */
.sn-page #cost .card-feature { display: flex; flex-direction: column; }
.sn-page #cost .card-feature > .eyebrow { flex: none; }
.sn-page #cost .card-feature > p { flex: 1 1 auto; display: flex; align-items: center; margin: 0; padding: 8px 0; }
.sn-page #cost .card-feature > h3 { margin-bottom: 4px; }

/* FAQ answers run the width of the box (overrides the 70ch measure above) */
.sn-page .faq-answer p { max-width: none; }

/* Row-sync for cards carrying four rows (tag, title, body, list). The default
   grid-2 sync assumes two, which wrapped rows 3 and 4 back over rows 1 and 2. */
.grid-sync.sync-4 { grid-template-rows: repeat(4, auto); }
.grid-sync.sync-4 > .card,
.grid-sync.sync-4 > .card-soft { grid-row: span 4; }
@media (max-width: 880px) { .grid-sync.sync-4 > .card { grid-row: auto; } }

/* The 38px indent aligns a card title with the text beside a feature-list icon.
   When the card also carries an intro paragraph the indent breaks the left
   edge instead, so drop it for those cards. */
.card-feature:has(.feature-list):has(> p) > h3 { padding-left: 0; }

/* ---- Use-case and partner heroes: brand navy, varied by pattern ----
   The lever colours belong to the product pages. A use case that happens to
   run on one lever is not the product, so it takes the house treatment and is
   distinguished by which pattern washes the hero. */
.hero-pattern-2 .page-hero::before,
.hero-pattern-2 .article-hero::before { background-image: url('patterns/pattern2.svg'); }
.hero-pattern-3 .page-hero::before,
.hero-pattern-3 .article-hero::before { background-image: url('patterns/pattern3.svg'); }
.hero-pattern-4 .page-hero::before,
.hero-pattern-4 .article-hero::before { background-image: url('patterns/pattern4.svg'); }
.hero-pattern-5 .page-hero::before,
.hero-pattern-5 .article-hero::before { background-image: url('patterns/pattern5.svg'); }
.hero-pattern-6 .page-hero::before,
.hero-pattern-6 .article-hero::before { background-image: url('patterns/pattern6.svg'); }
.hero-pattern-7 .page-hero::before,
.hero-pattern-7 .article-hero::before { background-image: url('patterns/pattern7.svg'); }
.hero-pattern-8 .page-hero::before,
.hero-pattern-8 .article-hero::before { background-image: url('patterns/pattern8.svg'); }

/* ---- Placement: the same 45% footprint the themed heroes use ----
   The lines above choose the artwork. This one places it, matching the rule
   beside the themed wash block that Flow, Pace, EBITDA and working-capital
   already run on — `background-size: 45% auto`, flush right, no-repeat.

   Why. `cover` is width-driven in a landscape frame: it scales every artwork
   up until it spans the full hero width, then crops whatever height that
   implies. For a portrait or square file that means a hard magnification and
   a hard crop, so the figure is squeezed rather than placed, and it bleeds
   across the copy column instead of sitting beside it. Sizing to 45% of the
   hero gives each drawing its own footprint on the right and lets the
   composition survive. Same reasoning already recorded against the themed
   heroes; these are the pages that never got it.

   All four By Payment heroes are listed, which is a consistency decision
   rather than four identical faults. pattern3, 4 and 5 were being squeezed
   as described above. pattern2 was NOT: at 971x514 it is the only landscape
   asset in the set, so `cover` already sized it sanely and Accounts Payable
   looked correct on its own. It is placed here anyway so the four use-case
   heroes read as one treatment rather than three-plus-one. Asked for on
   21 September 2026 after seeing the set side by side.

   no-repeat is required: below 100% the pattern would otherwise tile. */
.hero-pattern-2 .page-hero::before,
.hero-pattern-3 .page-hero::before,
.hero-pattern-4 .page-hero::before,
.hero-pattern-5 .page-hero::before,
.hero-pattern-6 .page-hero::before,
.article-hero::before {
  background-size: 45% auto;
  background-repeat: no-repeat;
}
/* ROUND 2026-09-24: pattern6 (the Visy page) joins the list above — it was
   the one page-hero pattern never placed, so `cover` spread it behind the
   copy. It also sits 8% in from the right edge rather than flush, moved
   in at design review on 24 September 2026. */
.hero-pattern-6 .page-hero::before { background-position: right 8% center; }

/* ---- HERO EYEBROW PAIR: two labels, no chip ----
   Every hero eyebrow on the site is now plain text. The chip that used to sit
   here is gone: it was carried by 9 of 32 heroes (the five body[data-theme]
   product and outcome pages, and the four use-case pages with a paired label)
   and read as a different component from the other 23.

   What the chip was doing, and how it is done now: a paired hero carries the
   lever name beside the market name for it — "Lever 2 · Timing" next to
   "Dynamic Discounting" — and the two have to read as two labels, not as one
   run-on string. The pill separated them by drawing a box around each. Plain
   text separates them with a rule and a weight of colour instead:

     .eyebrow      the standard hero cyan, exactly as on every other hero
     .eyebrow-alt  white, one step brighter, preceded by a hairline divider

   The divider is a pseudo-element rather than a border so it does not inherit
   the label's own box, and it is sized in em so it tracks the label if the
   eyebrow scale ever moves. A single-label hero is unaffected — it has no
   .eyebrow-alt and no divider, and is now identical to how-it-works.

   The pair above still describes an UNTHEMED hero. On a themed one the first
   label is now white too — see the per-surface dark inks near the top of this
   file — so both labels landed on the same colour and the pair read as one
   run-on string separated by a hairline, which is the thing this component
   exists to prevent. The step is restored below, and it had to be restored
   downward: white is the ceiling on that wash, so the only second step
   available is under it, not over it.

   That inverts which label leads. It used to be the market name — alt, one
   step brighter than the cyan lever name beside it. It is now the lever name,
   at full white, with the market name a step under it. Deliberate, and the
   only option that keeps both labels legible on the wash; if the market name
   should lead again, the fix is to step the FIRST label down rather than to
   push alt past white, which it cannot go. */
.page-hero .eyebrow-row > .eyebrow-alt {
  position: relative;
  color: #fff;
  margin-left: 12px;
}
/* Themed hero: one step under the white first label. 0.72 is the step that
   reads as a second label rather than as a faded one — 1.82:1 against the
   label beside it, and still 7.65:1 on the Flow wash and 7.56:1 on Pace's,
   well clear of the 4.5:1 an eyebrow needs. 0.80 is too close to read as a
   step at all (1.51:1); 0.62 stops looking like a label and starts looking
   like muted body text. Scoped to body[data-theme] so an unthemed paired
   hero, whose first label is still cyan, keeps the original two steps. */
body[data-theme] .page-hero .eyebrow-row > .eyebrow-alt {
  color: rgba(255,255,255,0.72);
}
.page-hero .eyebrow-row > .eyebrow-alt::before {
  content: "";
  position: absolute;
  left: -12px;
  top: 50%;
  transform: translateY(-50%);
  height: 0.85em;
  border-left: 1px solid rgba(255,255,255,0.35);
}

/* ============================================================
   HERO ARTWORK: keep the pattern beside the copy, not under it
   The patterns were running full-bleed behind the headline and lede, which
   is what made the text hard to read. Mask each pattern layer so it fades in
   only past the text column, and deepen the scrim over the copy itself.
   ============================================================ */
.hero::before,
.page-hero::before,
.article-hero::before,
body[data-theme] .page-hero::before,
body[data-theme] .page-hero::after {
  -webkit-mask-image: linear-gradient(100deg, rgba(0,0,0,0.26) 0%, rgba(0,0,0,0.30) 36%, rgba(0,0,0,0.60) 58%, #000 80%);
  mask-image: linear-gradient(100deg, rgba(0,0,0,0.26) 0%, rgba(0,0,0,0.30) 36%, rgba(0,0,0,0.60) 58%, #000 80%);
}

.hero::after {
  background: linear-gradient(95deg,
    rgba(15,30,80,0.60) 0%,
    rgba(15,30,80,0.26) 48%,
    rgba(15,30,80,0.05) 74%,
    rgba(15,30,80,0) 100%);
}
.page-hero::after {
  background: linear-gradient(92deg,
    rgba(15,30,80,0.72) 0%,
    rgba(15,30,80,0.34) 46%,
    rgba(15,30,80,0.07) 72%,
    rgba(15,30,80,0) 100%);
}

/* ---- ROUND 2026-09-22: .article-hero joins the page-hero treatment ----
   This block used to argue the opposite, and the argument has expired.
   It read: "NO DIRECTIONAL MASK HERE, deliberately. The mask above is cut
   for a left copy column; .article-hero puts its copy in .container-narrow
   (880px, CENTRED), so the text spans roughly 15% to 85% of the frame and
   a horizontal fade buys nothing." That was true of the centred hero. It
   stopped being true the moment the articles moved onto .container, where
   the copy is a left column exactly like .hero and .page-hero.

   So the two workarounds that stood in for a mask both go. The blanket
   opacity: 0.40 was holding the artwork down everywhere because it could
   not be held down only over the copy; the 180deg ::after was scrimming
   the whole frame for the same reason. With the directional mask added
   above, the pattern fades in past the text on its own and runs at full
   strength on the right, and the scrim can be the 92deg one .page-hero
   already uses — heaviest over the copy, clear by the right edge.

   Placement comes from the 45% rule further up, which the articles now
   join. That rule's own note explains why: cover is width-driven, so on a
   portrait or square asset it magnifies and crops until the figure bleeds
   across the copy instead of sitting beside it. pattern6 is 900x942 and
   was doing exactly that — a mid-slice of the artwork ending in a hard
   vertical cut, with the right third of the hero left empty.

   Artwork is chosen by the body class now, the same hero-pattern-N system
   the use-case pages use. Both articles carry hero-pattern-3, matching
   Accounts Receivable. Asked for on 22 September 2026 after comparing the
   two heroes side by side.

   Contrast, measured on the rendered background with the copy hidden, at
   the brightest point behind the copy column: white headline 14.58:1 on
   the blog post and 14.50:1 on the case study; the .meta row at 0.72 white
   7.27:1 and 7.23:1. The figures this block used to record for the
   unmasked version were 1.74:1 and 1.48:1. */
.article-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(92deg,
    rgba(15,30,80,0.72) 0%,
    rgba(15,30,80,0.34) 46%,
    rgba(15,30,80,0.07) 72%,
    rgba(15,30,80,0) 100%);
}
/* The ::after is generated after .container, so at equal z-index it would
   paint over the copy. 1 -> 2, which is what .hero and .page-hero use. */
.article-hero > .container { position: relative; z-index: 2; }

/* SUPERSEDED. That comment described the 2026-09-14 generation, where the
   themed ::after really did paint a circles/squares texture. The 2026-09-15
   block at ~3392 replaced that texture with a plain darkening scrim, and
   nobody revisited the mask — so the scrim has been masked down to 0.26 of
   itself exactly where the copy sits, which is backwards for a scrim. */
body[data-theme] .page-hero::after { background-color: transparent; }

/* ---- Themed heroes: hold the artwork clear of the copy column ----
   The shared mask above never falls below 0.26, so the pattern is always at
   least a quarter present over the headline. On the navy heroes that is
   invisible: the artwork is brand-coloured on deep navy. On the four themed
   washes it is WHITE artwork on bright magenta and cyan, and at 0.26 rising
   to 0.57 by the end of the lede it reads as arcs drawn through the text.
   Measured at 1440: the copy column ends at ~800px, 55.5% of the frame.

   So these four get their own mask that is genuinely transparent across the
   copy and ramps only past it. flow, pace and outcome-working-capital are
   the ones this fixes; combined already cleared the copy on its own, and its
   pattern7-white band sits past 68% so the new ramp does not move it.

   And the scrim comes out of the mask entirely — see above. It is a 95deg
   gradient already shaped for the copy column, 0.28 at the left edge, and
   masking it was cancelling the one layer meant to protect the text. */
body[data-theme] .page-hero::before {
  -webkit-mask-image: linear-gradient(100deg, transparent 0%, transparent 50%, rgba(0,0,0,0.10) 60%, rgba(0,0,0,0.42) 70%, rgba(0,0,0,0.78) 80%, #000 92%);
  mask-image: linear-gradient(100deg, transparent 0%, transparent 50%, rgba(0,0,0,0.10) 60%, rgba(0,0,0,0.42) 70%, rgba(0,0,0,0.78) 80%, #000 92%);
}
body[data-theme] .page-hero::after {
  -webkit-mask-image: none;
  mask-image: none;
}

/* ---- Pace and EBITDA: place the artwork instead of cropping it ----
   background-position was doing NOTHING on these heroes. pattern3-white is
   742x884, portrait; `cover` in a landscape frame scales it to exactly the
   hero's width, so there is no horizontal slack for a position to act on and
   `right center` rendered identically to `left center`. Sizing by height
   instead gives the artwork its own footprint on the right.

   140% of the hero's height, so the figure is cropped top and bottom rather
   than squeezed, and the visible arc lands beside the copy. Opacity goes
   0.26 -> 1: the mask above holds fully transparent across the first 50% of
   the frame, so none of that strength reaches the text. The copy column ends
   at ~55%, where the mask is ~0.04. Contrast under the copy is unchanged.

   The wash gains an oklab interpolation with the sRGB declaration kept first
   as the fallback for Safari <16.2 and Chrome <111, which drop `in oklab` as
   invalid. Same treatment combined.html already uses. In sRGB the blue-to-
   cyan handoff dips through a grey middle; oklab holds chroma across it.

   Flow and outcome-working-capital keep the magenta ramp in sRGB and are
   untouched here. Bringing them to oklab is the obvious follow-up. */
/* ============================================================
   THEMED HERO WASHES - the single declaration of each
   ============================================================
   CONSOLIDATED. Each of these was declared three or four times, in four
   generations laid on top of each other, with the winner decided by line
   number: a --theme-accent version at ~2221, raw hex at ~3634/3639/3548,
   ramp tokens at ~3794/3801, then the oklab pair. Nobody could read the
   resolved state off the sheet, which is how the ::after scrim comment
   went stale for a year and how background-position sat dead on two
   heroes without anyone noticing. Seven blocks deleted; these three are
   now the only place a themed hero background is set.

   Every one of those blocks also carried `border-top: 4px solid ...`, and
   every one was already overridden by `body[data-theme] .page-hero
   { border-top: 0 }` at the end of the sheet - the 2026-09-16 round that
   removed the accent stripe site-wide. With the declarations gone that
   override has nothing left to override, so it goes too. Base .page-hero
   sets no border-top, so no stripe can come back.

   The sRGB declaration in each pair is the fallback for Safari <16.2 and
   Chrome <111, which drop `in oklab` as invalid. Keep it first.

   IF YOU CHANGE A WASH, CHANGE IT HERE. Do not add another block below. */
body[data-theme="lever-timing"]   .page-hero,
body[data-theme="outcome-ebitda"] .page-hero {
  background: linear-gradient(105deg,
    var(--blue-800) 0%, var(--blue-500) 34%, var(--cyan-700) 72%, var(--cyan-500) 100%);
  background: linear-gradient(105deg in oklab,
    var(--blue-800) 0%, var(--blue-500) 32%, var(--cyan-700) 70%, var(--cyan-500) 100%);
}

body[data-theme="combined"] .page-hero {
  background: linear-gradient(105deg,
    var(--blue-800)     0%, var(--blue-500)    28%,
    var(--magenta-700) 54%, var(--magenta-500) 72%,
    var(--cyan-700)    90%, var(--cyan-500)   100%);
  background: linear-gradient(105deg in oklab,
    var(--blue-800)     0%, var(--blue-500)    26%,
    var(--magenta-700) 58%, var(--magenta-500) 76%,
    var(--cyan-500)   100%);
}
/* ---- Every themed hero places its artwork the same way ----
   SIZED BY WIDTH, not height. The three patterns have very different
   aspect ratios - pattern1-white 1.22, pattern3-white 0.84, pattern7-white
   0.65 - so one `auto <height>%` gives three different footprints: at
   auto 140% Flow lands 939px wide, Pace 646px, Combined 501px. Width
   sizing gives all five the same 45% of the frame, 648px at 1440, which is
   what Pace was tuned to. It is also height-independent, so the footprint
   does not drift when a longer headline makes one hero taller.

   Opacity 1 on all of them. The mask above is fully transparent across the
   first 50% of the frame and ~0.04 where the copy column ends at ~55%, so
   none of this reaches the text on any of the five. The <=900px branch
   below drops it to 0.20 and sits later in the sheet, so it still wins on
   mobile - keep it below this rule.

   This replaces the per-theme sizing and the 0.26/0.28/0.30 opacities set
   in the block at ~4190. Those declarations are now dead weight and should
   be pruned when the themed-wash layering is consolidated. */
body[data-theme] .page-hero::before {
  background-size: 45% auto;
  background-position: right center;
  background-repeat: no-repeat;
  opacity: 1;
}

/* ---- combined.html is the one exception to the rule above ----
   Its ribbon sits inboard rather than flush to the right edge: 80% instead
   of 100%, which on a 1440 frame moves it ~119px left and leaves air on
   both sides. Asked for on 21 September 2026 after seeing the alternatives
   on the page.

   THIS IS A DELIBERATE EXCEPTION, not a stray override. The other four
   heroes run their artwork flush right and should stay that way; if a
   fifth page ever wants this, make it the rule rather than adding a second
   exception here.

   Nothing else changes. Width stays 45% so the ribbon is the same size as
   every other hero's artwork, and the mask above is still fully
   transparent across the first 50% of the frame - the soft cut on the
   ribbon's left edge is that mask, and it is why moving inboard costs
   nothing in contrast. */
body[data-theme="combined"] .page-hero::before {
  background-position: 80% center;
}

/* Flow and outcome-working-capital join Pace and EBITDA on oklab. In sRGB
   the blue-to-magenta handoff greys out through the middle the same way
   blue-to-cyan does. combined.html already interpolates in oklab at ~3874,
   so after this all five themed washes do. */
body[data-theme="lever-method"] .page-hero,
body[data-theme="outcome-wc"]   .page-hero {
  background: linear-gradient(105deg,
    var(--blue-800) 0%, var(--blue-500) 34%, var(--magenta-700) 72%, var(--magenta-500) 100%);
  background: linear-gradient(105deg in oklab,
    var(--blue-800) 0%, var(--blue-500) 32%, var(--magenta-700) 70%, var(--magenta-500) 100%);
}
/* opacity:1 is desktop only in effect. The <=900px branch immediately below
   sets body[data-theme] .page-hero::before to 0.20 at equal specificity and
   sits LATER in the sheet, so it wins on mobile with nothing restated here.
   Keep that branch below this block. */

/* Single column below this width, so the copy sits over the artwork wherever
   it is. Drop the mask and let opacity do the work instead. */
@media (max-width: 900px) {
  .hero::before,
  .page-hero::before,
  body[data-theme] .page-hero::before,
  body[data-theme] .page-hero::after {
    -webkit-mask-image: none; mask-image: none;
  }
  .hero::before, .page-hero::before { opacity: 0.42; }
  body[data-theme] .page-hero::before { opacity: 0.20; }
  .hero::after {
    background: linear-gradient(180deg, rgba(15,30,80,0.72) 0%, rgba(15,30,80,0.55) 100%);
  }
  .page-hero::after {
    background: linear-gradient(180deg, rgba(15,30,80,0.78) 0%, rgba(15,30,80,0.6) 100%);
  }
  .article-hero::before { opacity: 0.32; }
  .article-hero::after {
    background: linear-gradient(180deg, rgba(15,30,80,0.78) 0%, rgba(15,30,80,0.6) 100%);
  }
}



/* ---- Cookie policy: categories collapse, as on the B2BE page ---- */
.cookie-cats { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; margin: 18px 0 8px; }
.cookie-cat + .cookie-cat { border-top: 1px solid var(--line-soft); }
.cookie-cat > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 16px 20px; background: #fff;
  font-weight: 700; font-size: 1rem; color: var(--ink);
  transition: background 0.15s ease;
}
.cookie-cat > summary::-webkit-details-marker { display: none; }
.cookie-cat > summary:hover { background: var(--soft); }
.cookie-cat > summary:focus-visible { outline: 2px solid var(--gf-royal); outline-offset: -2px; }
.cookie-cat[open] > summary { background: var(--soft); border-bottom: 1px solid var(--line-soft); }
.cc-chev { width: 14px; height: 14px; flex: 0 0 auto; color: var(--ink-3); transition: transform 0.18s ease; }
.cookie-cat[open] .cc-chev { transform: rotate(180deg); }
.cookie-cat-body { padding: 18px 20px 20px; background: #fff; }
.cookie-cat-body > p { margin: 0 0 12px; font-size: 0.92rem; color: var(--ink-2); }
.cookie-cat-body .table-wrap { margin: 0; }
.legal-body .cookie-cat-body .comp-table { border: 1px solid var(--line-soft); }
@media (max-width: 600px) {
  .cookie-cat > summary { padding: 14px 16px; font-size: 0.95rem; }
  .cookie-cat-body { padding: 14px 16px 16px; }
}

/* ============================================================
   ROUND 2026-09-10 — alignment, link and typography corrections
   ============================================================ */

/* 1. Sub-nav anchors span the container, so the first sits under the logo
   and the last under the Contact us button rather than floating inboard. */
/* The original rule set `padding: 12px 0`, which cancelled the container's
   own 28px and pushed the strip 28px wider than the header on each side. */
.subnav .links { gap: 0; padding-left: 28px; padding-right: 28px; }
.subnav a { padding-left: 10px; padding-right: 10px; }
/* The end links sit flush against the container edges; `space-between` puts
   them there, and zeroing the outer padding takes the label itself all the
   way out. The text-align that used to sit here is gone: the anchors are
   shrink-to-fit now, so there was no slack left for it to act on. */
.subnav a:first-child { padding-left: 0; }
.subnav a:last-child  { padding-right: 0; }
@media (max-width: 720px) {
  /* Packed left and scrolling, the end links take a wider inset from the
     container edge — but only on their outer side. Padding them on both
     sides put 24px beside the first and last labels against 20px everywhere
     else, which is the same unevenness in miniature. */
  .subnav a:first-child { padding-left: 14px; }
  .subnav a:last-child  { padding-right: 14px; }
}

/* 2. Inline links inside body copy read as links. Buttons, cards, nav,
   footer and anything already carrying its own treatment are excluded. */
.section p > a:not(.btn),
.section li > a:not(.btn),
.section dd > a:not(.btn),
.legal-body a:not(.btn),
.callout-soft a:not(.btn),
.lede > a:not(.btn),
.fs-disclaimer a,
.contact-form a {
  color: var(--gf-blue);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.section p > a:not(.btn):hover,
.section li > a:not(.btn):hover,
.legal-body a:not(.btn):hover,
.callout-soft a:not(.btn):hover { color: var(--gf-blue-deep); text-decoration-thickness: 2px; }
/* REMOVED 2026-09-16: a link on a themed page is primary blue like every
   other link. Links on the navy band keep --gf-cyan via .section-cool, and
   links on the hero / callout washes keep #fff via the rule below. */
.callout p > a:not(.btn), .page-hero p > a:not(.btn), .hero p > a:not(.btn) {
  color: #fff; text-decoration: underline; text-underline-offset: 3px;
}

/* 8. Heroes vary with their copy, but a floor stops the short ones
   reading as stunted next to the rest. */
.page-hero { min-height: 520px; display: flex; align-items: center; }
.page-hero > .container { width: 100%; }
@media (max-width: 720px) { .page-hero { min-height: 0; display: block; } }

/* 9. Eyebrow colour lives in one block near the top of this file. */

/* 10. Section heads and their intro copy, one treatment everywhere.
   Previously these carried inline max-widths from 60ch to 66ch, margins
   from 24px to 48px, and a mix of .lede, .muted and plain paragraph
   colour, so the same element read differently from page to page. */
.section-head { max-width: 64ch; margin: 0 auto 36px; text-align: center; }
.section-head > .eyebrow { display: block; margin-bottom: 10px; }
.section-head > h2 { margin: 0 0 14px; }
.section-head > p { margin: 0; }
.section-head > p + p { margin-top: 14px; }

.section-head > p,
.section-lede {
  font-size: 1.02rem;
  line-height: 1.65;
  color: var(--ink-2);
  max-width: 64ch;
  margin: 0 auto 36px;
  text-align: center;
}
.section-head > p { margin-bottom: 0; }

/* A trailing note under a grid is a different role: smaller and quieter. */
.section-note {
  font-size: 0.9rem;
  line-height: 1.6;
  color: var(--muted);
  max-width: 64ch;
  margin: 32px auto 0;
  text-align: center;
}

/* 11. NO GRADIENT ON ANY BUTTON -- 29 September 2026, at the CFO's request.
   A filled button is .btn-primary on a light surface and .btn-light on navy
   or any dark band. Product buttons no longer carry the product colour; the
   route to Flow and to Pace is told apart by its label, which already names
   the product in full.

   .btn-flow, .btn-pace and .btn-flow-bright are retired. They were kept as
   aliases for one round while dev swapped their markup; dev confirmed on
   29 September that no template on main names them, so the aliases are
   deleted. The retired gradient recipe is kept in git: tag
   gradient-buttons-2026-09-28. */

/* 4. Guardrails lead with the brand icon and a plain title rather than a
   filled pill, so the six read as a set of statements rather than tags. */
.guardrail .g-head {
  display: flex; align-items: center; gap: 12px;
  margin-bottom: 14px;
}
.guardrail .g-icon { width: 34px; height: 34px; flex: 0 0 34px; object-fit: contain; }
.guardrail h4 { font-size: 0.98rem; color: var(--ink); margin: 0 0 8px; }

/* 6. The group strip left a wide gap before the logo because the copy was
   capped at 64ch inside a column that was much wider. Let the text use the
   column and pull the logo in. */
.group-strip { grid-template-columns: minmax(0, 1fr) auto; gap: 40px; }
.group-strip p { max-width: none; }
.group-strip .b2be-mark { flex: 0 0 auto; }
.group-strip .b2be-mark img { max-width: 190px; height: auto; display: block; }
@media (max-width: 780px) {
  .group-strip { grid-template-columns: 1fr; gap: 24px; }
  .group-strip .b2be-mark img { max-width: 150px; }
}


/* 7. HOME HERO ARTWORK.

   History, so this isn't re-litigated: the hero ran pattern7 sized by width
   (`124% auto`), which scaled that portrait artwork (768.71 x 1182.6) to
   roughly 2750px tall inside a ~750px frame — one magnified fragment rather
   than a pattern. Sizing it by height instead showed the whole ribbon and
   turned it into a small placed graphic in the right third; cropping harder
   filled the frame but hid most of the swirl. Neither works, because pattern7
   is portrait and this banner is landscape: on a wide frame that artwork can
   be shown in full or fill the space, not both.

   So the homepage hero uses pattern8 instead — a closed loop that is already
   near-square (745.91 x 744.76), so `contain` shows the complete figure at
   full height with no crop and no terminus.

   Positioned at 70% rather than flush right: pinned to the edge the loop read
   as cropped by the frame even though it wasn't. Floating it inboard gives
   clearance on both sides so the figure reads as complete and deliberately
   placed. It stays clear of the copy column, and the mask above keeps the
   overlap with the lede faint. */
.hero::before {
  background-image: url('patterns/pattern8.svg');
  background-position: 70% center;
  background-size: contain;
  background-repeat: no-repeat;
}
@media (max-width: 900px) { .hero::before { background-position: center; background-size: cover; } }

/* ROUND 2026-09-10 (fix) -- the item 9/10 typography normalisation above
   uses `.section > .container ...` selectors, which outrank the original
   `.section-cool ...` rules at the top of this file and repainted ledes and
   inline links in the dark cool sections with the light-background colours.
   Restore the dark-background treatment at matching specificity. */

.section.section-cool > .container .section-head > p,
.section.section-cool > .container .section-lede,
.section.section-cool > .container .section-note,
.section.section-cool > .container .section-head > .lede,
.section.section-dark > .container .section-head > p,
.section.section-dark > .container .section-lede,
.section.section-dark > .container .section-note { color: rgba(255,255,255,0.78); }

.section.section-cool > .container .muted,
.section.section-dark > .container .muted { color: rgba(255,255,255,0.62); }

.section.section-cool > .container a:not(.btn):not(.role-card),
.section.section-dark > .container a:not(.btn):not(.role-card) { color: var(--gf-cyan); text-decoration: underline; text-underline-offset: 3px; }

/* The role card is chrome, not prose. The rule above is a bare descendant
   selector, so at 0,3,1 it out-specified .role-card{text-decoration:none}
   (0,1,0) and underlined the card anchor; text-decoration propagates to
   descendants and a child cannot cancel it, so every .rc-tag and .rc-line
   on the navy band inherited the underline and the four boxes read as link
   lists rather than cards. The border and the .rc-cta carry the affordance.
   Same :not() repetition as the chrome selectors in 2 (fix) below. */
.section.section-cool > .container a.role-card,
.section.section-dark > .container a.role-card { text-decoration: none; }

/* 2 (fix) -- the underline rule above was scoped to `.section`, so prose
   links inside sections that carry their own class instead (.persona-band,
   .callout, .cta-band and so on) stayed unadorned. Anchor it to the text
   element that holds the link rather than to the section, then put the
   chrome back to no underline. The chrome selectors below repeat the
   :not() clauses so they match on specificity and win on source order. */
p > a:not(.btn):not([class*="btn"]),
li > a:not(.btn):not([class*="btn"]),
dd > a:not(.btn),
td > a:not(.btn) { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }

.site-header li > a:not(.btn):not([class*="btn"]),
.site-header p > a:not(.btn):not([class*="btn"]),
.site-footer li > a:not(.btn):not([class*="btn"]),
.site-footer p > a:not(.btn):not([class*="btn"]),
.subnav li > a:not(.btn):not([class*="btn"]),
.nav-dropdown li > a:not(.btn):not([class*="btn"]),
li > a.blog-card, li > a.card, li > a.tile,
p > a.arrow-link, p > a.cta-inline { text-decoration: none; }

/* The header used to sit in this rule, which put a prose underline back on
   nav links the moment they were hovered. Nav is chrome, not prose: the
   background and the blue carry the state. Footer links keep the underline. */
.site-footer li > a:not(.btn):hover { text-decoration: underline; text-underline-offset: 3px; }

/* The entity block in the footer keeps its own underlined phone and email. */
.foot-entity a { text-decoration: underline; text-underline-offset: 3px; }

/* Alternatives: the category cards sat flush against each other vertically
   because the subgrid row-sync needs `row-gap: 0` to line the rows up.
   A subgrid can override the gutters inside its own span, so the parent
   carries the 24px band gap and each card zeroes it internally. The only
   gaps the parent's value actually paints are the ones between cards. */
.grid-sync.cat-grid { row-gap: 24px; }
.grid-sync.cat-grid > .cat-card { row-gap: 0; }
@media (max-width: 880px) { .grid-sync.cat-grid { row-gap: 24px; } }


/* The privacy line under the form buttons had lost its margin to a later
   `margin-top: 0` reset, so it sat hard against the button row. */
.mock-form .fs-disclaimer,
.contact-form .fs-disclaimer,
form .fs-disclaimer { margin-top: 22px; line-height: 1.6; }

/* ============================================================
   ROUND 2026-09-14 — contrast corrections
   ------------------------------------------------------------
   Two failures against WCAG AA (4.5:1 for text under 18.66px
   bold / 24px regular). Appended rather than edited in place,
   per the ground rules, so the earlier declarations stay
   readable as history.
   ============================================================ */

/* 1. --muted measured 4.18:1 on white and 3.84:1 on --soft, under the
   4.5:1 floor. It carries nearly every 12-14px supporting line in the
   site: .flow-step p, .arch-note, .tb-desc, .fs-opt span, .calc-helper,
   .section-note, .ev-meta and 32 others, none of which are large enough
   to qualify for the large-text exemption. #666B84 measures 5.25:1 on
   white and 4.83:1 on --soft, and reads as the same grey.
   All 39 uses sit on light ground. Dark surfaces override .muted with an
   explicit rgba(255,255,255,…) and do not reference this token, so
   nothing on a dark band moves. --muted-2 aliases this and follows. */
:root { --muted: #666B84; }

/* 2. Text on the product gradients.
   Every chip that carries text on a product fade was failing, because a
   two-stop brand fade runs from a colour dark enough for white to a
   colour light enough for ink, and no single text colour survives the
   sweep:

     Flow chip      #A30056 → #E9007B   white      4.42:1  (bright end)
     Pace chip      #2D6870 → #45A2AE   white      2.99:1  (bright end)
     Combined chip  #AF126B → #388DA1   white      3.82:1  (teal end)
     Flow tag       #690037 → #E9007B   white      4.42:1  (bright end)
     Pace tag       #2D6870 → #63E7F8   --cyan-ink 2.58:1  (dark end)
     Lever 1 tag    --grad-flow         white      4.42:1
     Lever 2 tag    --grad-pace         --cyan-ink 2.58:1

   Swapping the ink moves the failure to the other end rather than fixing
   it, so the fix is the gradient: text-bearing chips take the deep half
   of the same ramp and keep white, which holds 6.31:1 or better right
   across the fade. The chip still reads as Flow or Pace.

   This is chips only. Heroes, callouts, card top rules, list bullets and
   the hero washes keep the full brand fade: they are either decorative or
   carry type large enough to hold it. The distinction is the rule going
   forward — full fade on surfaces, deep fade under text.

   EXCEPTION, 2026-09-17: --chip-combined-stops is a declared departure
   from the rule above. It now carries the .page-hero wash verbatim
   (blue-800 -> blue-500 -> magenta-700 -> magenta-500 -> cyan-500) at
   the client's request, so the combined pill and hero read as the same
   object. That reintroduces the failure this section fixed — white on
   the cyan-500 tail is 1.47:1, not 6.31:1 — accepted deliberately here,
   for this chip only. Do not copy this pattern onto the Flow or Pace
   chips without the same explicit sign-off. */
:root {
  --chip-flow-stops:     var(--magenta-900) 0%, var(--magenta-700) 100%;
  --chip-pace-stops:     color-mix(in srgb, var(--cyan-900) 70%, #000) 0%, var(--cyan-900) 100%;
  --chip-combined-stops:
    var(--blue-800) 0%, var(--blue-500) 28%,
    var(--magenta-700) 54%, var(--magenta-500) 72%,
    var(--cyan-700) 90%, var(--cyan-500) 100%;
  --chip-combined-stops-oklab:
    var(--blue-800) 0%, var(--blue-500) 26%,
    var(--magenta-700) 58%, var(--magenta-500) 76%,
    var(--cyan-500) 100%;
}

/* Feature-list numerals and guardrail pills on themed pages */
body[data-theme="lever-method"]   .fl-icon,
body[data-theme="outcome-wc"]     .fl-icon,
body[data-theme="lever-method"]   .g-label,
body[data-theme="outcome-wc"]     .g-label {
  background: linear-gradient(135deg, var(--chip-flow-stops));
  color: #fff;
}
body[data-theme="lever-timing"]   .fl-icon,
body[data-theme="outcome-ebitda"] .fl-icon,
body[data-theme="lever-timing"]   .g-label,
body[data-theme="outcome-ebitda"] .g-label {
  background: linear-gradient(135deg, var(--chip-pace-stops));
  color: #fff;
}
body[data-theme="combined"] .fl-icon,
body[data-theme="combined"] .g-label {
  background: linear-gradient(135deg, var(--chip-combined-stops));
  background: linear-gradient(135deg in oklab, var(--chip-combined-stops-oklab));
  color: #fff;
}

/* Category tags on themed pages */
body[data-theme="lever-method"]   .tag,
body[data-theme="outcome-wc"]     .tag {
  background: linear-gradient(90deg, var(--chip-flow-stops));
  color: #fff;
}
body[data-theme="lever-timing"]   .tag,
body[data-theme="outcome-ebitda"] .tag {
  background: linear-gradient(90deg, var(--chip-pace-stops));
  color: #fff;
}
body[data-theme="combined"] .tag {
  background: linear-gradient(90deg, var(--chip-combined-stops));
  background: linear-gradient(90deg in oklab, var(--chip-combined-stops-oklab));
  color: #fff;
}

/* Lever card tags on the home and how-it-works pages. The About page
   reuses .lever-grid for B2BE and GlobalFinex and overrides these at
   higher specificity with the house blue, so it is unaffected. */
.lever-grid .lever:nth-child(1) .lever-tag {
  background: linear-gradient(90deg, var(--chip-flow-stops));
  color: #fff;
}
.lever-grid .lever:nth-child(2) .lever-tag {
  background: linear-gradient(90deg, var(--chip-pace-stops));
  color: #fff;
}

/* ---- Guardrails: the category label is an eyebrow ----
   The icon and label sat side by side, which read as a single inline chip
   and left the label competing with the h4 beneath it. Stacking the label
   under the icon gives the card three clear steps: mark, label, statement.

   Stacking alone did not settle it. The label was 1.02rem against a
   0.98rem h4, so the category read larger than the statement it labels
   and colour was the only thing separating two headings. The label is
   the small uppercase label above a heading, which is what .eyebrow is,
   so the card now carries the component instead of a private copy of it:
   size, weight, tracking and the light/dark colour pair all come from
   the one eyebrow definition. .g-title is gone.

   Only the spacing is local. .eyebrow ships a 14px bottom margin for use
   above a heading; inside .g-head the flex gap owns that space. */
.guardrail .g-head {
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}
.guardrail .g-head .eyebrow { margin-bottom: 0; }

/* ---- ROUND 2026-09-14b: .lede stepped, hero-only ----
   .lede is a hero standfirst and nothing else. All 37 uses sit in a
   .hero, .page-hero or .article-hero, plus the type specimen and the
   hero demos in the style guide. It is not a body-copy class:
   in-section intros use .section-lede / .section-head > p.

   The old clamp barely worked. clamp(1.05rem, 1.3vw, 1.15rem) renders
   16.8px at 390, 768 and 1280px — 0.8px over a 16px body, a difference
   nobody can see. The standfirst only separated from body copy above
   1415px. Stepping to whole numbers gives real hierarchy at every width
   and keeps the type scale free of decimals: 18px/27px, 20px/30px from
   1280. rem rather than px so a raised browser base font size scales.

   Colour is deliberately not restated here. The three hero rules set it
   at higher specificity and are untouched; the .lede colour at the top
   of the sheet stays live for the style guide's type specimen, which is
   the only .lede outside a hero.

   max-width is restated so the append carries the full intent in one
   place. .hero .lede keeps its 56ch — a descendant selector, so it wins
   on specificity regardless of order. */
.lede {
  font-size: 1.125rem;   /* 18px */
  line-height: 1.5;      /* 27px */
  max-width: 60ch;
}
@media (min-width: 1280px) {
  .lede { font-size: 1.25rem; line-height: 1.5; }   /* 20px / 30px */
}

/* ---- ROUND 2026-09-14c: component body copy to black ----
   --ink-2 was #4A4F66, a grey-navy carrying the body copy inside cards,
   guardrails, persona cards, flow steps and feature lists. It read as
   washed out against the pure-black --ink of ordinary paragraphs, so a
   card body looked weaker than the same sentence outside a card. Black
   removes that inconsistency: body copy is body copy wherever it sits.

   --ink-3 is an alias of --ink-2 and follows automatically, which is the
   intent — .cat-body, .ev-body, .fe-side-card p and the cookie-consent
   descriptions are the same tier of text.

   --muted is deliberately NOT folded in. It carries captions, metadata,
   labels and eyebrows, and it is the only thing separating a caption
   from the sentence above it. It also holds the AA tuning from the
   contrast round earlier today. Two tiers on light surfaces, not one:
   black for prose, --muted for everything that labels the prose.

   Safe on dark bands: every component using these tokens on a navy
   surface carries an explicit rgba(255,255,255,…) override at higher
   specificity, so none of them resolve the token there. */
:root { --ink-2: #000000; }

/* ---- ROUND 2026-09-14d: whole-number type scale, headings and intros ----
   Six of nine steps rendered fractional: h1 floor 38.4, h2 floor 28.8 and
   ceiling 41.6, h4 16.96, .section-lede 16.32, .section-note 14.4. The
   scale below was already latent in the values in use:

       13 · 14 · 16 · 17 · 18 · 20 · 22 · 28 · 40 · 64

   h1 and h2 KEEP their clamp and take whole endpoints only. A clamp can
   only ever have whole endpoints — 4.4vw is fractional at most widths —
   so whole numbers at every width would mean stepping, and a 40→64px
   step in a headline visibly snaps when the window crosses a breakpoint.
   Reviewed and settled: smooth beats whole for the two big headings.

   The gain is still real. h1's floor holds below 909px, so every phone
   and tablet width renders a whole 40px where it used to render 38.4px.
   h1 is now fractional only between 909 and 1455px.

   Bare element selectors are safe here: every scoped heading rule in the
   sheet (.guardrail h4, .legal-body h2, .gf-cc-head h2, .contact-info h4)
   carries higher specificity and is unaffected by this append.

   Body leading is deliberately NOT in this round. 16 × 1.55 = 24.8px is
   the last fractional value, but changing it moves the rhythm of every
   paragraph on all 33 pages, so it is its own decision. */
h1 { font-size: clamp(2.5rem, 4.4vw, 4rem); }     /* 40 floor, 64 ceiling */
h2 { font-size: clamp(1.75rem, 2.9vw, 2.5rem); }  /* 28 floor, 40 ceiling */
h4 { font-size: 1.0625rem; }                      /* 16.96 → 17 */

/* Both selectors restated: .section-head > p is (0,1,1) and would win
   over a bare .section-lede no matter where this block sits. */
.section-head > p,
.section-lede {
  font-size: 1.0625rem;   /* 16.32 → 17 */
  line-height: 1.6;
}
.section-note {
  font-size: 0.875rem;    /* 14.4 → 14 */
  line-height: 1.5;
}

/* ---- ROUND 2026-09-14e: one hero eyebrow and title position ----
   Measured at 1240px across the six hero shapes, the eyebrow's distance
   from the top of the hero ran 80 · 90 · 93 · 94 · 119 · 175px, the gap
   between label and h1 ran 4 · 14 · 20px, and one hero started its copy
   180px right of the other twenty-eight. Five separate causes:

     1. .page-hero centred its copy inside a 520px floor, so the eyebrow's
        offset depended on how long the lede was. terms.html sat 82px
        lower than for-cfos.html for no reason anyone chose.
     2. Three top paddings by hero type: 120 / 90 / 80.
     3. Three label gaps: .eyebrow 14px, .eyebrow-row 4px, .meta 20px.
     4. Chip eyebrows add 6px of their own padding, so a declared gap and
        an optical gap were not the same number.
     5. first-steps.html was the only .page-hero on .container-narrow.

   After this round: eyebrow top 90–94px, optical gap 14px everywhere,
   left edge 28px on every .page-hero. The residual 4px is the themed
   hero's accent stripe plus line-box leading on the inline-block span —
   both deliberate, both below the threshold of being visible, and
   reviewed as not worth two more declarations to chase.

   .hero keeps its 120px. The home statement is the one hero that is
   meant to sit lower than the rest. */

/* Anchor the copy to the top instead of centring it. The floor drops
   520 → 360: position was the thing that was inconsistent, and a hero
   whose height follows its content reads as intentional. */
.page-hero { align-items: flex-start; min-height: 360px; }

/* One top padding for every inner-page hero. */
.article-hero { padding: 90px 0 100px; }

/* One optical gap of 14px between label and title. A chip carries 6px of
   its own bottom padding, so its margin is 8px and the text lands in the
   same place as a plain eyebrow's 14px. */
.eyebrow-row { margin-bottom: 8px; }
body[data-theme] .page-hero > .container > .eyebrow { margin-bottom: 8px; }
.article-hero .meta { margin-bottom: 14px; }

/* ---- ROUND 2026-09-15a: prose that starts on the hero's left edge ----
   #control-point on how-it-works.html sat in .container-narrow (880px,
   centred) directly under a .page-hero in .container (1240px). Both are
   margin:0 auto with 28px of padding, so at 1440px the section's left
   edge landed 180px right of the h1's. The eyebrow, h1 and h2 read as
   one column and were not one.

   The container drops to the full 1240px and the copy runs the width of
   it: one left edge from eyebrow to last paragraph, and no cap on the
   right. Reviewed at 68ch first and taken to full width deliberately —
   the wide measure is the intended treatment, not an oversight.

   max-width: none rather than no declaration at all, because .lede caps
   at 60ch and .section-lede at 64ch from further up this file; a bare
   container swap would leave those two capped and the plain paragraphs
   wide, which is the one result nobody wants. */
.prose-left > p,
.prose-left > .lede,
.prose-left > ul,
.prose-left > ol,
.prose-left > .callout-soft { max-width: none; margin-left: 0; margin-right: 0; }

/* ---- The same left edge on the generated legal documents ----
   The three Flow documents under legal/ open their body on
   .container-narrow beneath a .container hero — the identical 180px offset
   .prose-left exists to remove. They cannot take the class: they are
   generated from Legal's Word files by the dev build, and the next
   revision from Legal would drop any edit made to the markup.

   .legal-doc is on those three pages and nothing else, so the treatment is
   applied from here instead of from the HTML. Same result, same reasoning
   as .prose-left above — one left edge from the eyebrow to the last
   clause, and no cap on the right.

   gdpr.html is the remaining document page with the offset. It is the
   dev's file and carries no hook, so it needs .legal-doc adding to its
   section; noted in the handover. */
.legal-doc > .container-narrow { max-width: var(--container); }
.legal-doc > .container-narrow > p,
.legal-doc > .container-narrow > ul,
.legal-doc > .container-narrow > ol,
.legal-doc > .container-narrow > table { max-width: none; margin-left: 0; margin-right: 0; }

/* ---- ROUND 2026-09-15b: the same left edge on every prose section ----
   The offset fixed above was not unique to how-it-works.html. Eighteen
   more prose blocks across fourteen pages opened a section on
   .container-narrow under a .container hero, so every one of them
   started its h2 180px right of its own h1 at 1240px.

   pace.html #core is in. It was held back while the treatment still
   capped the measure at 68ch, which left its card grid narrower than
   the section above it; at full width that reason is gone.

   flow.html #core is the one prose section still out. It already sits
   on .container, so its left edge was never wrong — only its measure,
   and that is now the intended treatment everywhere else. Left alone
   pending review rather than by argument.

   Lists and .callout-soft run the same full width as the paragraphs.
   A panel or a list narrower than the prose around it reads as a
   different block, and on use-case-pension-payments and
   use-case-tax-payments the callout is the section's last word.

   Not converted, and deliberately: legal long-form (terms, privacy,
   cookie) keeps the narrow column its tables are built for; the
   .article-hero blocks on blog and case-study pages are heroes, not
   body sections; first-steps keeps its wizard card; the two event
   registration forms keep the narrow measure a form wants. Sections
   pairing prose with ul.checklist are untouched for now: the rule
   covers lists, so they are a straight conversion whenever they are
   reviewed — held back for that review, not by any argument.

   Separately: event-launch-pay-smarter.html carried four bare
   class="container-narrow" divs with no .container, so those sections
   had no horizontal padding and ran to the viewport edge on mobile.
   They now carry both classes. */

/* ---- ROUND 2026-09-16b: the roundtable page joins the left edge ----
   event-finance-roundtable-oct-2026.html kept five prose sections on
   .container-narrow under a .page-hero in .container, so Why October,
   What this morning is not, What you leave with, Who is at the table
   and Seats are by invitation all opened 180px right of the hero's h1
   at 1440px. Four of the five were the checklist-and-prose pairings
   ROUND 2026-09-15b held back for review rather than excluded by
   argument; this is that review, and they convert.

   ---- ROUND 2026-09-16c: and Seats are by invitation centres instead ----
   The fifth section, the registration form, was reviewed at the left
   edge and centred instead. It now takes the .container +
   .eyebrow.center + h2.center + .section-lede pattern the other three
   centred sections on this page already use, so the page has four
   centred blocks built one way rather than three plus a variant.

   That reversal killed the rule this block was originally written for:
   .prose-left > .contact-form held the form's measure while its section
   ran full width, and this page was the only one pairing those two
   classes. Rather than leave an unreachable selector behind, it is
   replaced by the centred equivalents below.

   The 824px measure survives the change. It is what the form rendered
   at before either round — a child of an 880px container with 28px of
   padding either side, so the container's max-width was never the
   form's width. Hence the calc: var(--container-narrow) on its own
   measures 56px wider, which is a change to the form rather than to
   where it sits.

   The form centres as a block and nothing inside it does. Labels,
   inputs, the submit and the closing note all stay on the form's left
   edge, because a centred label breaks the scan line down the left of
   the fields that keyboard and screen-reader users follow, and a
   centred submit leaves that column with no closing edge.

   16c centred the submit on the argument that a single element closing
   the block was not part of that column. Reviewed and reversed: the
   button is the control the field column leads to, so it belongs on the
   same edge as the fields it submits. There is no #request override for
   it now — .contact-form > button[type="submit"] is already
   align-self: flex-start further up this file, and the base rule is
   left to do its job rather than restated here.

   74ch on the callout matches the "Who we are inviting" callout in the
   section above, so the page's two soft callouts share one measure.

   ---- ROUND 2026-09-16d: and the vertical rhythm with it ----
   Centring the section exposed three gaps, two of them introduced by
   16c above and one older than both rounds. Measured at 1440px, the
   section ran 14 / 20 / 36 / 36 / 0 against an original 14 / 20 / 16 /
   18 / 0.

   The 36px between the two paragraphs was the mistake. .section-lede
   carries margin: 0 auto 36px and is built for one intro paragraph
   before a component, which is how The format, The morning and Dates
   each use it; applied to a consecutive pair it separated two sentences
   of one thought as if they were different blocks. 16px restores the
   rhythm those paragraphs had as plain <p>. Adjacent-sibling collapse
   does the rest: the last lede still yields to the callout's larger
   margin, so only the pair tightens.

   36px before the callout is the lede-to-component gap The format
   already uses, and is kept rather than returned to its old 18px.

   The 0px was never ours. .callout-soft is margin: 18px 0 0, bottom
   zero, and .contact-form carries no top margin, so the first field
   label sat flush against the callout's lower edge — as true of the
   left-aligned layout as of this one, and only easier to see once the
   block was centred. 32px is this page's own component step, the
   margin the "Who we are inviting" callout is given inline.

   Result: 14 / 20 / 16 / 36 / 32. */
#request p.section-lede { margin-bottom: 16px; }
#request .callout-soft { max-width: 74ch; margin-inline: auto; margin-top: 36px; }
#request .contact-form { max-width: calc(var(--container-narrow) - 56px); margin-inline: auto; margin-top: 32px; }

/* ---- ROUND 2026-09-15a: the matrix sub-head joins .section-head ----
   The "Which lever does what" block on how-it-works was a one-off:
   a bare .center div carrying its own max-width and margins inline,
   an h3 pinned to 1.4rem and a description pinned to 0.95rem. Next to
   the section descriptions above and below it, set by .section-head > p
   at 1.0625rem, it read as a smaller, quieter tier than the page has.

   Rather than a second intro component, .section-head now accepts an
   h3 title alongside its h2, so a subsection intro reuses the same
   measure, centring, eyebrow spacing and description scale. The element
   stays an h3 — it is a subsection of #levers, and the document outline
   should not be demoted to buy a font size. */
.section-head > h3 { margin: 0 0 14px; }

/* Same size, same clearance: 96px matches the section's own top padding,
   so the two heads in #levers are separated on the same terms. The old
   48px was a half-step that made sense while the sub-head was smaller;
   once the sizes matched it was the only thing still calling it a lesser
   tier, and it read as cramped rather than subordinate. */
.section-head-sub { margin-top: 96px; }
/* .section drops to 64px padding at 880px, so the sub-head follows it
   down. Left at 96px it would separate the two heads by more than the
   section separates itself from its neighbours. */
@media (max-width: 880px) { .section-head-sub { margin-top: 64px; } }
.section-head-sub > h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.75rem, 2.9vw, 2.5rem);  /* matches h2 exactly */
  line-height: 1.1;
  letter-spacing: -0.02em;
}

/* The trailing note under the matrix runs about 97 characters, so the
   64ch measure .section-note gives every other note broke it across two
   lines. Uncapped it sits on one line from roughly 700px up and wraps
   on its own below that, where one line is not available at any width. */
.section-note-wide { max-width: none; }

/* ---- ROUND 2026-09-15c: hero headline leading, and the gaps around it ----
   Four faults, measured across .hero, .page-hero and .article-hero at
   1440 / 1240 / 900 / 700px. All four are spacing, none needed markup.

     1. h1 leading was 1.05, which is BELOW Roboto's own glyph box of
        1.172em (ascent 0.927 + descent 0.244). Ink clearance — descender
        of one line to cap-height of the next — came to

            1.05 - 0.711 (cap) - 0.271 (descender) = 0.068em

        4.4px at the 64px ceiling and 2.7px at the 40px floor. That is a
        collision, not tight tracking, and it showed worst on the homepage
        where .hero-question h1 runs to 4.6rem over "Approved quickly."
        and at phone widths where the headline wraps to three or four
        lines. 1.1 is the value h2 already carries, so display leading is
        now one number rather than two, and clearance roughly doubles.

        1.15 below 880px because a single value cannot serve both ends of
        a clamp: at the 40px floor, 1.1 gives back the same cramped
        clearance 1.05 gave at 64px. Leading has to loosen as size drops.

     2. The gap ABOVE the headline was two different numbers. ROUND
        2026-09-14e set .eyebrow-row and the themed .page-hero eyebrow to
        8px, explicitly to compensate for "6px of chip padding" so a chip
        eyebrow would land where a plain 14px one did. The chip was then
        removed in 588bdb8 and the compensation was left behind, so those
        heroes have been sitting 6px tighter than the rest ever since.
        Measured: 30.1px above the homepage h1 against 22.4px above
        pace's, at 1240px. The compensation goes; 14px everywhere.

     3. The gap BELOW the headline was h1's `margin: 0 0 0.5em`, taken
        from a clamped font-size, so it was 32px at 1455px, 27.28px at
        1240px and 20px on a phone — fractional through the whole middle
        of the range, and smallest exactly where the headline is densest.
        Optically it ran 2.2-2.6x the gap above it: 52.8px against 30.1px
        at 1240px on the homepage.

        10px, not 14px, because the two gaps are not symmetric. The h1's
        own leading already contributes about 4px more space below its
        last baseline than the eyebrow's contributes above its first cap.
        Declared 14 above / 10 below is what makes the two read equal.
        Measured residual after this round: -1.8px to +0.6px across all
        three hero types at all four widths, against +9px to +27.3px
        before it. The number is tuned to the leading, so if h1's
        line-height changes again this one has to be re-measured.

     4. Stacked CTA buttons. gap: 12px is equal on both axes as declared,
        but the buttons are pills: side by side, two facing semicircular
        caps of radius r leave a mean separation of 12 + 2r(1 - pi/4),
        which at r = 23.5px is 22.1px. Stacked, the pills present their
        flat edges and the separation is a constant 12px across the whole
        overlap. Equal numbers, unequal space. row-gap 20px matches the
        optical mean; column-gap keeps its 12px.

   The paragraph break inside a hero follows from 3: at 18px it was
   32.2px optical against a 28.2px headline gap, so two stacked ledes
   separated MORE than the headline separated from the body. Only
   contact.html has the pair today. 8px puts it back under the headline
   gap (22.2 against 28.2) and the collapse is driven off the first
   paragraph, not the second, so the trailing gap to a bare
   .hero-cta-row on the two event pages is untouched. */
h1 { line-height: 1.1; }
@media (max-width: 880px) { h1 { line-height: 1.15; } }

.eyebrow-row { margin-bottom: 14px; }
body[data-theme] .page-hero > .container > .eyebrow { margin-bottom: 14px; }

.hero h1, .page-hero h1, .article-hero h1 { margin-bottom: 10px; }

.hero .lede:has(+ .lede),
.page-hero .lede:has(+ .lede),
.article-hero .lede:has(+ .lede) { margin-bottom: 8px; }

.hero-cta-row { row-gap: 20px; }


/* ============================================================
   ARCH DIAGRAM — THE FLOW VARIANT  .arch-diagram.is-flow
   2026-09-16
   ============================================================ */
/* Flow's architecture diagram carries the product accent rather than
   primary blue. The modifier is on the diagram, not on the page, because
   body[data-theme="lever-method"] is worn by the design-system page too —
   theming on it would have dragged the library specimen along. The
   specimen stays blue and documents this variant beside it.

   WHAT TURNS MAGENTA, and what does not. Only the GlobalFinex band: the
   three control-layer cards, both flow arrows and the remittance chip.
   The buyer column keeps its indigo and the supplier column its cyan, so
   the diagram still reads as three zones with our own layer between two
   ecosystems that are not ours. Recolouring the buyer column as well was
   considered and rejected — it collapses the left two zones into one.

   THE INK IS 700, NOT 500. magenta-700 measures 7.80:1 on white, the
   figure the eyebrow section above already relies on. magenta-500 is
   4.0:1 there and fails AA for the arrow labels and the chip, all of
   which are small text. 500 appears nowhere in this block.

   The card gradient is 700 -> 900, the same pair as --chip-flow-stops
   (and the pre-2026-09-29 .btn-flow), so the darkest surface in the diagram matches the
   darkest surface elsewhere on the page.

   The icons are gone from the markup, not hidden here — the seven
   .arch-icon tiles were removed from flow.html. The .arch-icon rules
   earlier in this sheet are left intact for the library specimen. */

.arch-diagram.is-flow .arch-col-gfx {
  background: linear-gradient(180deg, rgba(163,0,86,0.07) 0%, rgba(163,0,86,0) 100%);
  border-color: rgba(163,0,86,0.20);
}
.arch-diagram.is-flow .arch-col-gfx .arch-col-label { color: var(--magenta-700); }

/* The base .arch-card.is-gfx is already blue -> blue-deep. This variant used
   to replace that with pure magenta; it now bridges the two, same as the
   hero.

   UPDATED 2026-09-16: these cards now take the themed hero's ramp exactly —
   same four stops, same 105deg, same sRGB interpolation, so every gradient
   surface on flow.html is one gradient. An earlier pass held the close at
   magenta-700 on the grounds that 500 failed the body copy. That was true
   of the two-stop 155deg run it was measuring; it is not true here. Under
   the four-stop ramp magenta-500 exists only at the far corner, and the
   note ink is what had to move instead.

   .arch-note IS LIFTED TO PURE WHITE, and must stay there. At 0.78 it drops
   under 4.5:1 past 78.3% along the axis; at 105deg across a ~242px card the
   text reaches roughly 88-92%, where 0.78 gives 3.74-4.36:1. Minimum alpha
   is 0.847 if the text stops at 85%, 0.899 at 90%, 0.954 at 95% — the
   landing point cannot be pinned closer than 88-92%, so 0.92 is not safe
   and #fff is. #fff holds 4.87:1 at 95% and only the literal 100% corner,
   which is padding, falls to 4.42:1.

   The lift is scoped to .is-flow. The base rule and the design-system
   specimen keep 0.78, which is correct on their blue-only fill.

   The border stays magenta-700: at 1px it is not a text surface, and it
   frames the card against the white diagram better than 500. */
/* Hero ramp, exactly - stops, angle and interpolation. Added the oklab
   line 2026-09-21 when the hero gained one. These render on the same page
   as the hero; any divergence in pacing shows as two different magentas. */
.arch-diagram.is-flow .arch-card.is-gfx {
  background: linear-gradient(105deg,
    var(--blue-800) 0%, var(--blue-500) 34%,
    var(--magenta-700) 72%, var(--magenta-500) 100%);
  background: linear-gradient(105deg in oklab,
    var(--blue-800) 0%, var(--blue-500) 32%,
    var(--magenta-700) 70%, var(--magenta-500) 100%);
  border-color: var(--magenta-700);
}
.arch-diagram.is-flow .arch-card.is-gfx .arch-note { color: #fff; }

.arch-diagram.is-flow .arch-arrow::before {
  background: linear-gradient(to right, transparent 0%, var(--magenta-700) 50%, transparent 100%);
}
.arch-diagram.is-flow .arch-arrow::after { border-left-color: var(--magenta-700); }
.arch-diagram.is-flow .arch-arrow .arrow-label { color: var(--magenta-700); }

/* ---- Stacked, the connectors turn through 90 degrees ----
   Below 1000px the grid is a single column and the two .arch-arrow cells
   become full-width rows. DOM order already places each one between the two
   columns it joins, so only the geometry changes: the rule and the head run
   top-to-bottom instead of left-to-right, and the label keeps its place on
   the line. They used to be display:none here, which left the stack as three
   labelled boxes with nothing saying what passes between them.

   This block sits after the .is-flow accent rules above rather than with the
   other mobile arch rules further up, because the two .is-flow lines it
   restates match those rules' specificity exactly — source order is the only
   thing that decides it, so it has to come last. */
@media (max-width: 1000px) {
  .arch-arrow {
    display: flex;
    /* The label is ~26px and carries a 4px white halo, so the height has to
       cover the label plus enough line either side to read as a connector
       rather than a dash. */
    min-height: 64px;
  }
  .arch-arrow::before {
    top: 0; bottom: 0;
    left: 50%; right: auto;
    width: 2px; height: auto;
    transform: translateX(-50%);
    /* Not the horizontal gradient's symmetric fade: vertically the line has
       to arrive solid at the arrowhead, so it fades in from the block above
       and then holds. */
    background: linear-gradient(to bottom, transparent 0%, var(--gf-blue) 34%, var(--gf-blue) 100%);
  }
  .arch-arrow::after {
    top: auto; bottom: 0;
    left: 50%; right: auto;
    transform: translateX(-50%);
    border-left: 6px solid transparent;
    border-right: 6px solid transparent;
    border-top: 9px solid var(--gf-blue);
    border-bottom: 0;
  }
  .arch-diagram.is-flow .arch-arrow::before {
    background: linear-gradient(to bottom, transparent 0%, var(--magenta-700) 34%, var(--magenta-700) 100%);
  }
  /* The accent rule above colours border-LEFT, which points the head right.
     It out-specifies the shorthand in this block, so the left edge has to be
     cleared here or it survives as an L beside the downward head. */
  .arch-diagram.is-flow .arch-arrow::after {
    border-top-color: var(--magenta-700);
    border-left-color: transparent;
  }
}

.arch-diagram.is-flow .arch-return-chip {
  border-color: var(--magenta-700);
  color: var(--magenta-700);
}


/* ============================================================
   OUTCOME BANNER — THE FLOW VARIANT  .outcome-highlight.is-flow
   2026-09-16
   ============================================================ */
/* Flow's MOR banner carries the product accent. Scoped to the banner for
   the same reason as the diagram above: .outcome-highlight also appears on
   outcome-ebitda.html and alternatives.html, and body[data-theme] would
   have taken the design-system page with it.

   THE WASH RUNS TO 500, AND THAT IS A DELIBERATE EXCEPTION.
   The banner's copy is left-aligned and full-bleed rather than centred, so
   it does reach the bright end, and white on magenta-500 is 4.42:1 — under
   the 4.5:1 AA floor for small text. It also runs against the rule set on
   2026-09-14 in TODO-design-system.md: full brand fade on surfaces, deep
   fade under text.

   Ending the fade on magenta-700 would have held 7.80:1 throughout and was
   the recommendation. The brighter wash was chosen instead, with the
   shortfall known. Recorded in TODO-design-system.md under
   "Accepted exceptions". Do not "fix" this back to 700 without asking —
   it is a decision, not an oversight. THAT DECISION IS PRESERVED BELOW:
   the 100% stop is still magenta-500.

   2026-09-16, second pass: the anchor moved from magenta-900 to the blue
   ramp so the banner follows the themed heroes and callouts. Only the
   run-up changed. The left and middle of the copy now sit on blue-800 ->
   blue-500 (16.31:1 -> 8.93:1) instead of magenta-900 -> magenta-700, so
   the accepted 4.42:1 now applies to a narrower strip at the right edge
   than it did before. The exception is unchanged; its blast radius shrank.

   The pattern is a white recolour, which the banner already used. The
   coloured originals are blue fans with magenta tails: near invisible on
   the old blue ground, and the relationship inverts on magenta, so only
   the blue would have shown. White is ground-agnostic.

   2026-09-21, third pass: TWO CHANGES, and the second retires the
   exception above in practice.

   1. pattern4-white -> pattern3-white. The hero patterns were swapped
      earlier today (b2e41e4), which made pattern4-white Pace's artwork
      while this banner sits on Flow. It now follows its own hero again.
      Anything that references a pattern by name has to move when the
      heroes do - this banner was the one that got missed.

   2. The banner is built like the small hero it is: artwork at full
      strength in its own right-hand column (38% wide, masked off the
      left), and the copy capped at 24ch / 62ch instead of running
      full-bleed underneath it. Without the caps there is no clear zone
      and the artwork crosses every line of the lede.

   WHAT THAT DOES TO THE 4.42:1 EXCEPTION. The wash is untouched - the
   100% stop is still magenta-500, so the decision recorded above stands
   and has not been reverted. What changed is that the copy no longer
   REACHES the bright end. Measured on the rendered page, the copy column
   now stops at ~50% of the panel; across it the background runs 10.80:1
   down to 9.44:1 and back to 10.24:1 at the cap. The far right edge still
   measures ~5.09:1 mid-height and lower into the bottom corner, but no
   text sits there any more.

   So the accepted shortfall no longer applies to anything. The entry in
   TODO-design-system.md under "Accepted exceptions" is now stale and
   should be closed rather than carried forward. */

.outcome-highlight.is-flow {
  background: linear-gradient(140deg,
    var(--blue-800) 0%, var(--blue-500) 40%,
    var(--magenta-700) 78%, var(--magenta-500) 100%);
}
.outcome-highlight.is-flow::before {
  background-image: url('patterns/pattern3-white.svg');
  background-size: 38% auto;
  background-position: right center;
  background-repeat: no-repeat;
  opacity: 1;
  /* 2026-09-22: px, not per cent. See the note on the collapse block. */
  -webkit-mask-image: linear-gradient(100deg, transparent 0, transparent 700px, rgba(0,0,0,0.30) 820px, #000 1010px);
  mask-image: linear-gradient(100deg, transparent 0, transparent 700px, rgba(0,0,0,0.30) 820px, #000 1010px);
}
/* The banner is a small hero, so it is now built like one: artwork in its
   own right-hand column, copy given a column of its own instead of running
   full-bleed underneath it. Without these two caps there is no clear zone
   and the artwork crosses every line of the lede. */
.outcome-highlight.is-flow h2 { max-width: 24ch; }
.outcome-highlight.is-flow p  { max-width: 62ch; }


/* ============================================================
   CARD-RAILS BAND — THE FLOW ACCENT  #card-rails
   2026-09-16
   ============================================================ */
/* Scoped to the id, which only flow.html carries. .timeline-frame is also
   on combined.html and the design-system page and neither is touched —
   that is the reason this is keyed on the section rather than on the
   component.

   THE EYEBROW IS magenta-500 ON NAVY, AND IT IS A KNOWN AA EXCEPTION.
   3.73:1 against --navy, under the 4.5:1 floor for small text. It also
   overturns, for this one band, the rule argued at length in the eyebrow
   section near the top of this sheet: the navy band keeps the site cyan,
   because navy is the one dark ground that is NOT the product's own
   colour. --gf-cyan measures 11.25:1 there.

   Asked for explicitly and chosen with the figure known. Recorded in
   TODO-design-system.md under "Accepted exceptions" and on the design
   system page. Do not revert it to cyan without asking.

   THE DOTS ARE THE OPPOSITE CASE — this is a fix, not a concession.
   They are non-text graphics, so the bar is 3:1. --gf-blue on navy was
   1.85:1 and had been failing all along; the dots read only because of
   their white rings. magenta-500 is 3.73:1 and clears it. The same value
   fails as an eyebrow and passes as a dot because the bars differ, not
   because the measurement does.

   All three dots take the same step. is-mid was --gf-indigo and is-end
   --gf-blue-deep, which resolve to #1C39BB and #142883 — indistinguishable
   at 18px, so the progression they encoded has never been visible. One
   colour states plainly what the band already looked like.

   The +55 card fades 700 -> 900, the deep pair, so its white copy holds
   7.80:1. Deliberately NOT the 700 -> 500 used by the MOR banner above:
   chosen per-element, and this one stays inside the floor. */

/* REMOVED 2026-09-16: the navy band returns to --gf-cyan at 11.25:1.
   magenta-500 here was 3.73:1, a logged exception now retired. */

#card-rails .timeline-marker::before,
#card-rails .timeline-marker.is-mid::before,
#card-rails .timeline-marker.is-end::before {
  background: var(--magenta-500);
  box-shadow: 0 0 0 2px var(--magenta-500);
}
#card-rails .timeline-extension { border-color: var(--magenta-500); }

/* UPDATED 2026-09-16: the DPO headline cell joins the site gradient recipe.
   It was the last accent panel still on the deep/deep pair, so against the
   home cards and the working-capital lever tags it read as a different
   component rather than the same one. sRGB first as the fallback; the oklch
   line only changes the pacing, not the endpoints. */
#card-rails .ts-cell.is-headline {
  background: linear-gradient(100deg, var(--blue-500) 0%, var(--magenta-500) 100%);
  background: linear-gradient(100deg in oklch, var(--blue-500) 0%, var(--magenta-500) 100%);
  border-color: var(--magenta-500);
}


/* ============================================================
   ARCH DIAGRAM — NEUTRAL BUYER & SUPPLIER COLUMNS
   .arch-diagram.is-flow
   2026-09-16
   ============================================================ */
/* The two outer columns are the parties Flow does not displace, so they
   go neutral and the control layer keeps the only accent in the diagram.
   Grey / magenta / grey reads as 'two untouched sides, one active middle',
   which is the claim the section is making.

   THE LABELS ARE INK-2, NOT INK-3. The column labels are 0.7rem uppercase
   at 600 — small text, so they need 4.5:1. ink-3 (#64748b) measures 4.76:1
   on white and clears it by almost nothing, and these sit on a #eef0f4
   wash rather than on white, which erodes the margin further. ink-2
   (#334155) measures 10.3:1 and holds on both grounds.

   THE BORDER IS --line, NOT --line-2, so the columns carry the same
   outline weight as the .ba-col.before panel in the before/after block
   further down the page. The two neutral surfaces on this page match.

   Scoped to .is-flow because .arch-col-buyer / .arch-col-sup also render
   on other pages, where the indigo and cyan coding is still in use. */

.arch-diagram.is-flow .arch-col-buyer,
.arch-diagram.is-flow .arch-col-sup {
  background: linear-gradient(180deg, var(--paper-3) 0%, rgba(238,240,244,0) 100%);
  border-color: var(--line);
}
.arch-diagram.is-flow .arch-col-buyer .arch-col-label,
.arch-diagram.is-flow .arch-col-sup   .arch-col-label {
  color: var(--ink-2);
}
.arch-diagram.is-flow .arch-col-buyer .arch-card:not(.is-gfx):not(.is-sup),
.arch-diagram.is-flow .arch-col-sup   .arch-card.is-sup {
  background: #fff;
  border-color: var(--line);
}


/* ============================================================
   BEFORE / AFTER — NEUTRAL LEFT PANEL  .before-after.is-flow
   2026-09-16
   ============================================================ */
/* The left panel is the do-nothing state. Its old fill was --soft
   (--blue-50, #F4F5FC) and its step borders --line-soft (--blue-100,
   #E8EBF8) — both faint blue. Going neutral puts the orange friction
   steps on grey instead of on blue, so they read harder.

   WHAT KEEPS ITS COLOUR, DELIBERATELY:
     - .ba-step.friction stays orange. It is the point of the panel.
     - .ba-col.after stays the blue gradient, untouched.

   Scoped to .is-flow because .before-after also renders on
   globalfinex-design-system.html, which still shows the original. The
   hook is on the wrapper in flow.html. */

.before-after.is-flow .ba-col.before {
  background: var(--paper-2);
  border-color: var(--line);
}
.before-after.is-flow .ba-col.before .ba-head {
  border-bottom-color: var(--line);
}
.before-after.is-flow .ba-col.before .ba-step:not(.friction) {
  background: #fff;
  border-color: var(--line);
}



/* ============================================================
   LEVER + OUTCOME CARDS — BLUE INTO THE PRODUCT RAMP
   .lever-grid .lever  ·  .persona-card[data-outcome]  ·  the card CTA
   2026-09-16
   CARRIES TWO ACCEPTED AA EXCEPTIONS — see section 2.
   ============================================================ */
/* The four cards on index.html — the two lever cards and the two outcome
   routing cards — carried pure product colour: --grad-flow #690037 -> #E9007B
   and --grad-pace #2D6870 -> #63E7F8 on the top rule, the chip and the
   bullets. Everything else on the site had already moved to the site ramp
   (1413ed2, f1f6f76): a themed page opens on blue and hands over to the
   product. The home page was the last surface still opening on the accent,
   so it read Flow and Pace first and GlobalFinex second.

   These cards now take the hero ramp. how-it-works.html shares .lever-grid
   and takes the same treatment, which is intended — it is the same pair of
   cards. about-b2be-group.html also reuses .lever-grid for its B2BE and
   GlobalFinex cards; it overrides the chip, the question line and the
   bullets to house blue at higher specificity but has never overridden the
   TOP RULE, so its two cards have been drawing Flow and Pace bars all
   along. They now draw blue-into-accent bars instead, which is less wrong
   than before but still not right. Left as found rather than fixed
   silently: a named About exception is a separate decision.

   POSITION. This block sits immediately before the themed-hero stripe rule,
   which carries its own "keep it last" note. Nothing here touches
   .page-hero, so the two do not interact.

   IT MUST BE LATE IN THE SHEET, though. The declarations it supersedes are
   spread across four places, and the winners were:
     ~3563  top rules            --grad-flow / --grad-pace
     ~3577  persona top rules    --grad-flow / --grad-pace
     ~3567  bullets              --grad-flow / --grad-pace
     ~4740  chips                --chip-flow-stops / --chip-pace-stops
   The chip rule at ~4740 is the reason: an earlier position loses to it. */

/* 1 - TOP RULES. Nothing sits on them, so they run the hero's full
       four-stop ramp at every stop, including the bright one. */
.lever-grid .lever:nth-child(1)::before,
.persona-card[data-outcome="working-capital"]::after {
  background: linear-gradient(90deg,
    var(--blue-800) 0%, var(--blue-500) 34%,
    var(--magenta-700) 72%, var(--magenta-500) 100%);
}
.lever-grid .lever:nth-child(2)::before,
.persona-card[data-outcome="ebitda"]::after {
  background: linear-gradient(90deg,
    var(--blue-800) 0%, var(--blue-500) 34%,
    var(--cyan-700) 72%, var(--cyan-500) 100%);
}

/* 2 - CHIPS (and, until 2026-09-29, THE CARD CTA). Two stops, blue-500 into the product's
       BRIGHT step, interpolated in oklch.

       WHY TWO STOPS AND WHY OKLCH. The previous three-stop sRGB ramp had
       two visible faults on an element this small: a slope kink where the
       mid-stop sat at 38%, and a low-chroma band through the middle,
       because a straight line across sRGB between two saturated colours
       passes through desaturated purple. Dropping the mid-stop removes the
       first; interpolating in oklch removes the second by travelling
       around the hue circle instead of through the middle of the cube.
       A plain sRGB two-stop gradient is declared first as the fallback for
       any engine without oklch interpolation.

       ------------------------------------------------------------------
       TWO AA EXCEPTIONS, TAKEN KNOWINGLY ON 2026-09-16. READ BEFORE REUSE.
       ------------------------------------------------------------------
       The label is white and spans the element. Ending on the bright step
       puts it over colours that cannot carry small text in ANY ink:

                       white      --cyan-ink (navy)
         magenta-500   4.42:1     3.69:1
         cyan-500      1.47:1    11.12:1

       Navy is not an escape. It is legible on the bright end and illegible
       on the blue start (2.58:1 on cyan-900, worse on blue-500), so no
       single ink clears the ramp. White is the better of the two.

       WHERE EACH RAMP CROSSES THE 4.5:1 FLOOR, measured along the oklch
       path from blue-500:

         Flow  holds 8.93:1 -> 4.5:1 for the first ~97% and misses only
               across the final ~3%. In practice the shortfall lands in the
               trailing padding on most label widths.
         Pace  crosses at ~35% and falls to 1.47:1 at the stop. Roughly
               two thirds of the label sits under the floor and the last
               third is not readable at all.

       Pace is the one that matters and it is not marginal. The same
       cyan-500 figure is recorded further up this sheet as the reason the
       themed hero's far edge "is not a text surface and must not become
       one". This makes it one, deliberately, for product presence.

       THE ONE-LINE FIX, if the floor is enforced later: move the 100%
       stops back to --magenta-700 (7.80:1) and --cyan-900 (6.31:1).
       Nothing else depends on the bright stops. A reserved-tail variant
       that keeps the bright step past the label was built and rejected in
       favour of this; it is the other way back.

       SCOPE. The PILL is .lever-grid only - index.html and
       how-it-works.html - because that is the only place it renders. The
       CTA half of this exception ended on 2026-09-29, when buttons lost
       their gradients; the figures above now apply to the pill alone. */
.lever-grid .lever:nth-child(1) .lever-tag {
  background: linear-gradient(100deg, var(--blue-500) 0%, var(--magenta-500) 100%);
  background: linear-gradient(100deg in oklch, var(--blue-500) 0%, var(--magenta-500) 100%);
  color: #fff;
}
.lever-grid .lever:nth-child(2) .lever-tag {
  background: linear-gradient(100deg, var(--blue-500) 0%, var(--cyan-500) 100%);
  background: linear-gradient(100deg in oklch, var(--blue-500) 0%, var(--cyan-500) 100%);
  color: #fff;
}

/* The card CTA used to take the same ramp as the pill. Retired on
   2026-09-29 -- no gradient on any button; see item 11, just before the guardrail rules.
   The pill keeps its ramp: it is a tag, not a button. */

/* 3 - BULLETS. A 9px dot cannot carry a four-stop ramp; it samples a
       sliver and renders as one colour. They take the product's own ramp
       step as a flat value, which is what the gradient collapsed to. */
.lever-grid .lever:nth-child(1) ul li::before { background: var(--magenta-700); }
.lever-grid .lever:nth-child(2) ul li::before { background: var(--cyan-900); }

/* 4 - TEXT LAYER. The question line above each lever heading and the
       outcome cards' label and CTA were the last product-coloured text on
       a light surface, which is exactly what f1f6f76 took off every other
       page: the accent stays on the washes. --gf-blue is 8.93:1 on white
       and on both card tints (#FEF4F9, #F2FCFE), against 4.60:1 and 6.31:1
       for the product values they replace.

       CONSEQUENCE, ACCEPTED: the two outcome cards are now separated only
       by the 4px top rule and the tint behind them. That is the same
       reduction the blue pass made everywhere else. */
.lever-grid .lever:nth-child(1) .lever-q,
.lever-grid .lever:nth-child(2) .lever-q,
.persona-card[data-outcome="working-capital"] .pc-role,
.persona-card[data-outcome="ebitda"] .pc-role,
.persona-card[data-outcome="working-capital"] .pc-cta,
.persona-card[data-outcome="ebitda"] .pc-cta { color: var(--gf-blue); }

/* ============================================================
   WORKING CAPITAL — THE TWO LEVER TAGS OPEN ON SITE BLUE
   body[data-theme="outcome-wc"] .grid-2 > .card:nth-child(n) .tag
   2026-09-16
   ============================================================ */
/* WHAT WAS WRONG. Both tags in the "Both levers, through a working-capital
   lens" grid were painted by body[data-theme="outcome-wc"] .tag at ~4781,
   which is keyed to the PAGE, not to the lever the tag labels. So both took
   the Flow chip ramp (--chip-flow-stops, magenta-900 -> magenta-700), and
   "Lever 2 · Timing" wore Flow magenta directly above a blue -> cyan Pace
   CTA. The tag contradicted the button beneath it.

   Two faults in one rule: the tags carried no blue at all, so they were the
   last elements on this page the "open on site blue" pass missed, and the
   second one named the wrong product.

   THE RAMP. blue-500 -> magenta-500 and blue-500 -> cyan-500, 100deg in
   oklch — the same two ramps as .lever-grid .lever-tag on index.html and
   how-it-works.html at ~5465. The lever pill and this tag are the same
   object at two sizes on two pages, and they now read that way. It is also
   this page's own hero endpoints: that wash opens --blue-500 and closes
   --magenta-500.

   SCOPE. data-theme="outcome-wc" is outcome-working-capital.html and
   nothing else. globalfinex-design-system.html matches a grep for the
   attribute but only as prose in its token table at ~503; its body carries
   .ds-body. flow.html (lever-method) shares the ~4781 rule and is NOT
   touched here — it keeps the deep chip ramp. This page has exactly two
   .tag elements and both sit in this grid.

   CONTRAST — AA EXCEPTION, DECLARED. .tag is 0.72rem (11.52px) at 600, so
   it is small text and the bar is 4.5:1. White on the ramps, measured
   across the oklch interpolation at 0.1% steps:

     Lever 1  blue-500 -> magenta-500   8.93:1 -> 4.42:1
              crosses 4.5:1 at 98% — the last 2% of the pill, past the end
              of the label at every width this page renders.
     Lever 2  blue-500 -> cyan-500      8.93:1 -> 1.47:1
              crosses 4.5:1 at 32%. Roughly two thirds of the label sits
              under the floor and the tail is not readable.

   The Lever 2 figure is a genuine failure and it is chosen, not missed:
   asked for on 16 September 2026, taking the literal hero match and product
   presence over the floor. It is the SAME exception already recorded for
   .lever-grid at ~5440, extended from two pages to three — the pill and the
   tag now fail identically, which is at least consistent.

   THE ONE-LINE FIX if the floor is enforced later: move the Lever 2 stop
   back to --cyan-900 (6.31:1 at the stop, clears the bar across the whole
   fade) and Lever 1 to --magenta-700 (7.80:1). That is the deep-chip rule
   at ~4750 — "full fade on surfaces, deep fade under text" — which this is
   a named departure from, not a repeal of. Swapping the ink instead does
   not work: --cyan-ink is 11.12:1 at the cyan stop but sits dark-on-dark at
   the blue end, which is the same dead end recorded at ~4740.

   The sRGB line is declared first as the fallback; browsers without oklch
   interpolation keep the same endpoints and only the pacing differs. */
body[data-theme="outcome-wc"] .grid-2 > .card:nth-child(1) .tag {
  background: linear-gradient(100deg, var(--blue-500) 0%, var(--magenta-500) 100%);
  background: linear-gradient(100deg in oklch, var(--blue-500) 0%, var(--magenta-500) 100%);
  color: #fff;
}
body[data-theme="outcome-wc"] .grid-2 > .card:nth-child(2) .tag {
  background: linear-gradient(100deg, var(--blue-500) 0%, var(--cyan-500) 100%);
  background: linear-gradient(100deg in oklch, var(--blue-500) 0%, var(--cyan-500) 100%);
  color: #fff;
}

/* ============================================================
   THEMED HEROES — NO TOP STRIPE
   body[data-theme] .page-hero
   2026-09-16
   ============================================================ */
/* The 4px accent stripe above the hero wash is removed from every themed
   page: flow.html, pace.html, combined.html, outcome-working-capital.html
   and outcome-ebitda.html. The hero wash now meets the nav directly.

   THIS IS EVERY STRIPE ON THE SITE. Only a themed body ever drew one, and
   those five pages are the complete set of themed bodies, so no page keeps
   it. globalfinex-design-system.html is untouched — its body carries only
   .ds-body, and its data-theme mentions at ~473 and ~506 are prose.

   WHY ONE OVERRIDE RATHER THAN DELETING THE SOURCE RULES. The stripe is
   declared three times and the winner differs by page: the base at ~425,
   the shared block at ~2106 (lever-method, lever-timing, outcome-wc,
   outcome-ebitda) and combined's own at ~3679. One rule at the end of the
   sheet retires all three without disturbing the hero backgrounds those
   same blocks also set. Deleting the declarations in place is the tidier
   end state if the stripe is never coming back.

   Specificity is (0,2,1), equal to the most specific of them, so position
   at the end of the sheet is what carries it. Keep it last. */



/* ============================================================
   ICON TILES REMOVED  .pc-icon .tb-icon .arch-icon
   2026-09-16
   ============================================================ */
/* The 37 icons are three-colour SVGs on transparent, and the tile existed
   to give them a surface. They read fine unaided on every background they
   currently sit on — all four contexts are light. .g-icon already had no
   tile; this brings the other four to it.

   Each width is the tile's old CONTENT box, so the icons render at exactly
   the size they do now and no row reflows: border-box means content =
   width - 2*padding - 2*border, e.g. .tb-icon 46 - 18 - 2 = 26.

   Restating the variant selectors is deliberate. Nine earlier rules set
   these backgrounds at up to (0,3,0) — .persona-card[data-outcome=...],
   .arch-col-buyer .arch-card, the .section-cool pair — and a bare
   .pc-icon reset would lose to all of them. */
.pc-icon, .tb-icon, .arch-icon {
  background: none; border: 0; padding: 0; border-radius: 0;
}
.persona-card .pc-icon,
.persona-card[data-outcome="working-capital"] .pc-icon,
.persona-card[data-outcome="ebitda"] .pc-icon {
  background: none; border: 0; padding: 0; border-radius: 0;
  width: 34px; height: 34px;
}
.trust-strip .tb-icon,
.section-cool .trust-strip .tb-icon {
  background: none; border: 0; padding: 0; border-radius: 0;
  width: 26px; height: 26px;
}
.arch-card .arch-icon,
.arch-card.is-gfx .arch-icon,
.arch-col-buyer .arch-card .arch-icon,
.arch-col-sup   .arch-card .arch-icon,
.arch-col-gfx   .arch-card .arch-icon {
  background: none; border: 0; padding: 0; border-radius: 0;
  width: 22px; height: 22px;
}

/* ============================================================
   EBITDA AND PACE — THE CARD TAGS OPEN ON SITE BLUE
   body[data-theme="outcome-ebitda"] .grid-2 > .card:nth-child(n) .tag
   body[data-theme="lever-timing"] #core .grid-sync .tag
   2026-09-16
   ============================================================ */
/* WHAT WAS WRONG. The last two pages whose tags carried no blue.

   EBITDA. Both tags in the "Both levers, through a P&L lens" grid were
   painted by body[data-theme="outcome-ebitda"] .tag at ~4811, keyed to the
   PAGE and not to the lever the tag labels. Both took the Pace chip ramp,
   so "Lever 1 · Method" wore Pace teal directly above a magenta Flow CTA.
   The same two faults as outcome-working-capital.html at ~5595, mirrored:
   there both tags went Flow magenta, here both went Pace teal. Note the
   card order is REVERSED against that page — Pace leads on an EBITDA page
   because Pace is the return lever — so nth-child(1) is Lever 2 and
   nth-child(2) is Lever 1. The ramps below are assigned to the LEVER, not
   to the position.

   PACE. The three core-card tags were painted by #core .grid-sync .tag at
   ~4037, a deep cyan-on-cyan chip with no blue in it at all. These are not
   lever-named tags — "Invoice-level", "Buyer-controlled", "Supplier-led" —
   but every one of them is a property of Pace, so all three take the
   Lever 2 ramp.

   THE RAMP. blue-500 -> magenta-500 and blue-500 -> cyan-500, 100deg in
   oklch — the same two ramps as .lever-grid .lever-tag on index.html and
   how-it-works.html at ~5519, and as the outcome-wc tags at ~5656. The
   lever pill and these tags are the same object at two sizes, now on five
   pages, and they read that way.

   SPECIFICITY. The Pace rule must carry #core: the rule it supersedes at
   ~4037 is (0,1,2,0) on an id, so a plain body[data-theme] .tag at (0,0,2,1)
   loses. body[data-theme="lever-timing"] #core .grid-sync .tag is (0,1,3,0)
   and wins. The EBITDA rules at (0,0,3,2) clear the ~4811 rule they
   supersede.

   SCOPE. data-theme="outcome-ebitda" is outcome-ebitda.html and nothing
   else; data-theme="lever-timing" is pace.html and nothing else.
   globalfinex-design-system.html matches a grep for both attributes but
   only as prose in its token table at ~504; its body carries .ds-body.
   flow.html shares the ~4037 #core rule and is NOT touched — it keeps its
   magenta override at ~4041. EBITDA has exactly two .tag elements and both
   sit in this grid; Pace has exactly three and all sit in #core.

   CONTRAST — AA EXCEPTION, DECLARED. .tag is 0.72rem (11.52px) at 600, so
   it is small text and the bar is 4.5:1. White on the ramps, measured
   across the oklch interpolation at 0.1% steps:

     Lever 1  blue-500 -> magenta-500   8.93:1 -> 4.42:1
              crosses 4.5:1 at 98% — the last 2% of the pill, past the end
              of the label at every width these pages render.
     Lever 2  blue-500 -> cyan-500      8.93:1 -> 1.47:1
              crosses 4.5:1 at 32%. Roughly two thirds of the label sits
              under the floor and the tail is not readable.

   The Lever 2 figure is a genuine failure and it is chosen, not missed:
   asked for on 16 September 2026, taking the hero match and product
   presence over the floor. It is the SAME exception recorded for
   .lever-grid at ~5440 and for outcome-wc at ~5644, now extended from
   three pages to five. Pace carries it three times on one page, which is
   the largest single concentration of it on the site.

   THE ONE-LINE FIX if the floor is enforced later: move the Lever 2 stops
   back to --cyan-900 (6.31:1 at the stop, clears the bar across the whole
   fade) and Lever 1 to --magenta-700 (7.80:1). Swapping the ink instead
   does not work: --cyan-ink is 11.12:1 at the cyan stop but sits dark-on-
   dark at the blue end — the dead end recorded at ~4740.

   The sRGB line is declared first as the fallback; browsers without oklch
   interpolation keep the same endpoints and only the pacing differs. */

/* EBITDA — card 1 is Lever 2 (Pace leads on this page), card 2 is Lever 1 */
body[data-theme="outcome-ebitda"] .grid-2 > .card:nth-child(1) .tag {
  background: linear-gradient(100deg, var(--blue-500) 0%, var(--cyan-500) 100%);
  background: linear-gradient(100deg in oklch, var(--blue-500) 0%, var(--cyan-500) 100%);
  color: #fff;
}
body[data-theme="outcome-ebitda"] .grid-2 > .card:nth-child(2) .tag {
  background: linear-gradient(100deg, var(--blue-500) 0%, var(--magenta-500) 100%);
  background: linear-gradient(100deg in oklch, var(--blue-500) 0%, var(--magenta-500) 100%);
  color: #fff;
}

/* PACE — all three core tags are Pace properties, so all three take Lever 2 */
body[data-theme="lever-timing"] #core .grid-sync .tag {
  background: linear-gradient(100deg, var(--blue-500) 0%, var(--cyan-500) 100%);
  background: linear-gradient(100deg in oklch, var(--blue-500) 0%, var(--cyan-500) 100%);
  color: #fff;
}

/* ---- ROUND 2026-09-16d: two soft sections are one band, not two ----
   white-paper.html is the only page on the site that runs two
   .section-soft blocks back to back: Opening, then What's in the paper.
   .section carries 96px top and bottom, so the two paddings met and put
   192px between Opening's last paragraph and the next eyebrow.

   Everywhere else that doubled gap marks a background change, which is
   what earns it. These two share --soft, so there is no seam to mark and
   the page read as one continuous band with a hole in the middle.

   padding-top drops to 0 and the gap is carried by the previous
   section's padding-bottom alone: 192 -> 96, the site's existing section
   number rather than a new one. Written as a general adjacency rule
   instead of a page scope — it matches nothing else today, and if the
   pattern recurs it should collapse there too.

   Reviewed against a tighter 56-64px, which would read as more obviously
   joined but introduces a spacing value the site does not otherwise use.
   Taken at 96 deliberately, to be looked at again rather than guessed. */
.section-soft + .section-soft { padding-top: 0; }


/* ---- ROUND 2026-09-16b: the alternatives category cards get their
   internal spacing back ----
   The eight cards in "Category by category" are row-synced with subgrid so
   the four rows line up across each pair. Subgrid inherits the parent's
   gutters, so the row-sync zeroes row-gap inside each card and forces
   margin-top: 0 on every child — and because display is overridden from
   flex to grid, the card's own gap: 14px never applied. The head, body,
   Strength/Limit list and footer sat flush, with only the footer's 10px
   pad separating anything.

   Spacing goes on the bottom of each row rather than the top: margin-top
   is forced to zero, and row-gap has to stay at zero for the rows to line
   up. Uniform values, so both cards in a row grow by the same amount and
   the alignment holds. The last row carries no bottom margin, leaving the
   card's 24px padding clean at the base.

   Below 880px the card reverts to display: block and loses the flex gap
   entirely — these margins are the only spacing it has there. */
.grid-sync.cat-grid > .cat-card > .cat-head { margin-bottom: 14px; }
.grid-sync.cat-grid > .cat-card > .cat-body { margin-bottom: 16px; }
.grid-sync.cat-grid > .cat-card > .cat-row  { margin-bottom: 18px; }
.cat-card .cat-row { gap: 10px 14px; }
.cat-card .cat-foot { padding-top: 16px; }


/* ---- ROUND 2026-09-16c: the supplier-side funding table reads as a table ----
   .alt-table already declared background: #fff, but it sits in a plain
   .section with no background of its own — white on white, with only a 1px
   --blue-200 border marking its edge. The band above it is section-soft, so
   the contrast made this one look unfinished.

   Zebra rows carry the fill instead of tinting the whole table, which keeps
   the highlighted GlobalFinex row as the only strongly coloured row.

   border-collapse also moves to separate. The rule at 1743 declares
   border-radius + overflow: hidden, but collapsed borders defeat
   border-radius in every major browser, so the corners have always rendered
   square. Nothing doubles up under `separate` because the cells carry a
   bottom border only, and border-spacing: 0 keeps the grid tight.

   Backgrounds go on the td, not the tr: a td background paints over its
   row's, so hover and the highlight have to be set at the same level as the
   stripes or they lose to them. Source order settles the three — stripe,
   then hover, then the highlight, which outranks both by class.

   Hover moves off --softer, which was the stripe colour: it would have been
   invisible on even rows and indistinguishable from a stripe on odd ones.

   Scoped to .alt-table alone. The shared rule at 1743 also serves
   .comp-table in for-ap.html, which had the same white-on-white problem.
   Round 16d below extends this treatment to it. */
.alt-table { border-collapse: separate; border-spacing: 0; }
.alt-table tbody tr:nth-child(even) td { background: var(--softer); }
.alt-table tbody tr:hover td { background: var(--soft); }
.alt-table tbody tr.alt-row-gf td { background: var(--gf-indigo-soft); }
.alt-table tbody tr.alt-row-gf .alt-name { color: var(--gf-blue); }


/* ---- ROUND 2026-09-16d: the AP stage table reads as a table ----
   Extends 16c to .comp-table. Same reasoning applies line for line:
   white-on-white in a plain .section, square corners from
   border-collapse: collapse defeating the radius at 1743, and a
   tr-level hover that a td-level stripe would outrank.

   The highlighted row is the pivot, not a product row: everything
   above "Liability confirmed" is unchanged, everything below is where
   the decision layer acts. The tag in that row already says so; the
   fill stops it reading as one more stage in a list.

   td:first-child carries the label weight that .alt-name gives the
   first column in alternatives.html, so for-ap's eight plain stage
   cells match without a span in each one. */
.comp-table { border-collapse: separate; border-spacing: 0; }
.comp-table tbody td:first-child { font-weight: 600; color: var(--ink); }
.comp-table tbody tr:nth-child(even) td { background: var(--softer); }
.comp-table tbody tr:hover td { background: var(--soft); }
.comp-table tbody tr.comp-row-gf td { background: var(--gf-indigo-soft); }
.comp-table tbody tr.comp-row-gf td:first-child { color: var(--gf-blue); font-weight: 700; }

/* ============================================================
   OUTCOME BANNER — THE EBITDA VARIANT
   2026-09-21
   ============================================================ */
/* outcome-ebitda.html's "The maths" banner was still the base treatment:
   a flat --gf-royal -> --gf-blue wash with the COLOURED pattern4 at 0.50
   running full-bleed under full-bleed copy. Two faults, the same pair the
   Flow banner had in 3040566 — it did not follow its own hero, and the
   artwork crossed every line of the lede.

   Same fix, this page's colours: the hero's cyan ramp, pattern4-white in
   its own right-hand column, and the copy capped so it has a column too.

   THE SCRIM IS NOT DECORATION HERE. Flow's banner needs none — its
   magenta ramp holds 9.44:1 under the copy unaided. Cyan is a far lighter
   endpoint and the same construction measured 5.09:1, which passes AA but
   with little margin on a page whose hero manages ~7. Adding the hero's
   own 95deg scrim takes it to 6.15:1. Measured across the copy column:

     4%   16.25:1      45%   7.12:1
     25%  12.12:1      50%   6.15:1   <- copy ends here
                       65%   4.08:1   <- artwork only, no text

   Past ~55% the wash falls under AA, exactly as it does on the hero. That
   region is artwork, not a text surface, and must not become one without
   re-measuring. If the lede ever grows past 62ch, re-measure first.

   Scoped to body[data-theme="outcome-ebitda"] rather than a class,
   because .outcome-highlight also renders on alternatives.html, which is
   unthemed, and on flow.html, which has its own .is-flow variant. */
body[data-theme="outcome-ebitda"] .outcome-highlight {
  background: linear-gradient(105deg,
    var(--blue-800) 0%, var(--blue-500) 34%,
    var(--cyan-700) 72%, var(--cyan-500) 100%);
  background: linear-gradient(105deg in oklab,
    var(--blue-800) 0%, var(--blue-500) 32%,
    var(--cyan-700) 70%, var(--cyan-500) 100%);
}
body[data-theme="outcome-ebitda"] .outcome-highlight::before {
  background-image: url('patterns/pattern4-white.svg');
  background-size: 38% auto;
  background-position: right center;
  background-repeat: no-repeat;
  opacity: 1;
  z-index: 0;
  /* 2026-09-22: px, not per cent. See the note on the collapse block. */
  -webkit-mask-image: linear-gradient(100deg, transparent 0, transparent 700px, rgba(0,0,0,0.30) 820px, #000 1010px);
  mask-image: linear-gradient(100deg, transparent 0, transparent 700px, rgba(0,0,0,0.30) 820px, #000 1010px);
}
/* Later sibling than ::before, so it lands over the artwork; the content
   sits at z-index 1 and clears both. */
body[data-theme="outcome-ebitda"] .outcome-highlight::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(95deg, rgba(0,0,0,0.28) 0%, rgba(0,0,0,0.10) 55%, rgba(0,0,0,0) 100%);
}
body[data-theme="outcome-ebitda"] .outcome-highlight h2 { max-width: 24ch; }
body[data-theme="outcome-ebitda"] .outcome-highlight p  { max-width: 62ch; }


/* ============================================================
   OUTCOME BANNER — THE ARTWORK COLUMN COLLAPSES BELOW 1000px
   2026-09-21, breakpoint moved 720 -> 1000 on 2026-09-22
   ============================================================
   Both banners in this branch — .outcome-highlight.is-flow and the
   outcome-ebitda variant — put the artwork in its own 38% right-hand
   column and cap the copy at 24ch / 62ch so it clears. The default is no
   longer one of them: it collapses at 1000px in its own branch below,
   because its column is 72% and thins out at a different width.

   THE 721-1010px BAND WAS BROKEN UNTIL 2026-09-22, AND THIS IS WHY THE
   BREAKPOINT MOVED FROM 720px TO 1000px. Both masks used to fade in at
   50% of the panel, picked to sit past the 62ch cap. But the cap's effect
   is a fixed px distance, not a percentage: the copy's right edge lands
   591px (Flow) and 594px (EBITDA) from the card's left edge at every
   width down to ~720px, which is half the panel at 1440 and 83% of it at
   768. So from 721px up to about 1010px the copy ran past the 50% stop
   and the artwork crossed it.

   WHAT THAT COST, white copy on the rendered background with the copy
   hidden, at the brightest point behind the copy column. These are the
   figures BEFORE the fix, and the first two are the reason this was not
   left for later:

              Flow           EBITDA
      768px    1.01:1         1.17:1     <- white text on white artwork
      900px    2.28:1         1.90:1
     1024px    8.77:1         4.03:1
     1440px    8.91:1         5.47:1

   The last words of the lede were sitting on pattern strokes running at
   opacity 1, which are near-white on any ground. Not a near miss.

   And the overlap itself, copy edge -> leftmost visible artwork,
   card-left-relative, each banner measured against a twin carrying
   `::before { display: none !important }`:

              Flow (is-flow)            EBITDA
      768px   591 -> 441   -150px      594 -> 441   -153px
      900px   591 -> 545    -46px      594 -> 523    -71px
      940px   591 -> 571    -20px      594 -> 548    -46px
     1000px   591 -> 610    +19px      594 -> 585     -9px
     1010px   591 -> 616    +25px      594 -> 591     -3px
     1024px   591 -> 625    +34px      594 -> 600     +6px
     1440px   591 -> 765   +174px      594 -> 734   +140px

   EBITDA cleared about 20px later than Flow because its artwork is
   pattern4-white, whose figure starts further left in its own box. That
   is why one breakpoint had to cover the later of the two.

   THE FIX IS THE SAME ONE THE DEFAULT TOOK: the fades are anchored at
   700px from the card's left edge instead of 50% of it, so they no longer
   move with the viewport, and this block's breakpoint moved to 1000px so
   the band where the column cannot fit becomes texture instead. After the
   change, artwork clears the copy by +68px (Flow) and +51px (EBITDA) at
   1024, and by +174px and +140px at 1440. Above 1000px the desktop render
   is all but unchanged: max channel delta 36/255 on Flow and 24/255 on
   EBITDA, on the faintest left edge of the artwork only.

   ONE FAILURE IS NOT FIXED BY THIS AND IS NOT THE ARTWORK'S FAULT. On the
   EBITDA banner the wash itself puts white copy on bright cyan once the
   copy runs past ~55% of the panel, which it does at every width below
   about 1200px. Background under the copy measures 2.19:1 at 768, 2.95:1
   at 900, 3.44:1 at 1000 and 4.03:1 at 1024 - all under the 4.5:1 floor,
   with the artwork already out of the way. The variant's own note above
   says it: "Past ~55% the wash falls under AA... That region is artwork,
   not a text surface, and must not become one without re-measuring." At
   tablet widths it became one. Fixing it means changing that wash or
   extending its 95deg scrim, which is a visual-identity decision on a
   product page rather than a defect fix, so it is recorded here and
   raised rather than taken unilaterally. Flow does not have this problem:
   its wash holds 5.74:1 under the copy across the same band.

   WHY THERE IS A BREAKPOINT AT ALL, from the original 2026-09-21 note:
   the 24ch / 62ch caps are what create the clear zone, and below about
   700px they stop binding, because the copy column is narrower than 62ch
   already. The copy then runs full-bleed and the artwork crosses four
   lines of the lede. That note put it as "without the caps there is no
   clear zone" — true, and not fixable by a cap at that width.

   There is no room for two columns down there, so the artwork stops being
   a column and becomes a texture: full-bleed, mask off, opacity down to
   the 0.18 the swirl-muted heroes use. Chosen on review over dropping the
   pattern to wash-only, which is what the themed page heroes do at this
   breakpoint; the texture keeps the brand artwork on the banner and the
   legibility cost at 0.18 was accepted.

   The caps are deliberately left in place. They do nothing below the
   breakpoint and resume their job as the viewport grows back past it. */
/* ALL THREE BANNERS COLLAPSE HERE, on one rule. The default carried its
   own 1000px block for a few hours on 2026-09-22, written while the two
   variants were still on 720px; once they moved here too the two blocks
   were identical and are now one. `.outcome-highlight::before` alone
   would not have been enough to reach the variants anyway - it scores
   0,1,1 against their 0,2,1 - which is why all three are named.

   For the default, the column past its 700px fade is 484px at 1440, 344px
   at 1100 and 244px at 1000; for the two variants at 38% it is narrower
   still. Below 1000px none of them has room, so all three drop the mask
   and run the artwork full-bleed at 0.18.

   Both of the default's mask layers have to go, not just the horizontal
   one, or its vertical feather would keep cutting the texture off at the
   top and bottom of the card. `mask-composite: intersect` is left alone
   deliberately: with `mask-image: none` there is nothing to composite and
   it has no effect. Checked, because it does not read that way.

   THE TEXTURE DOES CROSS THE COPY, and at this width that is unavoidable:
   there is no room for two columns, so either the artwork sits under the
   text or it goes away entirely. The 2026-09-21 decision chose the
   texture over dropping to wash-only, and this keeps it.

   MEASURED, worst background anywhere under the copy column, texture on,
   copy hidden. All three banners, all four texture widths, one method:

              default      Flow       EBITDA
      390px    6.21:1      5.75:1     2.69:1
      768px    6.17:1      5.75:1     2.19:1
      900px    6.52:1      5.74:1     2.95:1
     1000px    6.59:1      5.74:1     3.44:1

   The default and Flow clear the 4.5:1 floor, neither comfortably; 0.18
   is the ceiling for this pattern, not a setting. Do not raise it, and
   re-measure before anything brightens these washes.

   An earlier version of this note put the default at 4.78-4.99:1 here.
   Those figures were taken across the WHOLE card, including the bright
   right-hand end of the wash where no copy sits, so they measured a
   region that is not a text surface. The figures above are the copy
   column only, which is the one that matters.

   EBITDA DOES NOT CLEAR IT, and the texture is not what fails: its wash
   is. See the note above this block. */
@media (max-width: 1000px) {
  .outcome-highlight::before,
  .outcome-highlight.is-flow::before,
  body[data-theme="outcome-ebitda"] .outcome-highlight::before {
    background-size: cover;
    background-position: center;
    opacity: 0.18;
    -webkit-mask-image: none;
    mask-image: none;
  }
}


/* ============================================================
   TRUSTED-BY LOGO STRIP
   ============================================================
   Customer logos on about-b2be-group.html, replacing the placeholder that
   specified "monochrome, evenly spaced grid, neutral grey on light
   background". Ten marks, five across, collapsing to three then two.

   The monochrome treatment is baked into the component rather than sitting
   behind a modifier, because there is one logo strip on the site and the
   brief is monochrome. A future colour strip overrides `filter`.

   KNOWN LIMIT of grayscale: it preserves lightness, so a pale mark stays
   pale. Signify and HarperCollins therefore sit lighter than 3M or Assa
   Abloy. The even-weight alternative is `filter: brightness(0)`, which
   crushes every mark to one flat grey regardless of source colour — but it
   turns a knockout-on-block logo into a solid rectangle, which is worse for
   Rexel and Visy. Grayscale chosen on review, 21 September 2026, with the
   fade accepted. Per-logo opacity nudges are the fix if it grates.

   Logos are sized by height, not width, because the supplied artwork has no
   common bounding convention. A square mark reads heavier than a wide
   wordmark at equal height, hence the two correction classes. */
.logo-strip {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 40px 48px;
  align-items: center;
  justify-items: center;
}
.logo-strip li {
  display: flex; align-items: center; justify-content: center;
  width: 100%; min-height: 56px;
}
.logo-strip img {
  display: block;
  width: auto; height: auto;
  max-width: 100%;
  max-height: 40px;
  filter: grayscale(1) contrast(0.85);
  opacity: 0.58;
}
.logo-strip img[data-ratio="square"] { max-height: 52px; }
.logo-strip img[data-ratio="wide"]   { max-height: 30px; }
/* A mark reversed out of a filled block reads smaller than its bounding box
   suggests, because the block itself is not the logo. Visy and Rexel get a
   little more height so their wordmarks match the free-standing ones. */
.logo-strip img[data-ratio="block"]  { max-height: 48px; }
/* Dulux's artwork carries the swoosh above the wordmark, so half its height
   is illustration. Sized up so the word reads at the same weight as the rest. */
.logo-strip img[data-ratio="padded"] { max-height: 58px; }

@media (max-width: 900px) {
  .logo-strip { grid-template-columns: repeat(3, 1fr); gap: 32px; }
}
@media (max-width: 560px) {
  .logo-strip { grid-template-columns: repeat(2, 1fr); gap: 28px 24px; }
}

/* ============================================================
   TRUST STRIP ON MOBILE
   2026-09-22
   ============================================================ */
/* Below 540 the strip was a single column with a 16px gap and no other
   change, so four discrete credentials read as one undifferentiated
   block. It becomes a divided list instead: hairlines separate the
   claims, and the icon top-aligns to the name so the ladder holds when
   a description wraps, which it does at 360 and below. Side padding
   drops 28 to 20 to buy back the 16px that keeps "ANZ, Asia, UK,
   Europe, North America" on one line at 360.

   The .section-cool divider is for completeness. No page puts the strip
   on a navy band today, but the design system documents that variant and
   a --blue-100 hairline would vanish on it. */
@media (max-width: 540px) {
  .trust-strip { grid-template-columns: 1fr; gap: 0; padding: 8px 20px; }
  .trust-badge {
    align-items: flex-start;
    gap: 12px;
    padding: 16px 0;
    border-top: 1px solid var(--blue-100);
  }
  .trust-badge:first-child { border-top: 0; }
  .section-cool .trust-badge { border-top-color: rgba(255,255,255,0.12); }
  .trust-strip .tb-icon { margin-top: 2px; }
  .tb-name { font-size: 1rem; }
  .tb-desc { margin-top: 2px; }
}

/* ============================================================
   404 HERO
   2026-10-01
   ============================================================ */
/* The 404 artwork is pattern8's own band drawn as "404"
   (patterns/pattern8-404.svg), so the usual pattern1 swirl and its
   vignette come off: two line patterns in one hero compete. Copy sits
   left and the artwork right; under 860 the artwork stacks above the
   copy, capped at 320 so the heading stays in the first screen. */
.page-hero--404::before { display: none; }
.page-hero--404::after { background: none; }
.page-hero--404 .not-found-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: 48px;
  align-items: center;
}
.page-hero--404 .not-found-art img { display: block; width: 100%; height: auto; }
@media (max-width: 860px) {
  .page-hero--404 .not-found-grid { grid-template-columns: 1fr; gap: 32px; }
  .page-hero--404 .not-found-art { order: -1; max-width: 320px; }
}
