/*
    CAF — site stylesheet.

    Replication of the existing design, written against the markup this project emits. Every value here
    is measured from the live sites with `dotnet run -- --theme-report`; re-run it to check them.

    Why this is written rather than taken: Divi keeps the design in the WordPress database and emits it
    as CSS at render time. Their framework stylesheet is 824,698 bytes written against `.et_pb_*` markup
    that nothing here emits, and the per-page half is keyed to positional module ids (92 on one page).
    Their own child stylesheet is 16-18 KB of !important patches that `@import`s Divi's. So the design
    transfers; the code cannot.

    What IS reused: their layouts (the footer is theirs, converted), their class hooks, their palette,
    their typefaces, and their assets.

    The figures this comment used to carry were retracted twice and are corrected here rather than
    repeated: it said "22 of the 65 their stylesheet targets" and "55 of America's 154 child-theme
    rules", and both were wrong. The rule parser could not read inside @media, so the applicable
    totals are 64 on America and 59 on Canada; and the count was taken against the export rather than
    against pages we serve, which is a different question. Measured from the running site after the
    hooks were carried from all four levels: 51 of 64 land on America and 39 of 59 on Canada, and
    22 of 22 shared hooks reach our DOM on America, 19 of 19 on Canada. None of them was adopted -
    the design QA pass found that even the rules that land were written for Divi's row and arrive on
    our section one level above the grid they were meant to lay out.
    See .claude/guides/front-end.md; re-measure with `dotnet run -- --theme-report --rules`.

    Layered: tokens, then base, then layout, then one block per widget family, then the preserved hooks.
*/

/*
    Breakpoints are literals on purpose: a media condition cannot read a custom property and this
    project has no CSS build step, so the two values are written out and declared here instead.
    Both are Divi's own, which is what makes them the right ones to match rather than invent:

      981px - its tablet/desktop boundary, where a migrated column grid re-forms
      768px - its phone boundary, above which a card or a listing row can sit side by side

    EACH IS WRITTEN ONE WAY, and on 3 October 2026 (decision 163) neither was. A boundary needs two
    non-overlapping spellings and this file had five: 981/980 was consistent, but the phone boundary
    appeared as min-width 768, min-width 769, max-width 767 AND max-width 768, so two rules both
    applied at exactly 768px and a third applied at neither. The spellings are now, and only:

      @media (min-width: 981px)   /  @media (max-width: 980px)
      @media (min-width: 769px)   /  @media (max-width: 768px)

    Two undeclared tiers went at the same time. A 480px tier set table-cell and popup padding, and 480
    measures nothing on either site - those fold into the phone boundary. A 1024px tier re-formed the
    listing grid's columns, and a grid changing its column count is layout, which re-forms at 981
    everywhere else here.

    ONE EXCEPTION SURVIVES AND IS NOT AN OVERSIGHT: the client's own footer keeps max-width 1024px,
    because the width it releases is theirs rather than ours. Its own comment says so.

    There used to be a third breakpoint, 45rem, used by the card and listing blocks alone. It was not a
    measurement of anything - it disagreed with Divi's phone boundary by 48px and with nothing on
    either live site - so it is gone.
*/

/* ---------------------------------------------------------------- tokens */

:root {
    /* Measured from their own child stylesheet, which is the unambiguous statement of the brand:
       #ff3b21 x10 and #0d393b x6 on America, x12 and x6 on Canada. The page-wide counts are noisier -
       Divi's default blue and a plugin's Bootstrap blue outrank both on Canada. */
    --caf-orange: #ff3b21;
    --caf-orange-pale: #ffcec7;
    --caf-teal: #0d393b;
    --caf-teal-dark: #0b2d2e;

    /* NEVER PAINT A BACKGROUND WITH var(--caf-teal). Five rules redefine it to the paper colour to
       lighten text on a dark ground - .caf-section--on-dark, .caf-hero, .caf-tinted--on-dark,
       .darkGreenBox and the article's dark page header - and every element that WANTS a teal
       background is, by construction, one of those same elements. So the token resolves to white
       exactly where it is asked to paint teal, and the band comes out white under white text.
       .darkGreenBox's own comment has said this since it was written; a scripted substitution of
       #0d393b -> var(--caf-teal) on 3 October 2026 did it anyway, in all three places, and
       --visual-sweep caught all three as same-colour findings on /contact, /finance, /give-now and
       /what-we-do. Write the hex, or use --caf-teal-dark, which nothing redefines. */

    /* THE BRAND DOCUMENT NAMES FIVE COLOURS AND THIS FILE HAD THREE OF THEM - decision 163,
       3 October 2026. docs/CAFA_Brand_Quick_Reference_3.19.24.pdf:

           DEEP GREEN #0d393b   ORANGE #ff3b21   LILAC #d2c1dd   KHAKI #ad894f   BLACK #000000

       --caf-teal IS Deep Green. The token was named from the measurement before the document existed
       and is deliberately NOT renamed: 40 uses plus --caf-teal-dark, .caf-section--on-dark and a dozen
       class names, and a visitor sees no difference either way. The brand name goes where a human
       reads it, which is SectionColorOptionsProvider's drop-down.

       The document's distribution rule - "Green should be predominant colour on a page. Orange and
       Khaki are used only to highlight." - was checked rather than assumed and it already holds: of
       --caf-orange's 39 uses, 26 are a hover colour, a focus outline or an accent border, and the 13
       backgrounds are buttons and badges. NOTHING PAINTS A BAND IN ORANGE. Read that before adding
       one.

       Lilac is declared because migrated sections are painted with it and it had no token. Khaki is
       declared because the document lists it as a highlight and this file had none that was not
       orange. Black is --caf-ink already. */
    --caf-lilac: #d2c1dd;
    --caf-khaki: #ad894f;

    /* From the rendered design CSS: #fcfcfc x18, #0d0d0d x15, #464646 x8 on the America home page. */
    --caf-paper: #fcfcfc;
    --caf-paper-alt: #f5f5f4;
    --caf-ink: #0d0d0d;
    --caf-ink-muted: #464646;
    --caf-rule: #d8d8d8;

    /* The muted ink on a dark ground. It was #dcdcdc written out at FIVE separate sites and declared
       nowhere - an undeclared sixth ink, which is the one colour in this file no comment could tell you
       about. Named on 3 October 2026 (decision 163); the five sites reference it now. */
    --caf-ink-muted-on-dark: #dcdcdc;

    /* A FIELD KEEPS ITS OWN INK, AND THAT IS WHAT THESE THREE ARE FOR.

       --caf-ink is remapped to the paper colour in FIVE places - .caf-section--on-dark and its grid and
       column siblings, .caf-page-hero, .caf-tinted--on-dark, .darkGreenBox, and the article's dark page
       header - so that TEXT lightens on a dark ground. A text input is not text on the ground: it
       paints its own near-white field and then took the lightened ink onto it, which is #fcfcfc on
       #fcfcfc. THAT SHIPPED. The search box on /give-now sits in a section whose gradient ends #0d393b,
       so everything typed into it was invisible in every engine, and the placeholder was invisible in
       Firefox and nearly so in Chrome, which paints its own darkgray instead of inheriting. 302 more
       sections are painted #0d393b, so it was one editor action away from every form on the site.

       Re-darkening the fields inside each on-dark scope is the move .caf-section--on-dark's own comment
       forbids: a rule that lists the elements will one day miss one. So this is the other half of that
       rule rather than an exception to it - an ink and a paper the dark scopes do not capture, because
       a field's ground never changes.

       THEY READ THE ROOT VALUES THROUGH var() DELIBERATELY. A custom property's var() is substituted
       where the property is DECLARED, so these resolve here, at :root, where --caf-ink is still
       #0d0d0d - and they inherit that substituted value into a scope that has remapped --caf-ink.
       Retyping the hexes renders identically and is the desync this file already carries once, in the
       split page header's four retyped tokens. */
    --caf-field-ink: var(--caf-ink);
    --caf-field-ink-muted: var(--caf-ink-muted);
    --caf-field-paper: var(--caf-paper);

    /* THE SAME MECHANISM FOR A WHOLE PANEL RATHER THAN ONE FIELD, added 16 October 2026 with decision
       205. The charity results - facet rail, cards, pager - used to render on /search, a controller
       view that no on-dark scope can reach. They render inside a Page Builder widget now, and the one
       page that carries that widget puts it in .caf-section__grid--on-dark over the brand-split
       gradient, which lightens --caf-ink, --caf-ink-muted, --caf-teal, --caf-link and --caf-paper-alt
       so that TEXT stays legible on a dark ground.

       A panel is not text on the ground. It paints its own light grounds - a white facet head, a teal
       pager bar, white cards - and inside that scope it was taking the lightened ink onto them: white
       on white, and a pager strip with white text on white. The field exemption above is the same
       defect one token wide; this is it a component wide.

       Read through var() at :root for the reason given above: substitution happens where the property
       is DECLARED, so these resolve to the root values and carry them into a scope that has remapped
       the originals. Retyping the hexes renders identically today and desyncs the first time the
       palette moves. */
    --caf-panel-ink: var(--caf-ink);
    --caf-panel-ink-muted: var(--caf-ink-muted);
    --caf-panel-teal: var(--caf-teal);
    --caf-panel-link: var(--caf-link);
    --caf-panel-paper-alt: var(--caf-paper-alt);

    /* Outfit is the site's HEADING and interface face - 88 declarations on America, 58 on Canada.
       Source Serif 4, at 98 declarations, is the BODY face: this file called it "the secondary
       rather than an accent" and then referenced it from no rule at all, so every paragraph on both
       channels rendered in Outfit while both live sites set them in serif. Checked against
       cafamerica.org/advisers-report and /news-insights before wiring it up - the headings there are
       sans and the paragraphs under them are unmistakably serif. A declared token that no rule uses
       is the same failure as a dormant rule, and it shipped 40KB of font to prove it.
       Both are self-hosted from Google's own files: openly licensed, and no third-party request. */
    --caf-font: "Outfit", system-ui, -apple-system, "Segoe UI", sans-serif;
    --caf-font-serif: "Source Serif 4", Georgia, serif;

    /*
       17px is the base, and this read 16px until 12 September 2026 for the same reason the container
       read 1080px: a FREQUENCY COUNT over everything the page loads is a count of the framework, not
       a reading of the design. "46 declarations at 16px against 21 at 14px and 19 at 18px" is what
       --theme-report's type scale says, and what the sites themselves declare is a bare

           p { font-size: 17px }

       in their own CSS, on both channels. Measured on the rendered pages rather than argued from the
       count: 15 of the 16 paragraphs on cafamerica.org/alert/afghanistan-ofac and all 8 on
       cafcanada.ca/story/making-cross-cultural-connections-in-mexico compute 17px, and ours computed
       16px on the same article.

       The line height corroborates it and is why this is a change rather than a guess: both live
       pages compute line-height 27.2px, which is 1.6 x 17 exactly - the ratio --caf-line already
       carries. At 16px ours computed 25.6px, so the leading was wrong by the same 6% as the type.

       1.0625rem rather than 17px so a visitor who has changed their browser's text size still gets it.
    */
    --caf-text: 1.0625rem;
    --caf-text-small: 0.875rem;
    --caf-text-lead: 1.125rem;

    /* The heading scale, counted across the America export's own authored font sizes (excluding the
       _phone and _tablet variants, which are overrides rather than the scale): 28px x227, 20px x125,
       25px x95, 50px x69, 16px x47, 44px x46, 34px x46, 18px x46, 26px x46, 24px x37, 54px x33.

       So the display size is 50px - the size every one of the 69 hero titles declares - and the modal
       heading is 28px. These were literals until now, and two of them were guesses that measured
       wrong: h1 read 40px against a 43-55px cluster, and h2 read 32px against the commonest heading
       on either site. Tokens rather than literals so the hero can name the display size rather than
       reinvent it in a clamp. */
    --caf-text-display: 3.125rem;

    /*
       h1 and h2 are the third value in this file counted from the wrong thing, and h2 was half the
       size it should be on every page of both channels.

       The scale below was counted from the export's AUTHORED font sizes - what Divi writes onto
       individual modules - which is a different question from what an h2 IS. --theme-report now reads
       the sites' own declarations for bare h1…h5:

           cafamerica   h1 54px  h2 54px  h3 25px  h4 22px  h5 28px
           cafcanada    h1 54px  h2 46px  h3 39px  h4 32px  h5 28px

       Confirmed on a matched pair rather than in aggregate - cafamerica.org/what-we-do and ours, the
       same page and the same headings: "Who We Serve" and "OUR SERVICES" render H2 54px there and
       H2 28px here, while "Individuals & Families" is H3 23px against our 24px and "Give Anywhere,
       Safely" is H5 16px uppercase on both. SO h3, h4 AND h5 ARE LEFT ALONE: they already match what
       the pages render, and the two channels' declared values for them disagree too much to reconcile
       (h3 is 25px on America and 39px on Canada).

       h1 is 54px because both sites declare 54px - the one figure they agree on. h2 is 48px, between
       America's 54 and Canada's 46, because this stylesheet serves both channels and the design system
       applies one treatment; it is 6px off each rather than exact on one.

       The CASE is deliberately not carried. Both h2s on /what-we-do are uppercase, both on /contact
       are, and only one of four on /how-we-work is - so it is a per-module setting rather than a rule,
       unlike the article title, which is uppercase on 2 of 2 across both channels.
    */
    --caf-text-h1: 3.375rem;
    --caf-text-h2: 3rem;
    --caf-text-h3: 1.5rem;
    --caf-text-h4: 1.25rem;
    --caf-text-h5: 1rem;

    /* The body link colour, measured on both live sites and deliberately not --caf-orange. The reason
       for both, and for why this is declared here rather than on .fr-view, is with the .fr-view a rule
       that reads it. */
    --caf-link: #d14508;

    --caf-line-tight: 1.2;
    --caf-line: 1.6;

    /* One duration for the colour changes this site makes on hover and focus. Nothing here animates
       position or size - there is no motion on either live site to reproduce - so this is the whole of
       the motion vocabulary, and it is honoured only where the visitor has not asked for less. */
    --caf-transition: 160ms ease;

    /*
       The live content container, and THIS NUMBER WAS WRONG ON EVERY PAGE OF BOTH CHANNELS until
       12 September 2026. It read 1080px, which is `.et_pb_row{width:80%;max-width:1080px}` in
       style-static.min.css - DIVI'S FRAMEWORK DEFAULT, not this client's setting. Both sites
       override it in their own generated stylesheet, `et-core-unified-tb-*.min.css`:

           .container, .et_pb_row, ... { max-width: 1300px }

       Measured on the rendered pages rather than read out of a file, at innerWidth 1536: every
       row on cafamerica.org/what-we-do and cafcanada.ca/what-we-do computes max-width 1300px and
       renders 1217px, which is the 80%; ours rendered 1080px on all 17 grids of the same page.
       137px narrower, everywhere.

       THE SWEEP COULD NOT HAVE FOUND IT, and the reason is worth keeping: at 80% the cap only binds
       above a ~1625px viewport, so below about 1350px the two are IDENTICAL - at 1200px both are
       960px. --visual-sweep runs at 375px and 1200px, which are precisely the two widths where this
       defect does not exist. It was found by measuring the live page beside ours at a desktop width.
    */
    --caf-container: 1300px;

    /*
       Rows that opt out of the cap: 166 on America and 91 on Canada set max_width="1600px", and the
       footer rows set it in the layout itself. Worth knowing before reaching for it: a 1600px row is
       INDISTINGUISHABLE from a 1300px one below a ~1625px viewport, because 80% binds first on both.
       On a 1920 screen it is 1536px against 1300px, which is where the difference lives.
    */
    --caf-container-wide: 1600px;

    /* Divi's gutter 3 leaves 5.5% between columns (.et_pb_column_1_2{width:47.25%}). */
    --caf-gutter: 5.5%;
    --caf-space-small: 0.75rem;
    --caf-space: 1.5rem;
    --caf-space-large: 2.5rem;

    /*
       THE HEADER BAND, AND IT IS THE STYLESHEET'S NUMBER RATHER THAN THE EXPORT'S. The height used
       to come from the logo: whatever max_height the export put on that one <img>, which was 65px on
       America and 60px plus 10px of padding on Canada. So the two channels' headers stood at 65 and
       80, the mark was the full height of its own band with nothing around it, and the band could be
       changed only by editing a generated partial.

       80px for both. It is Canada's existing height, so one channel does not move at all, and it
       gives America's mark 18px of air where it had none. front-end.md's standing instruction is
       that we reproduce the layout rather than the measurement, and the 65px this replaces was
       measured off live before that instruction existed.
    */
    --caf-header-height: 5rem;
}

/* ---------------------------------------------------------------- fonts */

/*
    Variable fonts, latin subset, self-hosted. Taken from Google's own files rather than from the
    client's server: both are openly licensed (SIL OFL) and Google is where the live sites load them
    from anyway. Divi's own ETmodules icon font is deliberately NOT here - it is Elegant Themes'
    artwork, which is also why the social links render a label rather than a glyph.

    The latin subset covers French: é, à, ç and œ are all inside U+0000-00FF plus U+0152-0153.
*/
@font-face {
    font-family: "Outfit";
    src: url("/fonts/outfit-latin.woff2") format("woff2");
    font-weight: 100 900;
    font-display: swap;
}

@font-face {
    font-family: "Source Serif 4";
    src: url("/fonts/source-serif-4-latin.woff2") format("woff2");
    font-weight: 200 900;
    font-display: swap;
}

/* ---------------------------------------------------------------- base */

*,
*::before,
*::after {
    box-sizing: border-box;
}

body {
    margin: 0;
    /*
       THE FOOTER SITS AT THE BOTTOM OF A SHORT PAGE. Without this the page simply ends where its
       content ends, so /search with no query - 991px of document in a 1100px window, measured
       3 October 2026 - drew the teal footer and then the page ground below it. That is the same
       complaint as the 24px strip .caf-footer__section fixes, arriving by a different route, and the
       two are easy to mistake for each other: one is a margin escaping and shows on EVERY page, this
       one is a document shorter than the viewport and shows only on the few short ones.

       svh rather than vh so a phone's collapsing address bar does not make the page taller than the
       screen and introduce a scroll on a page that has nothing to scroll.

       The children this adds a flex context to are the skip link, the header, main, the footer and
       the popups. The skip link is position: absolute and the popups are <dialog> elements that are
       display: none until .showModal() puts them in the top layer, so none of the three is in flow
       and none of them is affected. The header's position: sticky is unaffected too - it resolves
       against the viewport, not against this container.
    */
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    font-family: var(--caf-font);
    font-size: var(--caf-text);
    line-height: var(--caf-line);
    color: var(--caf-ink);
    background: var(--caf-paper);
}

h1,
h2,
h3,
h4,
h5,
h6 {
    font-family: var(--caf-font);
    color: var(--caf-teal);
    line-height: var(--caf-line-tight);
    margin: 0 0 0.6em;
}

/*
    HEADLINES ARE ALL CAPS, because the brand document says so in those words - "MAAX Bold.
    Headlines. Always used in ALL CAPS." - decision 163, 3 October 2026.

    This replaces the argument at --caf-text-h1 above, which was that the case is a per-module setting
    because both h2s on /what-we-do are uppercase, both on /contact are, and only one of four on
    /how-we-work is. That was a sound reading of THE LIVE PAGES and the wrong question: a Divi author
    setting caps per module is the absence of a rule, not evidence against one, and the document
    supplies the rule. It is the same failure as the three frequency counts this file records - the
    container, the body size and the h2 - asking the markup what the design is.

    h3 and h4 stay sentence case. They are in-body sub-headings, and the document's word for a
    sub-headline is "typically", not "always". h5 already uppercased, four hundred lines of this file
    ago, for its own measured reason.

    THREE RULES BECOME REDUNDANT HERE AND ARE GONE RATHER THAN LEFT AGREEING: .caf-body__title and
    .caf-hero__title are both h1 elements - _Body.*.CAF.Article.cshtml and _PageHero.cshtml - and
    .topBannerQuote h5 restated the global h5 rule it already inherits.
*/
h1 { font-size: var(--caf-text-h1); text-transform: uppercase; }
h2 { font-size: var(--caf-text-h2); text-transform: uppercase; }
h3 { font-size: var(--caf-text-h3); }
h4 { font-size: var(--caf-text-h4); }

/*
    A MIGRATED HEADING BRINGS ITS OWN SIZE, BECAUSE THE TAG DOES NOT GIVE IT ONE IN DIVI.

    352 of the 395 et_pb_heading modules across the two exports declare title_font_size, and it does not
    follow title_level: /give-now draws four card titles as h1 at 25px beside a section title that is h2
    at 54px. The scale above is keyed to the tag, so it got both of those wrong in opposite directions -
    the cards rendered at 54px and wrapped to three lines.

    THE CLAMP IS BUILT HERE RATHER THAN WRITTEN INLINE, and that is a platform constraint rather than a
    preference. Xperience's rich text widget sanitises inline CSS at render and drops a declaration
    whose value it does not accept - per declaration, silently. Measured: a heading stored with
    `font-size: clamp(2rem, 5.4vw, 3.375rem)` served with its text-align and text-transform intact and
    no font-size at all, while a sibling heading's bare `1.5625rem` came through. Custom properties are
    NOT sanitised - the url() that text-module pictures travel on proves it - so the three numbers cross
    as custom properties and the function lives here. DiviWidgetMapper.TryReadHeadingSize has the rest.

    A heading that declares nothing falls back to the scale above, three times over, so the clamp
    collapses to exactly the size it had. A heading with no smaller phone size gets min == max, which
    collapses the same way.
*/
.fr-view h1 { font-size: clamp(var(--caf-heading-min, var(--caf-text-h1)), var(--caf-heading-vw, var(--caf-text-h1)), var(--caf-heading-max, var(--caf-text-h1))); }
.fr-view h2 { font-size: clamp(var(--caf-heading-min, var(--caf-text-h2)), var(--caf-heading-vw, var(--caf-text-h2)), var(--caf-heading-max, var(--caf-text-h2))); }
.fr-view h3 { font-size: clamp(var(--caf-heading-min, var(--caf-text-h3)), var(--caf-heading-vw, var(--caf-text-h3)), var(--caf-heading-max, var(--caf-text-h3))); }
.fr-view h4 { font-size: clamp(var(--caf-heading-min, var(--caf-text-h4)), var(--caf-heading-vw, var(--caf-text-h4)), var(--caf-heading-max, var(--caf-text-h4))); }
.fr-view h5 { font-size: clamp(var(--caf-heading-min, var(--caf-text-h5)), var(--caf-heading-vw, var(--caf-text-h5)), var(--caf-heading-max, var(--caf-text-h5))); }
.fr-view h6 { font-size: clamp(var(--caf-heading-min, var(--caf-text-small)), var(--caf-heading-vw, var(--caf-text-small)), var(--caf-heading-max, var(--caf-text-small))); }

/*
    THE NAMED HEADING TREATMENTS - 4 October 2026, decision 172 phase 3.

    These replace 57 raw CSS declarations that widgets wrote straight into a style attribute, each one
    setting the three --caf-heading-* custom properties the six rules above read. That is a per-page
    measurement sitting on top of the type scale, and it was invisible to the editor who had to live
    with it - "no one will know they are there", which is the complaint that started this.

    Eight measured steps became three. The maxima clustered: 1.625rem x25 and 1.8125rem x3; 2.5rem x8,
    2.6875rem x2 and 2.8125rem x4; 3.375rem x7. Seventeen headings move by 2-3px at the widest clamp
    and forty do not move at all. --display is --caf-text-h1 exactly, which is the measurement agreeing
    with the design system rather than departing from it.

    Declared twice on purpose. A bare class is 0,1,0 and .fr-view h2 is 0,1,1, so the element rule
    would win inside a rich text block - which is exactly where these headings render once a treatment
    is set. The .fr-view-qualified form is 0,2,0 and takes it back.

    No uppercase treatment, deliberately: of the 22 values that forced it, 13 sat on an h2 which is
    already uppercase above, and 9 sat on an h3, where the brand document says sentence case.
*/
.caf-heading--standfirst,
.fr-view .caf-heading--standfirst { font-size: 1.625rem; }

.caf-heading--large,
.fr-view .caf-heading--large { font-size: clamp(2rem, 4.5vw, 2.6875rem); }

.caf-heading--display,
.fr-view .caf-heading--display { font-size: clamp(2rem, 5.4vw, 3.375rem); }

/* Left is not redundant: .caf-highlights__item > * centres every child below 768px, and a figure
   highlight is centred at every width, so some of these hold a heading out of that. */
.caf-heading--left,
.fr-view .caf-heading--left { text-align: left; }

.caf-heading--centred,
.fr-view .caf-heading--centred { text-align: center; }

/* Uppercase, letter-spaced h5 is the site's own small-heading treatment - .topBannerQuote h5 and the
   footer's "Links" headings both do it. */
h5 {
    font-size: var(--caf-text-h5);
    letter-spacing: 0.1px;
    text-transform: uppercase;
}

/* h6 had no size at all, so it rendered at the browser default - smaller than body copy and bold,
   which is nothing either site does. */
h6 { font-size: var(--caf-text-small); }

p { margin: 0 0 1em; }

a {
    color: var(--caf-teal);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15em;
}

a:hover { color: var(--caf-orange); }

img { max-width: 100%; height: auto; }

/* ---------------------------------------------------------------- layout */

/*
    THE PAGE SHELL CONSTRAINS NOTHING, and that is the whole of the full-bleed mechanism.

    Divi's .et_pb_section spans the viewport and its .et_pb_row sits inside at width:80%;max-width:
    1080px. Our markup has had that exact pair since the columns section was written - <section
    class="caf-section"> wrapping <div class="caf-section__grid"> - and only this file assumed
    otherwise, capping <main> at 1080px. Measured on /advisers-report at a 2033px viewport before the
    change: every band rendered 1032px wide, 51% of the screen, so all 589 declared background colours
    painted a box floating on white where the live site paints a band edge to edge.

    The header and footer have always done it this way (.caf-header / .caf-header__section), so this
    is the pattern already in this file rather than a new one - it had simply never been applied to
    the page.
*/
.caf-page { width: 100%; flex: 1 0 auto; padding-block: var(--caf-space); }

/*
    A FULL-BLEED BAND BRINGS ITS OWN PADDING, so main's shows as a white strip beside it rather than
    as space inside it. .caf-section already carries padding-block: var(--caf-space-large), and the
    hero is a .caf-section - so the 24px above was a gap between the sticky header and the top of the
    hero band, and the 24px below put white between the last band and the footer.

    Measured 3 October 2026, both channels: main started at the header's own bottom edge every time
    and its first child started 24px further down. The gap above the footer was 72px - this 24 plus
    .caf-footer's margin-top: 3rem - against the 80px standing gap front-end.md records for a section
    boundary. It is 48px now, and the last band's own 40px of bottom padding makes it ~88.

    The padding stays for everything it was written for: a listing, the search results, a form and a
    staff profile all land here as bare children and none of them paints a band.

    :has() rather than a wrapper class, for the same reason the :not() below is a :not() - _Layout
    renders @RenderBody() and cannot know what a template emits. It is already used in this file.
*/
.caf-page:has(> .caf-section:first-child, > .caf-body:first-child) { padding-block-start: 0; }
.caf-page:has(> .caf-section:last-child, > .caf-body:last-child) { padding-block-end: 0; }

/*
    A direct child that is NOT a band is constrained where it stands. Written as a :not() rather than
    as a wrapper class because _Layout renders @RenderBody() and cannot know what a template emits -
    an archive listing, the search results, a form and a staff profile all land here as bare children.

    width:min(80%, --caf-container) is .et_pb_row verbatim; 90% below Divi's own breakpoint is its
    narrow-screen row. A width rather than a max-width with padding, so the content measure stays the
    cap without box-sizing arithmetic. The cap is 1300px and the token's own comment says why that
    took three weeks to get right.
*/
.caf-page > :not(.caf-section, .caf-body, .caf-search-page),
.caf-section__grid,
.caf-body__row,
.caf-footer__row,
.caf-header__row {
    width: min(90%, var(--caf-container));
    margin-inline: auto;
}

@media (min-width: 981px) {
    .caf-page > :not(.caf-section, .caf-body, .caf-search-page),
    .caf-section__grid,
    .caf-body__row { width: min(80%, var(--caf-container)); }

    /* .caf-footer__row joined this list on 16 September 2026, and the comment above had already said
       it was here - "the header and footer have always done it this way" was true of the header and
       not of the footer, whose SECTION carried the cap. So every colour the footer declares painted a
       1600px panel floating in the middle rather than a band edge to edge, which is the same defect
       this block was written to fix on the page and one place was missed. Measured against live: its
       footer row is 948px of a 1185px viewport, which is min(80%, 1300) exactly. */
    .caf-footer__row,
    .caf-header__row { width: min(80%, var(--caf-container)); }
}

/*
    Divi's other two row widths, which this conversion did not have. width="100%" spans the band;
    max_width="1600px" raises the cap. Counted over English rows: 894 default, 31 full and 166 wide on
    America; 118, 20 and 91 on Canada.

    FULL IS THE ONE THAT SHOWS AND WIDE IS NEARLY THEORY, because the percentage binds before the cap:
    a wide row is identical to a default one below a ~1625px viewport and is 1536px against 1300px on a
    1920 screen, while a full row differs everywhere - at 1200px it is ~1185px against 960px.

    Both outside the media query above and both more specific than it, so they hold at every width -
    Divi emits width:100% for a full row with no media query of its own. The narrow-screen 90% is
    deliberately still the floor for a full row: min() takes it below 981px, which keeps a side gutter
    on a phone rather than running the text into both edges.
*/
.caf-section__grid--full { width: min(100%, var(--caf-container)); }
.caf-section__grid--wide { width: min(80%, var(--caf-container-wide)); }
.caf-section__grid--full.caf-section__grid--wide { width: min(100%, var(--caf-container-wide)); }

/*
    THE SAME TWO WIDTHS FOR A LAYOUT ROW, which the header, footer and body layouts get from the export
    exactly as a page section does - and did not read until 16 September 2026. 115 of the 285 rows
    across the six layouts declare one of these, so every one of them had been taking the default
    measure. The names are shared across the three prefixes because one rule should serve them.

    --uncapped is max_width="100%", which is "no pixel cap" rather than a width. It is what makes BOTH
    HEADERS full-bleed rather than merely full: they declare width="100%" max_width="100%", and live's
    header row is the whole 1185px of the viewport with the menu starting at x=0 and the logo panel
    ending at the right edge. A 1600px cap would still centre it on a wide screen.

    No 90% floor on a narrow screen, unlike the page's --full. A page's text wants a gutter; this is
    furniture, and the live headers run their menu and their logo panel edge to edge at every width.
*/
.caf-row--full { width: min(100%, var(--caf-container)); }
.caf-row--wide { width: min(80%, var(--caf-container-wide)); }
.caf-row--full.caf-row--wide { width: min(100%, var(--caf-container-wide)); }
.caf-row--full.caf-row--uncapped { width: 100%; }

@media (max-width: 980px) {
    .caf-section__grid--full,
    .caf-section__grid--full.caf-section__grid--wide { width: min(90%, var(--caf-container)); }
}

/*
    Bands take PADDING, not margin. With the colour spanning the viewport a margin between two
    coloured sections is a white stripe across the page, which is what the three :has() rules below
    used to work around - one adjacency rule now does it, works for padding as well as margin, and
    needs no :has().
*/
.caf-section,
.caf-body__section { margin-block: 0; padding-block: var(--caf-space-large); }

/*
    Divi puts pictures on rows and columns as settings rather than as modules inside them, and both
    arrive here as a --caf-background custom property. 148 columns across the two sites carry one and
    hold nothing else - a photo panel beside a text column is the commonest shape - so a column with a
    background needs a height of its own when the grid is collapsed and nothing is stretching it.
*/
.caf-section--background,
.caf-section__grid--background,
.caf-section__column--background {
    background-image: var(--caf-background);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}

/*
    A PICTURE DIVI TILES ACROSS THE TOP OF A COLUMN RATHER THAN COVERING IT - the thin rule above the
    heading in the grey-panel rows, 38 columns across both sites. The picture is a 61px white strip with
    a grey line at row 28. Stretched by the cover rule above, it became a dark band behind the text.
    Carried by the mapper's hook, since Divi's background_repeat is the setting (BackdropStripHooks). The
    raised position is Canada's background_vertical_offset: -25px, which leaves the line 3px from the top.
    The strip is white, so the column's own
    background colour, where it has one, shows only below the first 61px.

    Named `.caf-column--rule` since 5 October 2026, after the "Column rule" control that sets it. It was
    `.caf-backdrop--strip`, which described how Divi happened to paint it rather than what an editor is
    choosing. The import still parses the old spelling where it reads its own generated hook back
    (ColumnRule.FromClasses) - that is a legacy stored vocabulary, not a name anything renders.
*/
.caf-section__column--background.caf-column--rule {
    background-size: auto;
    background-position: center top;
    background-repeat: repeat-x;

    /* The rule has to sit ABOVE the heading. Every one of these columns opens with a module carrying
       custom_margin 50px (60 and 80-90 on three), which is what puts the heading below the line on
       the live site. Module margins do not survive conversion, so the column carries the one figure. */
    padding-top: 50px;
}

.caf-section__column--background.caf-column--rule-raised { background-position: center -25px; }

/*
    AND DIVI PUTS GRADIENTS THERE TOO, WHICH IS THE ONE BACKGROUND THIS CONVERSION USED TO DROP.

    A row or section setting use_background_color_gradient="on" makes Divi render the gradient INSTEAD
    of the flat colour, so CssColor refuses the colour on those - correctly - and until 18 September
    2026 nothing picked up what it refused. 17 rows and sections across the two exports painted neither.

    Two populations, and CssGradient's remarks have the census. 14 are translucent SCRIMS over a
    photograph, which is why the gradient paints ABOVE the picture here rather than instead of it -
    that is Divi's own order and the whole point of them. 3 are opaque two-tone PANELS where the
    gradient is the drawing: /give-now's charity search sits in a row whose background is
    #ff3b21 15%|#0d393b 15% at 90deg, which is the thick orange-and-teal frame the live page draws
    around the box and which we were rendering as nothing at all.

    A gradient takes the same inset a flat colour does, for the same reason: it is a panel, and a panel
    needs room around what it holds.
*/
.caf-section--gradient,
.caf-section__grid--gradient { background-image: var(--caf-background-gradient); }

.caf-section--gradient.caf-section--background,
.caf-section__grid--gradient.caf-section__grid--background {
    background-image: var(--caf-background-gradient), var(--caf-background);
}

.caf-section__grid--gradient { padding: var(--caf-space); }

/*
    THE FOUR GRADIENTS, NAMED - 4 October 2026.

    Until now the gradient arrived as a value: the section stored Divi's pipe notation in a free-text
    property an editor could not see, CssGradient parsed it, and the view wrote the finished
    linear-gradient() into a style attribute. Six sections across both channels carry one, in four
    distinct treatments, and none of the four is a per-instance measurement - they are four designs
    used once or three times each. So they are declared here, as the design system holds every other
    colour, and the section stores WHICH ONE rather than WHAT IT IS. See SectionPattern.

    Written as the values that were already reaching the page, not as fresh ones: CssColor folds an
    rgba() into eight-digit hex, so the scrim is #00000087 rather than rgba(0,0,0,0.53). Keeping the
    rendered bytes identical is what makes the before-and-after HTML diff readable.

    These sit on the SECTION and only declare a custom property, so --caf-background-gradient reaches
    the grid by inheritance when the row rather than the section is the painted element. The
    --gradient modifier above is what actually paints, and it is unchanged.
*/
.caf-section--pattern-dark-scrim {
    --caf-background-gradient: linear-gradient(180deg, #00000087 0%, #0000004a 100%);
}

/* /give-now's charity search frame: orange for the first 15% of the row, teal for the rest. The one
   gradient on either site that IS the page's design rather than a scrim over a photograph. */
.caf-section--pattern-brand-split {
    --caf-background-gradient: linear-gradient(90deg, #ff3b21 15%, #be3a28 15%, #0d393b 15%);
}

/* A hard white-to-paper split. Two sections draw one and they split at different heights, so they are
   two values rather than one - /who-we-serve at half, the FY23 statements at a quarter. Collapsing
   them would move a line across a page to save a line in this file. */
.caf-section--pattern-paper-split {
    --caf-background-gradient: linear-gradient(180deg, #ffffff 50%, #efefef 50%);
}

.caf-section--pattern-paper-split-quarter {
    --caf-background-gradient: linear-gradient(180deg, #ffffff 25%, #efefef 25%);
}

.caf-section__column--background:empty,
.caf-section__column--background > :only-child:empty { min-height: 18rem; }

/*
    Divi keeps a panel's colour in a section, row or column setting rather than in a stylesheet - 589 of
    them across the two sites, 191 on sections, 71 on rows and 327 on columns - and until they were read
    every one rendered on the page background. /advisers-report is the clearest case: three statistics
    reversed out of the brand teal, which arrived as plain headings on white.

    The colour arrives as --caf-background-color. Everything else about the panel does not: Divi wrote
    its font sizes and text colours - 1,139 and 1,716 of them - into CSS generated per page against
    positional module ids such as .et_pb_heading_3, which cannot survive flattening Divi's four nesting
    levels into three. So the text treatment here is derived from the colour's own luminance rather than
    migrated, and --on-dark is that derivation arriving.
*/
.caf-section--tinted,
.caf-section__grid--tinted,
.caf-section__column--tinted {
    background-color: var(--caf-background-color);
}

/* A column's own panel still needs its inset; the band gets its room from padding-block above and
   its width from .caf-section__grid. */
.caf-section__column--tinted { padding: var(--caf-space); }

/*
    AND SO DOES THE ROW'S OWN PANEL, which is the same case one level up.

    Divi's et_pb_section is full width and its et_pb_row is constrained inside it, so a colour declared
    on the ROW paints a centred panel rather than a band - and this conversion painted both on the
    section, because the mapper takes the row's colour in preference and then hands it to the
    full-width element. 52 colours across the two sites, 41 on America and 11 on Canada, including both
    home pages and the /alert/* articles.

    Measured on cafamerica.org/contact at innerWidth 1536: the Make a Gift Today panel is a 1300px box
    starting at x=110 with white either side, and ours painted the whole 1521px from x=0. The inset is
    --caf-space to match the column panel above rather than the live row's own 30px/50px, which is that
    one row's custom_padding rather than a rule.
*/
.caf-section__grid--tinted,
.caf-section__grid--background { padding: var(--caf-space); }

/*
    A Divi section holding several rows becomes several of these, each carrying the colour it inherited
    from the section - the teal panel on /advisers-report is two rows, a heading and then three columns.
    Closing the gap and the facing padding is what makes that read as the one panel it was rather than
    as two bands with a white stripe between them.
*/
.caf-section--tinted + .caf-section--tinted { padding-block-start: 0; }

/*
    THE LIVE SITES HAVE TWO RHYTHMS AND THIS FILE HAD ONE FLAT VALUE THAT MATCHED NEITHER.

    A .caf-section is one Divi ROW. Divi separates two rows of the same section by their own padding
    alone, and adds the section's own spacing at a boundary - so the gaps come in two families.
    Measured as rendered gaps between consecutive rows, on both channels independently:

        cafamerica.org/what-we-do   within  24, 0, 0, 40, 20, 40, 0, 0, 0                (median 20)
                                    across  50, 95, 120, 100, 120, 140, 64, 0, 110, 0    (median 95)
        cafcanada.ca/what-we-do     within  24, 0, 0, 40, 20, 0                          (median 20)
                                    across  50, 95, 120, 100, 120, 94, 65, 110, 0        (median 95)

    Ours was 80px at every one of them: too much for a row that belongs to the block above it, too
    little for a new one. The standing gap stays 80 rather than chasing the 95 - it is this
    stylesheet's own scale and the difference is 15px - and the two tighter tiers are what was missing.

    A DECLARED ZERO ONLY MEANS ANYTHING INSIDE A SECTION, and the first attempt at this got it wrong.
    /what-we-do's "Who We Serve" row declares padding-top: 0 and still sits 95px below the row before
    it, because that row is in the previous section; carrying the zero across the boundary closed a gap
    the live site holds open. The mapper now refuses both tighter tiers to a first or last row.
*/
.caf-section--space-top-tight { padding-block-start: var(--caf-space-small); }
.caf-section--space-top-none { padding-block-start: 0; }
.caf-section--space-bottom-tight { padding-block-end: var(--caf-space-small); }
.caf-section--space-bottom-none { padding-block-end: 0; }

/*
    Redefining the tokens rather than overriding each rule, so anything that already draws its colour
    from the palette adapts inside a dark panel - headings and body copy through --caf-ink, a hero
    subheading or a pager through --caf-ink-muted, and links through --caf-teal, which would otherwise
    be teal text on a teal ground. --caf-paper-alt goes translucent for the same reason: a table header
    or a .caf-section--cta block inside a dark panel would otherwise paint a light background under light text.
*/
.caf-section--on-dark,
.caf-section__grid--on-dark,
.caf-section__column--on-dark {
    --caf-ink: var(--caf-paper);
    --caf-ink-muted: var(--caf-ink-muted-on-dark);
    --caf-teal: var(--caf-paper);

    /* Body links took --caf-teal until 18 September 2026, so they were lightened here for free. They
       take --caf-link now, and #d14508 on a teal panel is 3.0:1 - which is the shape of defect this
       block exists to prevent, one token later. */
    --caf-link: var(--caf-paper);
    --caf-paper-alt: rgba(255, 255, 255, 0.12);
    color: var(--caf-ink);
}

/*
    The column grid. The template comes from the section itself as the --caf-columns custom property,
    written by ColumnsSectionViewComponent from Divi's own column_structure - so 2_5,3_5 is 2fr 3fr
    here exactly as it is 40/60 there.

    A custom property rather than an inline grid-template-columns, so that this stylesheet can collapse
    the grid on a narrow screen. An inline declaration would win against any rule here, which is why
    the sections were not responsive before.
*/
.caf-section__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--caf-space);
}

/*
    min-width: 0 on the columns, and it is the same defect the navigation row already carries a note
    about. A grid child defaults to min-width: auto - "never shrink below my content" - so one wide
    thing inside a column (a table, a pasted block, an image with an intrinsic width) pushes the column
    past its track, the row past the page, and the WHOLE PAGE scrolls sideways. The header column and
    .caf-nav were given this when the mobile menu was built; the page and body grids never were.

    Found by --visual-sweep, and only after its attribution was fixed: it first blamed the widest
    element sticking out, which was a span of pasted Word markup that wraps perfectly well at 200px.
    The offender is the outermost element that sticks out, and it was a body column overflowing by
    40px at 360px wide.

    THE SPLIT PAGE HERO'S TWO HALVES ARE THE THIRD CASE, added 2 October 2026. They are direct children
    of .caf-section__grid but are neither a section column nor a body column, so the rule above never
    reached them. Below 981px that grid is a single 1fr track, and the panel's min-content is set by its
    h1, whose clamp floor is --caf-text-h1 - 54px, and at 375px the 5vw term is 18.75px, so the floor is
    what applies. One unbreakable 14-letter French word at 54px is wider than the phone.

    Measured by the 2 October full sweep: 50 of its 53 page-overflow findings were these two selectors,
    25 each, across 25 pages on both channels and both languages - and that both halves are named the
    same number of times is the signature of the TRACK being over-wide, not of either half misbehaving.
    Worst was /fr/ce-que-nous-faisons/dons-a-des-projets-internationaux at scrollWidth 547 against 375.

    min-width: 0 alone would stop the PAGE scrolling and let the word spill out of the teal panel
    instead, so the title gets overflow-wrap too. Both are needed; neither is visible to a structural
    check, which is why this was confirmed by looking at the page and not by the sweep going quiet.
*/
/*
    AND header.caf-hero IS THE FOURTH SUCH CHILD, FOUND 13 OCTOBER 2026 - the list above had every
    grid child of .caf-section__grid except the one a page header is actually made of.

    A CAF.Page or CAF.ListingPage with a heading and no picture renders
    .caf-section__grid > header.caf-hero > h1.caf-hero__title, with no column between them. So the
    hero IS the grid item, and it kept min-width: auto while the title inside it already had both
    min-width: 0 and overflow-wrap. The title could break; its parent would not let it, because a grid
    item at auto refuses to shrink below the min-content of its longest unbreakable word.

    Measured on /news-insights/grantmaking-fundamentals at 360: header.caf-hero 394px wide inside a
    311px grid, the h1 the same 394, "Fundamentals" at 50px. Twelve pages, 7.5px to 51.5px over.

    THE 50px IS THE SUPPLIED LAYER'S, not ours - caf-overrides.min.css sets .caf-hero__title to a flat
    50px with no media query, over the clamp(1.375rem, 5vw, ...) below, which resolves to 22px at this
    width. That file is vendored and not ours to edit, and it does not need editing: a heading is
    allowed to be 50px on a phone if the box it sits in is allowed to wrap it.
*/
.caf-section__column,
.caf-body__column,
.caf-page-hero__panel,
.caf-page-hero__image,
.caf-hero { min-width: 0; }

/*
    EVERY HEADING, NOT JUST THE HERO'S - 13 October 2026, and the ten pages that needed it were all
    the same element.

    h1.caf-body__title is the article heading, rendered by the generated body partial rather than by
    _PageHero, so it never saw the rule that used to name .caf-hero__title alone. Its box was already
    constrained - 294px - and the text simply overflowed it: scrollWidth 387 against clientWidth 294
    on /story/closing-the-gender-gap, which is "Entrepreneurship" at the title size. Every ancestor
    passed it up to html, so the page scrolled sideways by 59px with no element visibly past the edge,
    because the overflow was INSIDE a box rather than a box being too wide.

    Named as a group rather than per class, because the next heading added to this site should not
    have to rediscover this. break-word rather than anywhere: it breaks a word only when that word
    cannot fit on a line of its own, so nothing that fits today moves.
*/
h1, h2, h3, h4, h5, h6,
.caf-hero__title,
.caf-body__title { overflow-wrap: break-word; }

/*
    AND THE HEADING HAS TO FIT, NOT MERELY STOP SCROLLING THE PAGE - 13 October 2026.

    min-width: 0 and overflow-wrap together stop the page moving sideways, and on their own they do it
    by breaking the word: /news-insights/grantmaking-fundamentals rendered "GRANTMAKIN / G /
    FUNDAMENT / ALS" at 360. The structural check passes and the page is worse. This is the rule the
    sweep cannot have an opinion about, and it is why the page gets looked at.

    THE 50px IS A VENDORED RULE WITH NO NARROW-WIDTH CASE. caf-overrides.min.css sets
    .caf-hero__title { font-size: 50px } unconditionally, which is right at desktop and is upstream's
    own "phone widths are the weakest". It is not ours to edit, so it is beaten on specificity: that
    selector is (0,1,0) and this is (0,2,0). A media query adds none, so the extra class is doing the
    work rather than the query.

    9vw rather than a fixed step, because the constraint is the longest word in a title we do not
    control. The worst of the twelve pages is "RESPONSIBILITY", 14 characters, which at this face needs
    about 0.62em each: 32px at 360 is roughly 280px inside a 311px column, and the clamp reaches the
    supplied 50px again at about 556px, where the column is wide enough to hold it. The floor is
    1.75rem so a short title does not go small for no reason.

    TAKE THIS BACK UPSTREAM. The right home for it is _10-page-hero.scss beside the rule it corrects;
    it lives here because that file cannot be edited in this tree.
*/
@media (max-width: 768px) {
    .caf-hero .caf-hero__title { font-size: clamp(1.75rem, 9vw, var(--caf-text-display)); }
}

/*
    THE GUTTER IS DIVI'S, AND IT IS PART OF THE TRACK LIST RATHER THAN SPACING AROUND IT.

    A Divi row separates its columns by a percentage of the row - 5.5% by default - and takes that out
    of each column in proportion to how much of the row the column is NOT, so 3_5,1_5,1_5 resolves to
    57.8/15.6/15.6 rather than 60/20/20. The tracks arrive here already written that way, so the gap
    has to be the same percentage or the row does not add up to 100%.

    This file used var(--caf-space) - a flat 24px - for every row on the site. Measured against live at
    1185px, its gutter is 65px, so every multi-column row was about 40px narrower in its gutters and
    correspondingly wider in its columns than the row it was converted from.

    --caf-space stays the fallback, for a row that declares no gutter and for everything stored before
    the property existed. Only column-gap moves: a percentage ROW gap would resolve against the width
    too, which is not a spacing anyone chose.
*/
@media (min-width: 981px) {
    .caf-section__grid,
    .caf-body__row,
    .caf-footer__row,
    .caf-header__row {
        grid-template-columns: var(--caf-columns, 1fr);
        column-gap: var(--caf-gutter, var(--caf-space));
    }

    /*
        A cell covering more than one track or more than one row. Divi lets a column hold a row and Page
        Builder sections cannot nest, so the converter flattens the two levels into one set of tracks and
        says here what covers what - see ColumnsSectionProperties.ColumnSpans. The home page's bento is
        the one row on either site that uses it: a tall panel spanning both rows, two panels beside it,
        and a wide one spanning their two tracks underneath.

        Inside the media query on purpose. Below it the grid is a single stacked column, where a row span
        would leave a hole; the declarations simply do not apply, which is why the spans travel as custom
        properties rather than as an inline grid-column that no rule could undo.
    */
    .caf-section__column {
        grid-column: span var(--caf-column-span, 1);
        grid-row: span var(--caf-row-span, 1);
    }
}

/* ---------------------------------------------------------------- body layout */

/*
    Divi's Theme Builder template that wraps an article: its title, byline, related posts and closing
    calls to action. Generated from the export - see Migration/Divi/BodyBuilder.cs - so these classes
    mirror the footer's, and the row grid is the same custom property the page sections use.
*/
.caf-body__section { margin-block: var(--caf-space-large); }
.caf-body__row { display: grid; grid-template-columns: 1fr; gap: var(--caf-space); }
/*
    The article title. The clamp was always right - both live templates compute 40px at a desktop
    width, which is this rule's 2.5rem ceiling - and the uppercase that used to be declared here is
    now what every h1 does, so only the clamp is left. The sentence this comment used to carry, "only
    the article title, because that is where the measurement is", was the right caution before the
    brand document existed and is answered by it: headlines are always caps.

    Weight is still left alone. The two sites disagree with each other - 500 on America, 700 on
    Canada - so there is nothing consistent to copy and the design system picks one.

    .caf-body__rule was deleted from here on 3 October 2026. It was emitted by nothing - its three
    neighbours below are all used - and the divider section 1,800 lines down already draws the same
    line, saying so in its own comment.
*/
.caf-body__title {
    margin: 0 0 0.5rem;
    font-size: clamp(2rem, 4vw, 2.5rem);
}
.caf-body__space { height: var(--caf-space); }
.caf-body__image { max-width: 100%; height: auto; }
.caf-body__button { margin-top: 0.9rem; }

/* The category line Divi prints above the title, from the page's own taxonomy. */
/* Only one selector, because .caf-body__categories was emitted by nothing - the generated article
   partials print this line through .pageHeader's first text block. */
.caf-body .pageHeader .caf-body__text:first-child {
    font-size: var(--caf-text-small);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* The closing call-to-action band, which the source marks with its own hook. */
/* padding-block rather than the shorthand: the band's width is the row's job now, and a side padding
   here would fight it. */
/*
   DO NOT UNSCOPE THIS - checked against the live site 4 October 2026, and the obvious fix is a defect.
   The Section style drop-down offers "Call to action - a light panel" on every section, and 103 of its
   110 placements sit on a CAF.Page where .caf-body never appears, so the class is emitted and nothing
   matches it. That reads as a fidelity bug until the source is read: on
   cafamerica.org/what-we-do/corporations/ every rule naming the hook is spacing and type -
   .color-cta .et_pb_column_1_2{padding:35px}, .color-cta .et_pb_text{margin:0!important;
   margin-bottom:20px!important}, .color-cta .et_pb_text h3{font-size:25px} - and there is NO
   BACKGROUND ANYWHERE. Dropping .caf-body from the selector would paint 83 pages grey that are not
   grey on the live site. The ground belongs to the article closing block, which is why it is scoped to
   the body that draws one. The label is the thing that is wrong, and that is decision 168.

   The class was the client's own `.color-cta` until 5 October 2026. The hook they write in the source
   is still read under that name by SectionStyle.FromHooks - it has to be, it is their word - but what
   we emit is ours, so the stylesheet and the Section style drop-down now use the same one.
*/
.caf-body .caf-section--cta { background: var(--caf-paper-alt); padding-block: var(--caf-space-large); }

/*
    The same block as each article's own content rather than the template's (ArticleClosing, decision
    122), so it is a Page Builder section inside the body's row rather than a section of its own - and
    left alone it would paint a grey box the width of the text, with its content at 80% of that.

    The shadow paints the band out to the page edges without widening anything, and the clip keeps it
    off the content above and below: a 100vw box would carry the scrollbar's width and scroll the page
    sideways. The grid takes the row's full width, which is the width the template's rows had.
*/
.caf-body .caf-article-closing {
    box-shadow: 0 0 0 100vmax var(--caf-paper-alt);
    clip-path: inset(0 -100vmax);

    /* The space the template put between the article and this block, which its spacer section and two
       section boundaries made - 241px measured at 1536 wide, and six large spaces is 240. */
    margin-block-start: calc(var(--caf-space-large) * 6);
}

/*
    And that spacer section - a divider and the author box that is not built, so nothing but space - now
    follows the block it used to precede, and would put the same space again between the band and the
    footer. Its space is above the block now.
*/
/* The band ends the section it is in, as it ended the template: no padding of the article's under it. */
.caf-body__section:has(.caf-article-closing) { padding-block-end: 0; }

.caf-body__section:has(.caf-article-closing) + .caf-body__section:not(:has(img, a, h1, h2, h3, h4, p:not(:empty))) { display: none; }

.caf-body .caf-article-closing > .caf-section__grid { width: 100%; }

/*
    THE SECOND HALF OF A SPLIT CLOSING BLOCK. The band that used to sit under the listing inside this
    one section is a two-column section of items now, immediately after it and carrying the same hook so
    it keeps the grey. The shadow is harmless painted twice - it is the same colour over the same
    ground - but the 240px that holds the block below the article is not, and would open a gap between
    the listing and the band it closes.
*/
.caf-body .caf-article-closing--continued { margin-block-start: 0; }

/*
    The content listing's header: the heading beside its button, then an intro where it has one, then the
    items. The row is the article template's own first row - 57.8% and 36.7% with a 5.5% gutter, which is Divi's 3_5,2_5 - so
    the block did not move when it stopped being template.
*/
.caf-content-listing__header { display: grid; grid-template-columns: 1fr; gap: var(--caf-space); }
/* A carried heading alone in its cell gives up its margin to the carried spacing; one with an intro under
   it keeps the margin a heading has above a paragraph. */
.caf-content-listing__header > .fr-view > h2:last-child { margin-block-end: 0; }
.caf-content-listing__header { margin-block-end: var(--caf-content-listing-header-space, 0); }

/* The strip starts level with the heading, as its column did, rather than centring on it. Beside the
   heading its link stays on one line and the column widens for it instead (see _ContentListing.cshtml). */
.caf-content-listing__header > .pr-slider-controls { align-self: start; }
.caf-content-listing__button { justify-self: start; align-self: start; }
/* Space under an intro, unless it already ends with an empty paragraph - the SDG page's does, carried
   verbatim, and that paragraph is what gives the author's own spacer its margin. */
.caf-content-listing__intro:not(:has(> :last-child:empty)) { margin-block-end: var(--caf-space); }
/* The paragraph the template's related strip sat in gave it 1em beneath, which is the gap above the
   band; kept, so the band did not move up when the paragraph went. The article closing's only - the
   home pages' "Our Insights" listings were never in a text module and are set in the page's sans. */
.caf-content-listing__listing:has(> .caf-body__related) { font-family: var(--caf-font-serif); margin-block-end: 1em; }

/* THE VISITOR CONTROLS - the category dropdown above a listing and the Load more button under it.
   Five placements carry them; every other listing renders none of this markup at all.

   The live control bar is a bare select at the left with a caret, no label and no border but its
   own, sitting above the grid with the items' own gap beneath it. Reproduced rather than copied:
   the type, the rule colour and the spacing are this stylesheet's own tokens, so the bar belongs to
   the site rather than to The Post Grid's defaults. */
.caf-content-listing__filter {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-block-end: var(--caf-space);
}
.caf-content-listing__filter-select {
    font: inherit;
    color: var(--caf-ink);
    background-color: transparent;
    border: 1px solid var(--caf-rule);
    border-radius: 2px;
    padding: 0.5rem 2rem 0.5rem 0.75rem;
    min-width: 12rem;
    /* The caret the live dropdown draws, as a background so the control keeps the platform's own
       keyboard and touch behaviour - a select styled into a div loses both. */
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, var(--caf-ink) 50%), linear-gradient(135deg, var(--caf-ink) 50%, transparent 50%);
    background-position: calc(100% - 1.05rem) 55%, calc(100% - 0.75rem) 55%;
    background-size: 0.3rem 0.3rem, 0.3rem 0.3rem;
    background-repeat: no-repeat;
}
.caf-content-listing__filter-select:focus-visible { outline: 2px solid var(--caf-ink); outline-offset: 2px; }
/* Hidden only once listing.js has wired the dropdown to submit on change. A form whose script never
   arrived keeps a button that works - which is the whole reason the class is added at runtime rather
   than written into the markup. */
.caf-content-listing__filter--auto .caf-content-listing__filter-submit { display: none; }

/* The live button is centred under the grid with a clear gap above it. .caf-button draws the fill. */
.caf-content-listing__more { margin-block-start: var(--caf-space); text-align: center; }
.caf-content-listing__load-more { display: inline-block; }

/* While a fetch is in flight. Deliberately a dimming of the items rather than a spinner: the items
   already on the page stay readable, and nothing is claimed to be happening in a place where it is
   not. The search page's own in-flight marker is the precedent. */
.caf-content-listing--busy .caf-content-listing__listing { opacity: 0.6; transition: opacity 120ms ease-out; }
.caf-content-listing__load-more[aria-busy="true"] { pointer-events: none; opacity: 0.7; }

@media (min-width: 981px) {
    /* A carried track list already includes the source row's gutter, which is 0% on both home pages -
       the importer declines a row with any other - so the gap goes with it. */
    .caf-content-listing__header { grid-template-columns: var(--caf-content-listing-columns, 57.8% 36.7%); column-gap: 5.5%; }
    .caf-content-listing__header[style*="--caf-content-listing-columns:"] { column-gap: var(--caf-content-listing-gap, 0); }

    /* Only beside the heading: stacked on a narrow screen the strip has the whole width, and a link that
       could not wrap would push the page sideways. */
    .caf-content-listing .pr-slider-controls .caf-content-listing__button { white-space: nowrap; }
}

/*
    The carousel's arrows, drawn rather than pictured. The client's strip carries two PNGs the media
    import holds at addresses no widget should hard-code, so the glyph is the same two-border chevron the
    buttons use, in the white the PNGs are, on the orange square the strip rules above already draw.
*/
.caf-content-listing .pr-slider-controls-left::before,
.caf-content-listing .pr-slider-controls-right::before {
    content: "";
    width: 0.6rem;
    height: 0.6rem;
    border-top: 0.15rem solid var(--caf-paper);
    border-right: 0.15rem solid var(--caf-paper);
}

.caf-content-listing .pr-slider-controls-left::before { transform: translateX(0.15rem) rotate(-135deg); }
.caf-content-listing .pr-slider-controls-right::before { transform: translateX(-0.15rem) rotate(45deg); }
.caf-body .darkGreenBox { padding: var(--caf-space); }

/*
    THE ARTICLE HEADER, IN ITS TWO SHAPES - decision 136, 29 September 2026. One template serves every
    article on both channels, and the article's own Hero image is the only thing that decides which
    shape it takes: the four layouts live assigns by Theme Builder rules the export does not carry are
    not reproduced.

    WITH A HERO IMAGE, THE SPLIT: picture beside the text, and the two orange bars both live sites draw
    from their Theme Options CSS - which is in no export, and was read off the live pages' unified
    stylesheet on 29 September 2026:

        .pageHeaderSplit:before, .pageHeaderSplit .bgImage:after
            { height: 4rem; background: #ff3b21; position: absolute; top: 10rem; width: 100%;
              right: calc(100% + 0px) }
        .pageHeaderSplit .bgImage:after { width: 1.5rem; left: calc(100% + 0px) }

    so a band 4rem tall, 10rem down, running from the row's left edge out to the page edge, and a
    1.5rem tab on the picture's right edge. ONLY THE BAND IS DRAWN - the tab was removed by decision
    139. 100vw rather than live's 100%, and the reason used to live on .homeBannerLeft h1::before, which
    is gone: a percentage resolves against the containing block, so the bar would stop at the row rather
    than the page, and it has to reach the edge at any width. Overflow to the LEFT never scrolls, which
    is what makes 100vw safe here. Above Divi's breakpoint only - live's phone section draws no bar.

    The bar is drawn only where the picture is (:has(> .caf-backdrop)), because the row's own ::before
    would otherwise sit beside the banner below.
*/
/*
    Three corrections by eye, 29 September 2026 (decision 139), on America's /blog and both sites'
    /story - every article showing the split:

    - THE BAR STANDS OFF THE PICTURE. Live draws it flush (calc(100% + 0px)); a gap of
      --caf-hero-bar-gap is the design now.
    - NO TAB. Live's second bar, the 1.5rem tab on the picture's right edge, is not drawn on this
      header, by decision. Other headers carry the same tab and are to be settled separately.
    - THE PICTURE IS TALLER. Ours was only as tall as the text beside it, 288px at 1440; cafcanada.ca's
      story header measures 386px at the same width, which is the 24rem floor here. The text is
      centred on that height, as live's is.
    - THE TEXT PANEL IS WHITE WITH BLACK TEXT. America's darkGreenBox painted it teal; cafcanada.ca's is
      already white with a black title. The tokens are reset on the panel rather than listing elements,
      for the reason .darkGreenBox gives, and the h1 is set because headings take --caf-teal.
*/
.caf-body { --caf-hero-bar-gap: 12px; }

.caf-body .pageHeaderSplit:has(> .caf-backdrop) > .caf-body__column:not(.caf-backdrop) {
    background-color: var(--caf-paper);

    /* The same air on both channels. Canada's panel had none - its column is not a darkGreenBox - so its
       title sat against the gutter. */
    padding: var(--caf-space);

    --caf-ink: #0d0d0d;
    --caf-ink-muted: #464646;
    --caf-link: #d14508;
    --caf-paper-alt: #f5f5f4;
    color: var(--caf-ink);
}

.caf-body .pageHeaderSplit:has(> .caf-backdrop) .caf-body__title { color: var(--caf-ink); }

@media (min-width: 981px) {
    .caf-body .pageHeaderSplit:has(> .caf-backdrop) { position: relative; min-height: 24rem; }

    .caf-body .pageHeaderSplit:has(> .caf-backdrop) > .caf-body__column:not(.caf-backdrop) {
        display: flex;
        flex-direction: column;
        justify-content: center;
    }

    .caf-body .pageHeaderSplit:has(> .caf-backdrop)::before {
        content: "";
        position: absolute;
        top: 10rem;
        right: calc(100% + var(--caf-hero-bar-gap));
        width: 100vw;
        height: 4rem;
        background: var(--caf-orange);
    }
}

/*
    WITHOUT ONE, THE BANNER: the whole section on the dark teal the page hero uses (#0d393b, see
    .caf-page-hero), the text in white, no picture - the full-width title bar live's alerts, webinars
    and podcasts carry. The picture column already withdraws (.caf-backdrop--none, below); this paints
    the section rather than the column so the band spans the viewport, and clears the column's own
    ground - white on Canada, teal-dark on America's darkGreenBox - so there is one teal, not two.

    The column's white is written inline as --caf-background-color, which no rule can outrank; this sets
    background-color itself, which .caf-tinted only feeds, so a more specific selector is enough.
*/
.caf-body .pageHeader:has(.caf-backdrop--none) {
    /* #0d393b rather than var(--caf-teal): this rule redefines --caf-teal to the paper colour four
       lines down, on this same element, so the token would paint the panel white under white text. */
    background-color: #0d393b;

    --caf-ink: var(--caf-paper);
    --caf-ink-muted: var(--caf-ink-muted-on-dark);
    --caf-teal: var(--caf-paper);
    --caf-link: var(--caf-paper);
    color: var(--caf-ink);
}

.caf-body .pageHeader:has(.caf-backdrop--none) .caf-body__column { background-color: transparent; padding-inline: 0; }

/*
    The author box - the staff pages an article credits (_ArticleAuthors.cshtml). Live's PublishPress
    box is a round headshot beside a name and a role; the name is the heading-weight line, the role the
    muted one. The colours are tokens, so the box reads on white, on America's teal panel and on the
    banner without a rule for each.
*/
.caf-authors { list-style: none; margin: 1.25rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 1rem 1.5rem; }
.caf-author { display: flex; align-items: center; gap: 0.75rem; }
.caf-author__portrait { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; flex: none; }
.caf-author__text { display: flex; flex-direction: column; }
.caf-author__name { font-family: var(--caf-font); font-weight: 700; color: var(--caf-ink); text-decoration: none; }
a.caf-author__name:hover { color: var(--caf-orange); }
.caf-author__role { font-size: var(--caf-text-small); color: var(--caf-ink-muted); }

@media (min-width: 981px) {
    .caf-body__row { grid-template-columns: var(--caf-columns, 1fr); column-gap: var(--caf-gutter, var(--caf-space)); }
}

/* ---------------------------------------------------------------- body copy */

/*
    The body face. .fr-view is Xperience's rich text wrapper - 1,268 widgets, the highest-volume
    markup on the site - and .caf-body__text is the generated body layouts' equivalent, so between
    them they are where a visitor's reading happens.

    Headings inside these are unaffected: the h1-h6 rule sets font-family explicitly, so it wins over
    what they inherit here. A button inside rich text would NOT have won, because .caf-button declared
    no family at all - it is given one below rather than left to inherit a serif it never had.
*/
.fr-view,
.caf-body__text { font-family: var(--caf-font-serif); }


/*
    Xperience's built-in rich text widget wraps its content in .fr-view, and this is the highest-volume
    markup on the site by a wide margin - 1,268 widgets. Nothing styled it until now, so migrated body
    copy inherited only the browser defaults.
*/
.fr-view { line-height: var(--caf-line); }
/*
    The second half of each of these is for a hooked text block. A text module that carried a
    module_class travels as a wrapping div (DiviWidgetMapper.WrapRichText), because the built-in rich
    text widget has nowhere else to put the class - so the first and last child of .fr-view can be that
    wrapper rather than the paragraph inside it, and without these the leading paragraph of 204 blocks
    on America and 77 on Canada keeps the top margin these rules exist to remove. Written for any
    top-level div rather than for a marker class of ours: an author's own wrapper wants the same
    treatment, and it is one rule instead of a class that would have to survive a re-import.
*/
.fr-view > :first-child,
.fr-view > div:first-child > :first-child { margin-top: 0; }
.fr-view > :last-child,
.fr-view > div:last-child > :last-child { margin-bottom: 0; }
/*
    BODY LINKS ARE ORANGE ON BOTH LIVE SITES AND WERE TEAL AND UNDERLINED HERE.

    The bare `a` rule above sets --caf-teal, which is right for the header, the footer, a listing card
    and a search result - all of which have their own measured treatments - and wrong for a link inside
    a paragraph, which is the one place a reader has to tell link from text at a glance.

    MEASURED ON THE RENDERED PAGES, both sites independently, on modules that declare nothing of their
    own: cafamerica.org/what-we-do/validation and cafcanada.ca/what-we-do/individuals-families both
    compute rgb(209, 69, 8) with text-decoration: none. That is #d14508, and it is deliberately NOT
    --caf-orange: the brand orange is #ff3b21, which the live sites reserve for a module that asks for
    it by name through link_text_color.

    THE CONTRAST IS A KNOWN TRADE AND THE FIGURES ARE HERE RATHER THAN ROUNDED, because the first
    version of this comment claimed "4.4:1 and passes" and that is only true on white:

        #d14508 on #ffffff  4.60:1   AA
        #d14508 on #fcfcfc  4.48:1   just under
        #d14508 on #f6f6f6  4.26:1   under
        #d14508 on #efefef  4.00:1   under - the card panels
        #ff3b21 on #ffffff  3.56:1   the 43 declared overrides
        #0d393b on #ffffff 12.61:1   what this replaced

    So a body link on a grey panel does not meet AA for normal text, and that is the live sites' own
    contrast reproduced rather than a choice made here - the same position --caf-orange buttons are
    already in at 3.47:1. It is logged rather than silently taken; a darker orange would meet AA on
    every ground and would no longer be the client's colour, which is CAF's call and not ours.

    THE UNDERLINE IS TRADED FOR A HOVER AND FOCUS ONE rather than simply dropped. Neither live site
    underlines a body link, so keeping ours would be a visible divergence on every page; but colour
    alone is not an affordance. #d14508 against the #0d0d0d of the text around it is 4.23:1, well over
    the 3:1 that lets colour distinguish a link at all, and the underline on hover and on focus is the
    second cue that makes relying on it legitimate.

    THE DEFAULT IS ON :root AND NOT ON .fr-view, and the difference is not cosmetic. .fr-view is a
    DESCENDANT of a dark panel, so declaring the token here would beat the one .caf-section--on-dark
    sets and body copy inside a teal band would keep #d14508 at 3.0:1 - the exact defect that block
    exists to prevent. Measured in the browser before it was moved: a probe anchor inside /contact's
    on-dark panel computed rgb(209, 69, 8). The order that works is :root, then the panel, then the
    module wrapper, each one closer to the link than the last.
*/
.fr-view a { color: var(--caf-link); text-decoration: none; }
.fr-view a:hover,
.fr-view a:focus-visible { text-decoration: underline; }

/*
    --caf-link is a token so a module can override it, which 43 of them do. Divi keeps a text module's
    link colour in link_text_color and renders it as per-module CSS keyed to a generated number, so
    nothing reached us: 35 modules on America and 8 on Canada, every one of them #FF3B21. /give-now's
    opening paragraph is the case that prompted this - "verify every charity" is the brand orange on the
    live page and arrived teal here. DiviWidgetMapper.WrapRichText writes the override onto the wrapper
    div as --caf-link, so it reaches this rule by inheritance and needs no selector of its own.
*/

.fr-view ul,
.fr-view ol { padding-left: 1.25em; margin: 0 0 1em; }
.fr-view li { margin-bottom: 0.35em; }
.fr-view img { display: block; margin: var(--caf-space) 0; }
.fr-view blockquote {
    margin: var(--caf-space) 0;
    padding-left: 1.25rem;
    border-left: 4px solid var(--caf-orange);
    font-size: var(--caf-text-lead);
}
/*
    width: 100% ON A TABLE IS A FLOOR, NOT A CEILING, and on a phone that is the difference between a
    tidy table and a page that scrolls sideways.

    A table lays out at auto, so it grows past its declared width whenever its cells cannot fit -
    width: 100% only stops it being NARROWER than its column. /privacy-policy at 360 put a 355px table
    in a 311px column and took the whole page with it, 12.8px over, because every ancestor passes that
    up. The cells already wrap: their min-content is a column of single words, and the table still
    could not fit inside the phone.

    So the table gets to scroll on its own rather than the page scrolling for it, which is the rule
    this project already applies to anything that is legitimately wider than its column. display:
    block is what makes a table scrollable at all - overflow has no effect on display: table - and the
    browser rebuilds the rows as anonymous table boxes inside it, so the table still looks like a
    table. Confined to the phone tier: above it the column is wide enough and the plain table is
    better, because a scroller the reader cannot see the end of is worse than one they never need.
*/
.fr-view table { width: 100%; border-collapse: collapse; margin: var(--caf-space) 0; }

@media (max-width: 768px) {
    .fr-view table { display: block; max-width: 100%; overflow-x: auto; }
}
.fr-view th,
.fr-view td { padding: 0.6rem 0.75rem; border: 1px solid var(--caf-rule); text-align: left; }
.fr-view th { background: var(--caf-paper-alt); }

/*
    TWO CONTENT TABLES SCROLLED THE WHOLE PAGE SIDEWAYS ON A PHONE, by 2px and 4px — found by the
    full sweep of 17 September 2026, which is the first time `page-overflow` had fired on anything but
    a one-off.

    The cause is the client's own markup and it is wrong in two different ways. `/privacy-policy`
    declares a two-column table at `width: 100%` and then gives TEN cells `width: 50%`;
    `/case-studies/reuniting-lovers` declares cell widths summing to about 122%. Both are inline, so
    they beat any stylesheet rule, and `table-layout: auto` then widens the columns to fit their
    content regardless. **Neither is ours**: the live privacy-policy page carries the identical table
    tag and the same ten 50% cells, and the 12 September `--origin` sweep recorded live's own
    reuniting-lovers overflowing by **20px at 1185px**, against our 4px at 360px.

    So the fix is the smallest thing that gives the content room back, and the room is ours to give:
    24px per column of horizontal padding, against overflows of 2px and 4px. Halving it at phone
    widths clears both with margin to spare, and changes nothing about how the table is laid out.

    `table-layout: fixed` was tried first and rejected although it also worked. It makes the declared
    widths authoritative, which is correct in principle — but at 360px it forced mid-word breaks, so
    `/blog/4-steps-to-planning-your-charitable-legacy` rendered "Benefici|ary designat|ions". A table
    that no longer scrolls the page but cannot spell is a worse page. `max-width: 100%` alone was
    measured too and fixes neither, because a table's used width is at least its minimum content
    width.

    `overflow-wrap: break-word` is a backstop rather than part of the fix, and it changes nothing on
    the three tables that can be measured — it breaks a word only when the word cannot fit its column
    at all, which none of them does. It is here because `/friends-fund-private` carries **three more
    tables** and is a secured page, so it answers 401 and neither the sweep nor a browser can measure
    it. Unlike `anywhere`, `break-word` does not enter the minimum-width calculation, so it cannot
    cause the mangling above.
*/
@media (max-width: 768px) {
    .fr-view th,
    .fr-view td { padding: 0.5rem 0.4rem; overflow-wrap: break-word; }
}

/* ---------------------------------------------------------------- button */

/*
    THE LIVE SITES HAVE TWO BUTTON SHAPES AND THIS FILE HAD ONE, so roughly three in five buttons on
    both channels rendered as a solid orange block where the original is an uppercase text link.

    Every figure below is a COMPUTED value read off the rendered live pages on 12 September 2026 -
    cafamerica.org/contact and cafcanada.ca/disaster-relief and /privacy - rather than a declared one,
    because Divi's button styling arrives as generated per-module CSS that is in neither child
    stylesheet: .transparent-cta and .orange-button appear on the page and in no file we can fetch.

    filled  padding 8px 41px 8px 30px, radius 0, 18px/600 Outfit uppercase, chevron at right: 15.4px
            (the asymmetric right padding IS the chevron's room), 47px tall
    link    no background, no padding, 18px/600 Outfit uppercase, chevron at right: -28px - outside
            the text box - and the text colour is the band's rather than the button's

    Which button gets which is ButtonVariant.FromDivi, from the colour the module declares. The
    chevron is drawn from two borders rather than set as a glyph: the live sites print Divi's
    ETmodules character "5", and that font is Elegant Themes' artwork which this project deliberately
    does not ship - see front-end.md. A chevron is a shape, not their drawing of one.
*/

.caf-button {
    position: relative;
    display: inline-block;
    font-family: var(--caf-font);

    /* 8px 41px 8px 30px, and the 11px of extra right padding is where the chevron sits. */
    padding: 0.5rem 2.5625rem 0.5rem 1.875rem;
    background: var(--caf-orange);
    color: var(--caf-paper);
    font-size: var(--caf-text-lead);
    font-weight: 600;
    line-height: var(--caf-line);
    text-decoration: none;
    text-transform: uppercase;
    border: 0;
    border-radius: 0;
    cursor: pointer;
    transition: background var(--caf-transition), color var(--caf-transition);
}

/*
    currentColor is what makes one chevron serve all three variants - including the link treatment,
    whose colour comes from the band it sits in rather than from this rule.
*/
.caf-button::after {
    content: "";
    position: absolute;
    top: 50%;
    right: 1.0625rem;
    width: 0.4rem;
    height: 0.4rem;
    border-top: 0.125rem solid currentColor;
    border-right: 0.125rem solid currentColor;
    transform: translateY(-50%) rotate(45deg);
}

.caf-button:hover { background: var(--caf-teal); color: var(--caf-paper); }

/* Divi's green-button: the same shape, the brand teal. #0b2d2e and #002e2e both read as dark and
   arrive here too, which is why this is one variant rather than three colours. */
.caf-button--dark { background: var(--caf-teal); }
.caf-button--dark:hover { background: var(--caf-orange); }

/*
    transparent-cta: 318 of the 506 declared button colours across the two exports, and the reason
    this section was worth rewriting.

    The colour is var(--caf-ink) rather than a fixed value, so it follows the band exactly as the live
    site does: the original declares #FCFCFC on a teal panel and #000000 on a light one, and
    .caf-section--on-dark and .caf-tinted--on-dark already redefine that token on precisely the bands
    that need it. One rule, and the two cases come out right on their own.

    THE RISK IN THAT IS A BUTTON THE AUTHOR MADE LIGHT BECAUSE IT SITS ON A PHOTOGRAPH - our ink would
    come out dark on a dark picture, and --visual-sweep cannot see it: its backdrop walk returns null
    the moment a background image intervenes, deliberately, so low-contrast skips text over photos.
    Counted instead, over both round-8 exports: of 245 transparent buttons, 107 declare a light text
    colour and ALL 107 sit inside an ancestor declaring a dark background COLOUR. None is over an
    image, and none is over nothing. The token resolves light in exactly the cases that need it.

    Padding rather than the live site's right: -28px. The chevron hanging outside its own box is an
    accident of Divi's absolute positioning, and a box that contains its own chevron has a hit area
    that matches what a visitor sees.
*/
.caf-button--link {
    padding: 0 1.5rem 0 0;
    background: none;
    color: var(--caf-ink);
}

.caf-button--link::after { right: 0.25rem; }
.caf-button--link:hover { background: none; color: var(--caf-orange); }

/* ---------------------------------------------------------------- call-to-action band */

/*
    The Contact / Newsletter band that closes most America pages, as one widget rather than a
    two-column section of rich text and buttons - see CtaBandWidgetProperties.

    Every figure is the one the converted section rendered with, so moving the band into a widget
    changes nothing a visitor sees: 48.5% 48.5% with a 3% gutter is what GutterFor resolves the
    source's gutter_width="2" to, and the panel inset is .caf-section__column--tinted's. The colour
    and the lightened text are the shared .caf-tinted and .caf-tinted--on-dark, which the view adds.
*/
.caf-cta-band { display: grid; grid-template-columns: 1fr; gap: var(--caf-space); }
.caf-cta-band__panel { min-width: 0; padding: var(--caf-space); }
.caf-cta-band--centred .caf-cta-band__panel { text-align: center; }

@media (min-width: 981px) {
    .caf-cta-band--panels-2 { grid-template-columns: 48.5% 48.5%; column-gap: 3%; }
}

/*
    THE GIFT PANEL: the same widget with its button on the corner (Button style), which is what
    Make Your Gift Count is on the America home page and ten more. The overhang itself is the
    .caf-button--corner rule further down, unchanged - these two lines only give it the right box.

    The PANEL is the positioned box, not the section grid the rule anchors to when a button widget
    sits in a column. In the widget the colour is painted by the panel, so that is the corner the
    button has to straddle; anchored to the grid it would hang off whatever the section's own inset
    happens to be. Below Divi's breakpoint the button stays in the flow, right-aligned, exactly as
    .caf-section__column does it - but by its own margin rather than the panel's text-align, which
    would have right-aligned the paragraph above it too.

    The panel widget joins this rule and the three below rather than repeating them, with one
    difference worth noting: its button sits inside .caf-panel__text, not as a direct child, because a
    picture beside the text makes the panel a grid and a third child would auto-place into it. So the
    combinator is a descendant one for the panel and a child one for the band.
*/
.caf-cta-band__panel:has(> .caf-button--corner),
.caf-panel:has(.caf-button--corner) { position: relative; }

/*
    A PANEL INSIDE A COLUMN, BELOW THE COLUMN'S OWN INTRO - the grey panels of the two-column rows,
    which the mapper places among their neighbours (TryMapPanelPair). The rich text above drops its last
    paragraph's margin, so the panel sat flush against the intro. Live separates them by Divi's standard
    module spacing, and the panels' own custom_margin top is 0px on 40 of 64. 30px is that spacing. The
    same space separates Canada's home page's two stacked panels. A band alone in its section has no
    previous sibling and is untouched.
*/
.caf-section__column > * + .caf-cta-band,
.caf-section__column > * + .caf-panel,
/* The tab set is built in the browser, so its previous sibling is often this file's own script tag -
   which is still an element, so the adjacent combinator holds. See wwwroot/js/tabs.js. */
.caf-section__column > * + .caf-tabs { margin-top: 30px; }

/*
    NO MORE OVERHANG THAN THERE IS ROOM FOR. A panel from a width="100%" row runs edge to edge, and the
    20px then hangs past the viewport and puts a sideways scrollbar on the page - --visual-sweep found
    it on /what-we-do/grant-management-services at 1521px, and it had found the same thing on /contact
    in September when the panel was still a section and a button. The section becomes a size container
    so 100cqw is its own width; half the difference between that and the panel is the room beside it,
    and the button takes 20px of it at most. A centred panel is unchanged; a full-bleed one sits its
    button flush. Only on sections holding a corner panel, so containment reaches nothing else.
*/
@media (min-width: 981px) {
    .caf-section:has(.caf-cta-band__panel > .caf-button--corner),
    .caf-section:has(.caf-panel .caf-button--corner) { container-type: inline-size; }

    /*
        100% resolves against the nearest positioned ancestor, which the rule above makes .caf-panel
        even where the button is nested inside .caf-panel__text - so the clamp measures the panel, as
        it does for the band.
    */
    .caf-cta-band__panel > .caf-button--corner,
    .caf-panel .caf-button--corner {
        right: calc(-1 * min(20px, max(0px, (100cqw - 100%) / 2)));
    }
}

@media (max-width: 980px) {
    .caf-cta-band__panel > .caf-button--corner,
    .caf-panel .caf-button--corner { display: flex; width: fit-content; margin-left: auto; }
}

/* ---------------------------------------------------------------- panel */

/*
    ONE panel: a heading, text, an optional picture and an optional button - the 39 single-panel
    call-to-action bands and three pinned content listings, which measured as one shape. The counts and
    why they are one widget are in PanelWidgetProperties.

    THE INSET FOLLOWS THE COLOUR, which is the one thing that differs from .caf-cta-band__panel above.
    That one pads unconditionally, which is right for a band: all 39 of the panels it used to carry are
    tinted. The three converted listings are not tinted at all, and padding them would indent a
    picture-beside-text row that the live site runs flush. var(--caf-space) is the same inset
    .caf-section__column--tinted and the band's panel both use, so a converted band is unchanged.
*/
.caf-panel.caf-tinted { padding: var(--caf-space); }

/* The label pill, as the card's - same treatment, because it is the same thing in the same place. */
.caf-panel__eyebrow {
    margin: 0 0 0.5rem;
    font-family: var(--caf-font);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--caf-teal);
}

.caf-panel__media { margin-bottom: var(--caf-space-small); }
.caf-panel__image { display: block; width: 100%; height: auto; }

/*
    THE PICTURE BESIDE THE TEXT, at the proportions the list archives already render - a third to the
    picture, two thirds to the text, stacking below Divi's breakpoint. The same tracks as
    .caf-listing--list .caf-listing__item:has(.caf-listing__media) further down, because that IS what
    the three converted listings drew: the shape reproduced, rather than a measurement carried.
*/
/*
    THE SUPPLIED LAYER HANGS THIS PANEL'S BUTTON 24px OUTSIDE ITS RIGHT EDGE, and on a phone there is
    no page left for it to hang into.

    caf-overrides.min.css carries
      .caf-panel--image-left .caf-panel__text > .caf-button--link
        { position: absolute; right: -24px; bottom: -31px; width: 60px; height: 76px }
    which is the orange corner tab, and at desktop the column is inset far enough to hold it. At 360
    the panel reaches the gutter, so 6.8px of the tab is past the edge and the page scrolls - measured
    on /disaster-crisis-response and /resources/views-of-charities.

    PULLED IN RATHER THAN CLIPPED. Clipping the panel would cut 36px off a 60px button and leave a
    visibly severed tab; the tab belongs on the corner, so at this width the corner is the panel's own
    edge. Beaten on specificity rather than with !important - the vendored selector is (0,3,0) and
    this is (0,4,1) - which is the one legitimate way to correct a vendored rule from a file that
    loads before it.
*/
@media (max-width: 768px) {
    .caf-panel.caf-panel--image-left .caf-panel__text > a.caf-button--link { right: 0; }
}

@media (min-width: 981px) {
    .caf-panel--image-left,
    .caf-panel--image-right {
        display: grid;
        gap: var(--caf-space);
        align-items: start;
    }

    .caf-panel--image-left { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }

    /* The text comes first in source order, so the picture's track is the second one. */
    .caf-panel--image-right { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }

    .caf-panel--image-left > .caf-panel__media,
    .caf-panel--image-right > .caf-panel__media { margin-bottom: 0; }

    /*
        THE PICTURE CROPPED TO THE HEIGHT OF THE TEXT, which is what a column background photograph does
        and what the two featured-item sections on Canada's news page were built as. The media box
        stretches to the row rather than sitting at the top, and the picture fills it.

        Inside this query on purpose: below Divi's breakpoint the two sides stack, there is no text to
        be as tall as, and a cropped picture would be an arbitrary band. A stacked phone keeps the
        natural picture whatever the fit says.
    */
    .caf-panel--fit-cover > .caf-panel__media,
    .caf-panel--fit-contain > .caf-panel__media { align-self: stretch; }

    .caf-panel--fit-cover > .caf-panel__media > .caf-panel__image { height: 100%; object-fit: cover; }

    /* The whole picture inside that box - a logo, a report cover, anything that must not be cut. */
    .caf-panel--fit-contain > .caf-panel__media > .caf-panel__image { height: 100%; object-fit: contain; }
}

/* ---------------------------------------------------------------- hero */

/*
    The banner Divi calls et_pb_fullwidth_header. Its own section supplies the dark ground and now the
    full width, so this only has to get the type right - and every figure below is declared by the
    modules themselves rather than chosen here.

    Counted across both round-8 exports: 97 instances, ALL of them title_font_size="50px" with
    title_font_size_phone="22px", and 92 of the 97 carry title_font="|||on|||||" - the fourth slot in
    Divi's font field, which is uppercase. Confirmed by eye on cafamerica.org/advisers-report and
    /news-insights, both of which render their banner title in caps.

    The 5 that do not ask for caps are all on America; they get it anyway, because the design system's
    whole claim is that a treatment is applied consistently rather than per page. If that turns out to
    matter on review it is one rule to scope.

    The clamp reproduces the two declared ends rather than interpolating invented ones: 22px on a
    phone, 50px on a desktop. Padding is small because the band it sits in already has its own -
    Divi's own custom_padding on 65 of the 69 America instances is 0px top and bottom for exactly the
    same reason.
*/
/*
    A HERO ALWAYS SITS ON A DARK BAND, AND ON 7 PAGES OURS WAS TEAL ON TEAL.

    The light treatment used to arrive by accident and only where the band was a flat colour. 90 of the
    97 hero sections declare background_color="#0D393B", so .caf-section--on-dark fired, redefined
    --caf-teal to --caf-paper, and the title came out white. THE OTHER 7 DECLARE A BACKGROUND IMAGE
    INSTEAD, and CssColor has no colour to read on those - so the title kept the bare h1 colour, which
    is --caf-teal, on a picture that is itself teal. /give-now rendered a 188px empty teal band where
    the live site says WAYS TO GIVE; so did Canada's /givenow, both languages.

    --visual-sweep is blind to exactly this, by construction rather than by omission: the backdrop walk
    returns null the moment a background image intervenes, so low-contrast skips text over pictures. It
    is the fifth defect in this file found by looking at the page, and the reason rule 13 stands.

    The treatment is unconditional here rather than derived per band, and that is measured. Every one of
    the 97 hero sections across both exports is dark - 90 at #0D393B, 5 on a photograph or a flat teal
    PNG, 2 on Canada's Give-Now-Background-3.png - so there is no hero on a light ground to make white
    text invisible on. Measured on the live sites too: the title computes #FCFCFC where a module
    declares title_text_color (68 of 97) and pure white where none does (29), and the subheading is
    white on all 50 that carry one, none of which declares a colour at all. Ours drew that subheading in
    --caf-ink-muted, #464646, which on the teal 90 was legible only just.

    Redefining the tokens rather than setting colours, for the reason .caf-section--on-dark's own
    comment gives: a rule that lists the elements to lighten will one day miss one.
*/
.caf-hero {
    padding-block: var(--caf-space);
    --caf-ink: var(--caf-paper);
    --caf-ink-muted: var(--caf-ink-muted-on-dark);
    --caf-teal: var(--caf-paper);
    color: var(--caf-ink);
}

/* An h1, so the case and the colour come from the global heading rules; only the clamp is its own. */
.caf-hero__title {
    margin: 0;
    font-size: clamp(1.375rem, 5vw, var(--caf-text-display));
    line-height: var(--caf-line-tight);
}
/* The label above the heading - the source's .topBannerQuote h5 - with the same small uppercase
   treatment the base h5 rule gives it, as a paragraph because it is not the heading of anything. */
.caf-hero__eyebrow {
    margin: 0 0 0.5rem;
    font-size: var(--caf-text-h5);
    letter-spacing: 0.1px;
    text-transform: uppercase;
}

.caf-hero__subheading { margin: 0.5rem 0 0; font-size: 1.25rem; color: var(--caf-ink-muted); }

/*
    THE PAGE HEADER FROM THE HERO FIELDS (Views/Shared/_PageHero.cshtml), which is the band above with
    its title lifted out of Page Builder. Its markup is the section the CAF.Hero widget used to sit in,
    so every rule above applies unchanged and a lifted header looks as it did.

    The colour is written here rather than read from --caf-teal, and that is load-bearing:
    .caf-section--on-dark redefines --caf-teal to the paper colour ON THIS SAME ELEMENT, so
    var(--caf-teal) here would paint the band white under white text. #0d393b is what 90 of the 97 Divi
    header sections declare.
*/
.caf-page-hero { --caf-background-color: #0d393b; }

.caf-hero__action { margin: 1.25rem 0 0; }

/*
    THE HOME BANNER - decision 140, 29 September 2026. Both channels' home pages, one design: the
    cafcanada.ca home header without what is only Canada's (the buttons running out to the left edge
    of the screen, the orange block under the photograph's corner), which is the brief - unify, not
    reproduce.

    Read off cafcanada.ca/ at 1440: the photograph 736px tall with NO scrim over it; a teal box at the
    left, 100px below the top of the photograph, the text 90px inside it; and one orange band 64px tall
    at the first line of the title, standing 24px out of the box's right edge. The buttons sit side by
    side at their own width.

    THE BOX IS MEASURED FROM ITS RIGHT EDGE, which is the correction of 4 October 2026. It used to be
    68% of the container, and because that container is itself 80% of the viewport with a 10% gutter
    either side, its right edge sat at a CONSTANT 64.4% of the screen at every width below 1529px.
    America's photograph has its subject at 53-64% of the frame, so the box's top-right corner landed on
    her face at every width from about 1135px to 1600px: measured covered at 1280, 1366 and 1536, clear
    at 1680 and 1920. Canada's photograph puts its subject in the right third and never showed it.

    Cropping could not fix the picture, and that is worth recording because Kentico's image variants
    make it look available: the only crop that moves her right of the box cuts the man out of the frame
    entirely, because he is already to her right. Narrowing the box inside the container could, but a
    box narrow enough took Canada's much longer title from 6 lines to 7 and stacked its buttons - two
    channels drifting apart over one page.

    SO MOST OF THE GUTTER WENT, NOT THE WIDTH. The box keeps an inset of its own - the bar needs ground
    to run across, and a box flush to the screen edge loses that half of the decoration entirely, which
    was tried on the way here and looked like a fault rather than a choice. What is left of the gutter
    pays for the right edge: 52% of the viewport, measured 48..710 at 1366 and 103..960 at 1920, with
    the bar showing 72px and 127px of orange. Canada keeps 6 lines and side-by-side buttons at both.

    The three expressions are each doing one job. margin-left: calc(50% - 50vw + inset) is the
    full-bleed trick against the centred .caf-section__grid - 50% of the grid minus half the viewport is
    exactly the distance from the grid's left edge to the screen's, at any width and whether the grid is
    at 80% or capped at 1300px - with the inset added back on. The width is then --caf-home-edge minus
    that inset, so the RIGHT edge stays put wherever the left one lands. And the inset takes a third of
    the gutter rather than a fixed figure, so the bar grows on a wide screen instead of staying mean.

    THE BAND IS SHORTER THAN IT WAS - 697px to 584px at 1366, 736px to 640px at 1920 - because it was
    taller than the live site's, seen in a side-by-side on 4 October 2026. The padding is symmetrical
    now where it used to carry an extra 2.5rem at the bottom, and the min-height clamp came down with
    it. Both channels' bands are content-driven at 1366, so this is the floor rather than the height.

    Above Divi's breakpoint only: on a phone the box is the width of the screen already.

    NO SCRIM, AND THERE NEVER WAS ONE ANYWHERE - established 3 October 2026. Two rules used to sit here:
    one laying a teal wash at 60% over any header with a picture (23 September 2026, written because
    white display type had disappeared into a beach on /who-we-serve), and one immediately below it
    cancelling that wash for this banner. The cancel always won - same specificity, later in source,
    same property - and six days after the wash was written decision 143 made a Page with a picture
    SPLIT, which took away its only other possible caller. So .caf-section--background became reachable
    from the home variant alone, where the cancel was waiting. The wash painted on no page on either
    channel, for ten days, and nothing could see it: --style-probe did not read background-image until
    the day this was found. Measured in the browser before removing it, and both home heroes read
    url(...) with no gradient in front.

    It is not needed either, which is why it is gone rather than repaired: no variant puts hero text
    over a photograph any more. The split's text sits on the teal panel, and this banner's text sits in
    the teal box below. IF A VARIANT EVER DOES, THE WASH HAS TO COME BACK - and be looked at, because it
    was never once seen working. The cancel went with it: .caf-section--background already declares
    exactly what it restated.
*/
.caf-page-hero--home .caf-hero { background-color: var(--caf-background-color); padding: var(--caf-space); }

.caf-page-hero--home .caf-hero__action { display: inline-block; margin-right: 1rem; }

@media (min-width: 981px) {
    .caf-page-hero--home {
        --caf-home-bar-top: 7.5rem;
        min-height: clamp(28rem, 42vw, 40rem);
        padding-block: 6.25rem;

        /* The box's right edge, which is the measurement the whole banner turns on, and the gutter it
           keeps on the left so the orange bar has something to run across. The inset takes a third of
           the container's own gutter and never less than 3rem, so the bar is a band rather than a nick
           at 1366 and gets more room on a wide screen where there is slack to spare. */
        --caf-home-edge: min(52vw, 60rem);
        --caf-home-inset: max(3rem, calc((50vw - 50%) / 3));
    }

    .caf-page-hero--home .caf-hero {
        position: relative;
        margin-left: calc(50% - 50vw + var(--caf-home-inset));
        width: calc(var(--caf-home-edge) - var(--caf-home-inset));
        padding: 5.5rem 3.5rem 4.5rem;
    }

    .caf-page-hero--home .caf-hero::before,
    .caf-page-hero--home .caf-hero::after {
        content: "";
        position: absolute;
        top: var(--caf-home-bar-top);
        height: 4rem;
        background: var(--caf-orange);
    }

    /* THE BUTTONS STRADDLE THE BOX'S BOTTOM EDGE (by eye, 29 September 2026): the box stops short of
       them by 1.25rem. A negative bottom margin on the inline-block takes that much out of the line
       box, so the box ends above the buttons without either being positioned - they stay in the flow
       and wrap as before. Only where there are buttons, so a home with none keeps its full padding. */
    .caf-page-hero--home .caf-hero:has(.caf-hero__action) { padding-bottom: 0; }
    .caf-page-hero--home .caf-hero__action { margin-bottom: -1.25rem; }

    .caf-page-hero--home .caf-hero::before { right: calc(100% - 1.5rem); width: 100vw; }
    .caf-page-hero--home .caf-hero::after { left: 100%; width: 1.5rem; }
}

/*
    THE PAGE HEADER WITH A PICTURE - decision 143, 29 September 2026. A Page (not an article, not the
    home) whose Hero has a picture splits: the teal box on the left, the picture as a column of its own
    on the right, 50/50 or 60/40 as the page's Hero layout says. Without a picture it stays the
    full-width teal band, the fallback the article header has too.

    Read off cafamerica.org/financial-advisors/ (60/40) and /what-we-do/ (50/50) in a browser: both sit
    inside the container, on white; the box is about 455px tall with its text about 95px in and centred
    on that height; the eyebrow carries a thin rule that runs the full width of the box [WRONG - see the
    correction below the panel rules; live draws no rule and the export declares no border]; and one
    orange band 4rem tall, about 9rem down, comes in from the page edge, overlaps the box's left side
    and shows again past the picture's right edge. The two pieces are the panel's ::before and the picture's
    ::after, as the home banner draws them, so they move with the boxes. No wash over the picture - the
    text is on the teal, not on the photograph.

    Below Divi's breakpoint the two stack, box first, and there are no bars.
*/
.caf-page-hero--split { background: none; }

/*
    THE TITLE BAND: A CENTRED HEADING OVER A FULL-WIDTH PICTURE, and it was a page name until
    13 October 2026.

    Six rules of the supplied design were addressed to html[data-caf-path="/give-now/"], for the same
    reason as the 70/30 above: the markup said "split" and nothing said which kind. This is a distinct
    header SHAPE rather than a proportion - the picture is behind the words instead of beside them -
    and any page may now pick it, which is the whole point of naming it.

    IT SHARES THE SPLIT'S MARKUP. The same panel and the same picture element; the picture is taken
    out of the flow to inset: 0 and the panel laid over it. That is how the supplied rules drew it,
    and keeping the markup means no new branch in _PageHero.cshtml and nothing new for --visual-sweep
    or a later reader to learn.

    The panel is transparent on purpose - background: none, not a colour - because the picture behind
    it is the band. Painting it would hide the thing it is sitting on. This is also why no rule here
    reaches for var(--caf-teal): inside .caf-page-hero that token resolves to the paper colour, and a
    band painted with it comes out white under white text.

    padding-block: 0 on the section and the padding moved onto the panel, so the picture reaches the
    band's own edges rather than stopping inside the section's air.
*/
.caf-page-hero--band { position: relative; padding-block: 0; }

.caf-page-hero--band .caf-section__grid {
    width: min(80%, var(--caf-container));
    grid-template-columns: 1fr;
}

.caf-page-hero--band .caf-page-hero__image {
    position: absolute;
    inset: 0;
    min-height: 0;

    /* Stretched rather than cropped, which is what the design asked for: the picture is a wash
       behind the words rather than a photograph with a subject to keep in frame. */
    background-size: 100% 100%;
}

.caf-page-hero--band .caf-page-hero__panel {
    position: relative;
    z-index: 1;
    min-height: 0;
    padding: calc(20px + min(5vw, 82px)) 0;
    background: none;
    text-align: center;
    align-items: center;
}

/* Neither orange bleed: both are drawn against the edge of a panel that no longer has one. */
.caf-page-hero--band .caf-page-hero__panel::before,
.caf-page-hero--band .caf-page-hero__image::after { display: none; }

.caf-page-hero--band .caf-page-hero__panel .caf-hero__title {
    margin: 0;
    font-size: 50px;
    font-weight: 500;
    line-height: 50px;
    letter-spacing: 0.1px;
}

/* Flush: live's box and picture touch, so the section grid's own gap is taken out. */
.caf-page-hero--split .caf-section__grid { display: grid; grid-template-columns: 1fr; gap: 0; }

/* Live's title is the banner size, not the band's - the same scale the home banner uses. */
.caf-page-hero--split .caf-hero__title { font-size: clamp(var(--caf-text-h1), 5vw, 4.5rem); line-height: 1.1; }

.caf-page-hero__panel {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: var(--caf-space);

    /* #0d393b rather than var(--caf-teal): this element is also .caf-hero, which redefines --caf-teal
       to the paper colour, so the token would paint the panel white under its own white title. */
    background-color: #0d393b;
}

/* THE RULE UNDER THE EYEBROW WAS NOT THERE, corrected 5 October 2026 after the user reported a
   separator production does not draw. The note above claimed "the eyebrow carries a thin rule that
   runs the full width of the box", read in a browser on 29 September; --style-probe against
   cafamerica.org/what-we-do/ says otherwise, and so does the export.

   Live's eyebrow is the h5 of an et_pb_text module whose settings declare fonts, sizes, letter
   spacing, background and margin and NO border of any kind, and the rendered element computes
   border-bottom: 0px none. Ours computed 1px solid rgba(252, 252, 252, 0.35).

   The full-bleed negative margin and the horizontal padding went with it: they existed only to make
   that rule span the box, and they cancel each other out, so the text does not move. The bottom
   padding stays, because it is the gap above the title rather than space for a line. */
.caf-page-hero__panel .caf-hero__eyebrow {
    margin-bottom: 1.25rem;
    padding-bottom: 0.75rem;
}

.caf-page-hero__image {
    position: relative;
    min-height: 16rem;
    background-image: var(--caf-background);
    background-size: cover;
    background-position: center;
}

@media (min-width: 981px) {
    .caf-page-hero--split { --caf-split-pad: 5.5rem; }
    .caf-page-hero--60-40 .caf-section__grid { grid-template-columns: 3fr 2fr; }
    .caf-page-hero--50-50 .caf-section__grid { grid-template-columns: 1fr 1fr; }

    /*
        THE THIRD PROPORTION, AND IT WAS A PAGE NAME UNTIL 13 OCTOBER 2026.

        The supplied design drew this with four rules addressed to html[data-caf-path="/how-we-work/"],
        because every page header emitted the same three classes and a stylesheet had no other way to
        tell that one apart. Rename the page and the header silently became 60/40. It is a layout, not
        a page: 70/30 drawn edge to edge, available to any page that picks it.

        The width is the supplied measurement kept as it was - 1620px is wider than --caf-container
        and narrower than --caf-container-wide, and it is what the design asked for rather than a
        token this file already had. max-width: none is needed because .caf-section__grid caps itself.
    */
    .caf-page-hero--70-30 .caf-section__grid {
        width: min(100%, 1620px);
        max-width: none;
        grid-template-columns: 70% 30%;
    }

    /* The panel bleed starts lower and reaches less far, because the band has no padding above it. */
    .caf-page-hero--70-30 .caf-page-hero__panel::before { top: 116px; right: calc(100% - 36px); }

    /* No orange tab on the far side of the picture: it would sit against the viewport edge. */
    .caf-page-hero--70-30 .caf-page-hero__image::after { display: none; }

    .caf-page-hero__panel { min-height: 28rem; padding: 4.5rem var(--caf-split-pad); }

    /* The eyebrow's full-bleed override went with the rule it was widening on 5 October 2026 - see
       the correction above. Nothing replaces it: with no line to span, the eyebrow is just text. */

    .caf-page-hero__panel::before,
    .caf-page-hero__image::after {
        content: "";
        position: absolute;
        top: 9rem;
        height: 4rem;
        background: var(--caf-orange);
    }

    .caf-page-hero__panel::before { right: calc(100% - 2.25rem); width: 100vw; }
    .caf-page-hero__image::after { left: 100%; width: 1.25rem; }
}

/* The same two, inside the article template's own header - see Views/Shared/_HeroDetail.cshtml. */
.caf-body__subheading { margin: 0.75rem 0 0; font-size: 1.25rem; color: var(--caf-ink-muted); }
.caf-body__action { margin: 1.25rem 0 0; }

/* ---------------------------------------------------------------- tile grid */

/*
    FOUR PICTURE TILES: ONE TALL ON THE LEFT, TWO HALVES ABOVE ONE WIDE ON THE RIGHT. The "Resources
    for …" block on nine America pages and the home page's feature grid - see TileGridWidgetProperties.

    Every figure is a COMPUTED value read off cafamerica.org on 28 September 2026, /what-we-do/friends-fund
    and the home page, at 1440 and 1920 wide. The source's own fractions say 1_2,1_2 and are not what
    the live page draws: the client's CSS narrows the left column, so the three tracks come out
    near-equal (348, 356, 356 at 1440) with 40px between them and 24px between the rows.

        resources  tiles 420px tall, the tall one both rows; heading 30px/500 Outfit, text 17px serif,
                   both inset 24px; the link a full-width bar, 20px/400 uppercase on 50% black, 12px 24px
        features   tall track two fifths of the row, tiles as tall as their words; text 16px serif,
                   inset 17px; the bar 17px/700 on 30% black with an arrow, and a label pill in the corner

    The text sits at the bottom of every tile, which is what the live flex column does.
*/
.caf-tile-grid { margin-block: var(--caf-space); }

.caf-tile-grid__header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--caf-space);
    margin-block-end: 1.5rem;
}

/* 43px uppercase in near-black, as live draws it, whatever the page's h2 scale says. */
.caf-tile-grid__heading {
    margin: 0;
    font-size: clamp(2rem, 4vw, 2.6875rem);
    font-weight: 500;
    line-height: 1;
    text-transform: uppercase;
    color: var(--caf-ink);
}

/* The chevron .caf-button draws, on the client's button, whose right padding is widened for it. */
.caf-tile-grid__button { position: relative; padding-right: 3rem; white-space: nowrap; }

.caf-tile-grid__button::after {
    content: "";
    position: absolute;
    top: 50%;
    right: 1.4rem;
    width: 0.4rem;
    height: 0.4rem;
    border-top: 0.125rem solid currentColor;
    border-right: 0.125rem solid currentColor;
    transform: translateY(-50%) rotate(45deg);
}

.caf-tile-grid__tiles {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.5rem;
}

.caf-tile-grid__tile {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    min-height: 26.25rem;
    overflow: hidden;
    background: var(--caf-tile-color, var(--caf-teal));
    color: var(--caf-paper);
}

.caf-tile-grid--features .caf-tile-grid__tile { min-height: 16rem; }

.caf-tile-grid__tile--empty { background: none; }

.caf-tile-grid__tile--empty > span {
    margin: auto;
    color: var(--caf-ink-muted);
    font-family: var(--caf-font);
}

.caf-tile-grid__image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Divi's gradient over the picture, 0.33 to 0.35 black on every tile that has one. */
.caf-tile-grid__tile--darken::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    background: rgba(13, 13, 13, 0.35);
}

.caf-tile-grid__text,
.caf-tile-grid__link,
.caf-tile-grid__eyebrow { position: relative; z-index: 2; }

.caf-tile-grid__text { padding: 1.5rem 1.5rem 0; }

.caf-tile-grid__heading-tile {
    margin: 0 0 1rem;
    font-size: 1.875rem;
    font-weight: 500;
    line-height: 1;
    color: var(--caf-paper);
}

.caf-tile-grid__body {
    font-family: var(--caf-font-serif);
    font-size: 1.0625rem;
    line-height: var(--caf-line);
    color: var(--caf-paper);
}

.caf-tile-grid__body > :first-child { margin-top: 0; }
.caf-tile-grid__body > :last-child { margin-bottom: 0; }
.caf-tile-grid__body a { color: var(--caf-paper); }

.caf-tile-grid__link {
    display: block;
    margin-top: 1.5rem;
    padding: 0.75rem 1.5rem;
    background: rgba(0, 0, 0, 0.5);
    font-family: var(--caf-font);
    font-size: 1.25rem;
    font-weight: 400;
    line-height: var(--caf-line);
    text-transform: uppercase;
    text-decoration: none;
    color: var(--caf-paper);
}

.caf-tile-grid__link:hover { color: var(--caf-paper); text-decoration: underline; }

/* The chevron, drawn from two borders as the buttons draw theirs. */
.caf-tile-grid__link::after {
    content: "";
    display: inline-block;
    width: 0.4rem;
    height: 0.4rem;
    margin-left: 0.6rem;
    border-top: 0.125rem solid currentColor;
    border-right: 0.125rem solid currentColor;
    transform: translateY(-0.12rem) rotate(45deg);
}

/* The home grid's version of the same parts. */
.caf-tile-grid--features .caf-tile-grid__text { padding: 1.5rem 1.0625rem 0; }
.caf-tile-grid--features .caf-tile-grid__heading-tile { margin-bottom: 0.6rem; }
.caf-tile-grid--features .caf-tile-grid__body { font-size: 1rem; }

.caf-tile-grid--features .caf-tile-grid__link {
    padding: 0.875rem 1.0625rem 0.625rem;
    background: rgba(0, 0, 0, 0.3);
    font-size: 1.0625rem;
    font-weight: 700;
}

/* A glyph, not an escape - see the card's arrow and CLAUDE.md rule 12. */
.caf-tile-grid--features .caf-tile-grid__link::after {
    content: "→";
    width: auto;
    height: auto;
    margin-left: 0.45rem;
    border: 0;
    transform: none;
}

/* The label pill, pinned to the corner as the card's is on the live template. */
.caf-tile-grid__eyebrow {
    position: absolute;
    top: 0;
    left: 0;
    margin: 0;
    padding: 0.5rem 0.9rem;
    background: var(--caf-teal);
    font-family: var(--caf-font);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--caf-paper);
}

/* Stacked below Divi's breakpoint, like every other row; side by side above it. */
@media (min-width: 981px) {
    .caf-tile-grid__tiles {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        grid-template-rows: auto auto;
        column-gap: 2.5rem;
    }

    .caf-tile-grid--features .caf-tile-grid__tiles {
        grid-template-columns: minmax(0, 4fr) minmax(0, 3fr) minmax(0, 3fr);
        column-gap: 1.875rem;
    }

    .caf-tile-grid__tile--tall { grid-column: 1; grid-row: 1 / span 2; }
    .caf-tile-grid__tile--wide { grid-column: 2 / span 2; }
}

/* ---------------------------------------------------------------- team grid */

/*
    The "Our Team" block: picked staff pages two to a row, each a portrait beside a name, a role and a
    LinkedIn link. Measured on cafamerica.org/how-we-work at 1440 and 1920 on 28 September 2026:

    heading   54px/500 Outfit uppercase, centred, near-black; 40px above and below its row
    intro     body copy, 25px above and below
    card      30px padding all round, no border or fill; two 50% columns, 2-gutter
    portrait  150px square (100px on phone), 40px before the text; the file itself is the circle
    name      30px/500 Outfit teal, line-height 1, 8px below
    role      body copy, serif 17px
    link      16px/600 serif, brand orange, no underline
    button    the link treatment, at the right-hand end of the row

    The portrait is cropped to a circle here as well, so a person with no team portrait - whose
    profile photograph is used instead - still reads as one of the set.
*/

.caf-people { margin-block: var(--caf-space); }

.caf-people__heading {
    margin: 2.5rem 0;
    font-size: clamp(2rem, 4vw, 3.375rem);
    font-weight: 500;
    line-height: 1;
    letter-spacing: -0.1px;
    text-transform: uppercase;
    text-align: center;
    color: var(--caf-ink);
}

/* /what-we-do/cadf's "Meet our team": the page's h3, left-aligned and teal, in its own case. */
.caf-people--subheading .caf-people__heading {
    font-size: var(--caf-text-h3);
    text-transform: none;
    text-align: left;
    color: var(--caf-teal);
}

/* Body copy on live is the serif, here as in the listing's text; the page's own default is Outfit. */
.caf-people__intro,
.caf-people__role { font-family: var(--caf-font-serif); }

.caf-people__intro { margin-block: 1.5625rem; }
.caf-people__intro > :last-child { margin-bottom: 0; }

.caf-people__members {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    margin: 0;
    padding: 0;
    list-style: none;
}

.caf-people__member {
    display: flex;
    align-items: flex-start;
    gap: 1.25rem;
    padding: 1.875rem 0;
}

.caf-people__portrait {
    flex: none;
    width: 100px;
    height: 100px;
    border-radius: 50%;
    object-fit: cover;
}

.caf-people__text { min-width: 0; }

.caf-people__name {
    margin: 0 0 0.5rem;
    font-size: 1.875rem;
    font-weight: 500;
    line-height: 1;
    color: var(--caf-teal);
}

.caf-people__role { margin: 0; }

.caf-people__link {
    display: inline-block;
    font-family: var(--caf-font-serif);
    font-size: 1rem;
    font-weight: 600;
    color: var(--caf-orange);
    text-decoration: none;
}

.caf-people__link:hover { color: var(--caf-teal); }

.caf-people__footer { display: flex; justify-content: flex-end; padding-block: 1rem; }

.caf-people__notice,
.caf-people--empty { color: var(--caf-ink-muted); font-style: italic; }

@media (min-width: 769px) {
    .caf-people__member { gap: 2.5rem; padding: 1.875rem; }
    .caf-people__portrait { width: 150px; height: 150px; }
}

/* TWO TO A ROW FROM THE SPACE THE GRID HAS, NOT FROM THE WINDOW - and it was the window until the
   webinar's speakers put a people grid inside an article column (decision 153). Divi's 981px
   breakpoint is the right answer for a grid in a full-width section and the wrong one for a grid in a
   column half that wide: a 1400px window still gave two columns of about 375px, which left 185px for
   the words beside a 150px portrait and broke "Vicki Kabalika" across two lines. 1000px is where two members fit
   with words beside them rather than under them: a member is a 150px portrait, 60px of padding and a
   40px gap, so a column under 500px leaves the role fewer than 250px and every multi-word name wraps. */
.caf-people { container-type: inline-size; }

@container (min-width: 1000px) {
    .caf-people__members { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 2.375rem; }
}

/* ---------------------------------------------------------------- item */

/*
    ONE item in a column of a section, beside others like it - see ItemWidgetProperties. This is what
    the card grid became when the grid moved out of the widget and into the section: the column count
    and the item count are the section's business now, so nothing here lays anything out.

    Every figure is the one the card grid rendered with, so an item in a 1_3,1_3,1_3 section renders as
    its card did in a three-column grid. What follows IS the per-card half of that block, moved here;
    the grid half was deleted rather than rewritten, so there is no card grid block left to compare
    against - git show 0044c65^:wwwroot/css/site.css is where the measurements are argued.

    THE GAPS ARE GONE FROM HERE and that is the point. The card grid set --caf-card-grid-gap to 3%
    (plain), 1.25rem (panel) and 5.5% (compact), because it drew its own columns. A section takes its
    gutter from the row it was converted from, through GutterFor - gutter_width="2" is 3% and "1" is 0 -
    which is the same number arrived at honestly instead of per style.

    A CONTAINER, so an item can answer to the width of its column rather than to the viewport. Nothing
    below uses it yet: every type size here is fixed, and the stacking is the section's at 981px. It is
    declared because that is the mechanism a widget in an arbitrary column needs, and .caf-people has
    proved it works here. Deliberately NOT on .caf-section__column: cqw units resolve to the nearest
    size container whatever its name, so containing the column would make 100cqw the column's width and
    silently flatten the corner button's overhang clamp, which measures the section on purpose.
*/
.caf-item {
    container-type: inline-size;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/*
    So a row of items is as tall as its tallest, which is what make_equal="on" does on the live rows.
    The section's grid cell already stretches; this is the item filling it.

    :only-child SINCE 3 OCTOBER 2026, and the restriction is the whole point of the rule rather than a
    detail of it. Every item written before decision 160 was one per column, so an unqualified
    height:100% meant "fill the cell". /finance is the first page to stack EIGHT in one column, and
    there each one claimed the full cell in turn: rows 3 to 16 were laid out a column-height apart and
    the page became scenery. An item with siblings has no cell of its own to fill, so it takes its own
    height - which is also what a stacked list of document rows wants.
*/
.caf-item:only-child { height: 100%; }

.caf-item--center { text-align: center; }
.caf-item--right { text-align: right; }

/*
    AN IMAGE IN THE TEXT IS A BLOCK, so text-align cannot reach it. .fr-view img is display: block with
    its own vertical margins - the rule the body copy needs, where an image is a figure between
    paragraphs - and a block box centres by its margins, not by its parent's text-align. Without this
    the six "Who We Serve" tiles centre their heading and their words and leave the icon hard left,
    which is markup that passes every structural check and a page that looks wrong.
*/
.caf-item--center .caf-item__text img { margin-inline: auto; }

.caf-item__eyebrow {
    margin: 0 0 0.5rem;
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--caf-ink-muted);
}

.caf-item__heading {
    margin: 0 0 0.625rem;
    font-weight: 500;
    line-height: 1;
}

.caf-item__text { font-family: var(--caf-font-serif); }

.caf-item__text > :last-child { margin-bottom: 0; }

/* The button sits at the foot, so a row of them lines up whatever the text above each. margin-top on
   the item's own child rather than on the text, because the text is optional. */
.caf-item__button { align-self: flex-start; margin-top: auto; }

.caf-item--center .caf-item__button { align-self: center; }
.caf-item--right .caf-item__button { align-self: flex-end; }

/* plain - "Who We Serve". The rule between rows is the section's now: .caf-section--ruled. */
.caf-item--plain { padding: 2.5rem 0 0.9375rem; }

.caf-item--plain .caf-item__heading {
    font-size: 1.4375rem;
    letter-spacing: 0.1px;
    color: var(--caf-ink);
}

.caf-item--plain .caf-item__text { margin-bottom: 1.5625rem; }

.caf-item--plain .caf-item__button {
    font-size: 1.125rem;
    line-height: 1.7;
}

/*
    panel - "Our Services", and every converted call-to-action panel.

    THE INSET FOLLOWS THE COLOUR, as the panel widget's does and for the same reason: var(--caf-space)
    is the inset .caf-section__column--tinted and .caf-cta-band__panel both use, so a converted band is
    unchanged. The card grid's own 2.1875rem is close enough to var(--caf-space) that reproducing it
    exactly would be the per-page measurement the front-end guide says to stop carrying.

    The lightening is the shared .caf-tinted--on-dark the view adds, not a redefinition here - the card
    grid hard-coded #0d393b and its own --caf-ink override because it had no colour property.
*/
.caf-item--panel.caf-tinted { padding: var(--caf-space); }

.caf-item--panel .caf-item__heading {
    margin-bottom: 1.625rem;
    font-size: 1.5625rem;
    letter-spacing: 1px;
}

.caf-item--panel .caf-item__text { margin-bottom: 3rem; }

/*
    THAT GAP IS ROOM FOR A BUTTON, so a panel that has none does not want it. The text is the last child
    exactly when no button was rendered - see _ItemMarkup.cshtml - and without this a tile of nothing but
    words carries 3rem of empty ground at its foot. Found by looking at the before and after of Canada's
    /what-we-do/corporations, whose six tiles are the only panels on either site with no button at all:
    the structural check passed and the tile had simply grown 48px.
*/
.caf-item--panel .caf-item__text:last-child { margin-bottom: 0; }

.caf-item--panel .caf-item__button {
    font-size: 1.25rem;
    font-weight: 500;
    line-height: 1.7;
}

/* compact - "Advantages of …", which carry a heading and words and usually no link. */
.caf-item--compact .caf-item__heading {
    margin-bottom: 1.5625rem;
    font-size: 1.5rem;
    line-height: 1.1;
    letter-spacing: 1px;
    color: var(--caf-teal);
}

/*
    THE PICTURE, added 3 October 2026 with decision 160 — the deferred question the item was registered
    as a view component to keep open. Deliberately the PANEL'S rules in the panel's shape rather than
    new ones: the same tracks, the same breakpoint, the same two fits, so a placement that moves between
    the two widgets looks the same in both and there is one thing to fix if either is wrong.

    ABOVE THE HEADING NEEDS ALMOST NOTHING, because the item is already a flex column and the picture is
    simply its first child. That is also why no .caf-item__body wrapper is emitted in that case: the 697
    placements written before this carry exactly the markup they always did.
*/
.caf-item__media { margin-bottom: var(--caf-space-small); }
.caf-item__image { display: block; width: 100%; height: auto; }

/*
    BESIDE THE TEXT THE ITEM STOPS BEING A FLEX COLUMN and becomes a two-track grid, so the column moves
    down to .caf-item__body — which is why the body wrapper exists at all. Without it the button's
    margin-top:auto would have nothing to push against.

    NO height:100% HERE, and that is the whole lesson of this rule. It was written with one, by analogy
    with .caf-item above, and it collapsed /finance to a single visible row at every width: a percentage
    height on a flex child of an indefinite-height flex column resolves to something the browser then
    lays the siblings out underneath, so item 1 claimed the column and items 2 to 8 went off the page.
    The item's own height:100% is against the SECTION'S GRID CELL, which is definite; this one had
    nothing definite to be a percentage of.
*/
.caf-item__body {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

@media (min-width: 981px) {
    .caf-item--image-left,
    .caf-item--image-right {
        display: grid;
        gap: var(--caf-space);
        align-items: start;
    }

    .caf-item--image-left { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }

    /* The text comes first in source order, so the picture's track is the second one. */
    .caf-item--image-right { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }

    .caf-item--image-left > .caf-item__media,
    .caf-item--image-right > .caf-item__media { margin-bottom: 0; }

    /*
        Cropped to the height of the text, inside the query for the panel's reason: below the breakpoint
        the two sides stack, there is no text to be as tall as, and a cropped picture would be an
        arbitrary band. A stacked phone keeps the natural picture whatever the fit says.
    */
    .caf-item--fit-cover > .caf-item__media,
    .caf-item--fit-contain > .caf-item__media { align-self: stretch; }

    .caf-item--fit-cover > .caf-item__media > .caf-item__image { height: 100%; object-fit: cover; }

    /* The whole picture inside that box - a report cover, anything that must not be cut. */
    .caf-item--fit-contain > .caf-item__media > .caf-item__image { height: 100%; object-fit: contain; }
}

.caf-item--empty { color: var(--caf-ink-muted); font-style: italic; }

/*
    THE LINE BETWEEN THE ROWS of a block built as a section per row - see
    ColumnsSectionProperties.RuledBelow. Desktop only, because the source drew it as a divider row
    marked disabled_on="on|on|off" and a stacked phone has no rows to divide.

    Positioned on the column rather than drawn as the section's own border-bottom so it spans the
    columns and not the row's full width, which is what the divider modules did - one per column, with
    the gutter between them left bare. position: relative only on a ruled section, so the corner
    button's positioned ancestor is untouched everywhere else.
*/
@media (min-width: 981px) {
    .caf-section--ruled .caf-section__column { position: relative; }

    /*
        Half the gap below, so the line sits in the middle of it. A ruled row and the row under it both
        take the standing gap, which is --caf-space-large each side, so half of that distance is one
        --caf-space-large from the bottom of this one. The source put its divider row's line in the
        middle of a 93px gap by the same reasoning.
    */
    .caf-section--ruled .caf-section__column::after {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        bottom: calc(-1 * var(--caf-space-large));
        border-top: 1px solid var(--caf-teal);
    }
}

/* ---------------------------------------------------------------- media and text */

/*
    A PICTURE BESIDE A HEADING, TEXT, A BUTTON AND AN OPTIONAL GREY PANEL - the who-we-serve rows and an
    article's photograph beside its words, which converted to a two-column section until they were one
    widget. It lays out exactly as that section did, from the same arithmetic: --caf-columns is
    ColumnsSectionViewComponent.GridTemplate over the Divi fractions, --caf-gutter is GutterFor, and the
    two sides stack below Divi's 981px breakpoint in source order, so a picture on the right comes after
    the text on a phone as it does on the live sites.

    Measured on cafamerica.org at 1534px:
      /who-we-serve/us-nonprofits   1_2,1_2, gutter 2 (3%): the photograph fills its half as tall as the
                                    text beside it; the text column tiles Group-70.png, a 20x61px strip
                                    whose one grey pixel (#808080) is at row 28, and its first module
                                    sits 50px down.
      /blog/resilience-in-haiti-…   eight rows of a column background photograph beside text, cover and
                                    centred, as tall as the text - 148px beside a heading alone.
    The corner classes those columns carry (topRightBorder, topLeftBorder, bottomBorderRight) paint
    nothing on either live site - no border, no pseudo-element, no rule in any stylesheet - so they are
    not drawn here either.
*/
.caf-media-text {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--caf-space);
}

@media (min-width: 981px) {
    .caf-media-text {
        grid-template-columns: var(--caf-columns, 1fr 1fr);
        column-gap: var(--caf-gutter, var(--caf-space));
    }
}

.caf-media-text__media,
.caf-media-text__text { min-width: 0; }

.caf-media-text--align-center { align-items: center; }

.caf-media-text__media > :last-child { margin-bottom: 0; }

/* The cropped photograph: the side is as tall as the text, and the picture fills it. */
.caf-media-text__frame {
    display: flex;
    flex-direction: column;
    height: 100%;
    margin: 0;
}

.caf-media-text__picture {
    display: block;
    flex: 1 1 auto;
    min-height: 18rem;
    background-image: var(--caf-background);
    background-position: center;
    background-repeat: no-repeat;
    background-size: cover;
}

.caf-media-text--fit-contain .caf-media-text__picture { background-size: contain; }

@media (min-width: 981px) {
    /* Beside a heading alone the live photograph is 148px, so the floor is about that rather than the
       18rem a stacked picture needs to be seen at all. */
    .caf-media-text__picture { min-height: 9rem; }
}

/* The line above the text, drawn rather than tiled: the same 1px grey at 28px, the text 50px down. */
.caf-media-text__text--rule {
    padding-top: 50px;
    background: linear-gradient(#808080, #808080) no-repeat 0 28px / 100% 1px;
}

/* Canada's strip is raised 25px, which leaves the line 3px from the top. */
.caf-media-text__text--rule-raised { background-position: 0 3px; }

/* The panel below the text, separated as it is in a column - see .caf-section__column > * + .caf-cta-band. */
.caf-media-text__text > * + .caf-cta-band { margin-top: 30px; }

.caf-media-text--empty,
.caf-media-text__missing {
    padding: var(--caf-space);
    border: 1px dashed var(--caf-rule);
    color: var(--caf-ink-muted);
}

/* ---------------------------------------------------------------- accordion */

.caf-accordion { border-bottom: 1px solid var(--caf-rule); }
.caf-accordion__title {
    padding: 0.85rem 0;
    font-weight: 600;
    color: var(--caf-teal);
    cursor: pointer;
}
.caf-accordion__title:hover { color: var(--caf-orange); }
.caf-accordion__content { padding: 0 0 1rem; }

/* ---------------------------------------------------------------- tabs */

/*
    A group of accordion panels drawn as a tab set - the 27 panels that came from Divi's et_pb_tabs
    rather than from an accordion. The wrapper and the strip do not exist in the markup: wwwroot/js/tabs.js
    builds them, so EVERY RULE IN THIS BLOCK IS INERT UNTIL IT HAS RUN and the fallback is the accordion
    above, untouched. See analysis/status.md §5 for what this replaces.

    The strip and the panel summaries are both present at every width and exactly one of them is
    rendered - the strip above the stacking width, the summaries below it. display:none rather than a
    visually-hidden clip, because the hidden one must leave the tab order as well as the page, and
    because two controls for one panel is the thing to avoid rather than to style around.

    The treatment is the live sites' shape with this project's own values: equal-width tabs in a row,
    a rule along the top of each that lights up on the open one, and the open tab's ground continuing
    into the panel below it so the two read as one surface. Live draws the rule 5px in #ff3b21 over
    #f5f5f4, which is --caf-orange over --caf-paper-alt here; the type comes from the tokens rather
    than from live's 'Outfit 600 uppercase, line-height 24px', per the front-end guide's standing rule.
*/

.caf-tabs__strip { display: none; }

@media (min-width: 981px) {
    .caf-tabs { background: var(--caf-paper-alt); }

    .caf-tabs__strip {
        display: flex;
        align-items: stretch;
    }

    .caf-tabs__tab {
        /* A flex box of its own so a label that wraps to two lines sits level with the ones that do
           not - "Adviser Insights and Strategies" against "Humanitarian Crisis in Haiti". */
        display: flex;
        flex: 1;
        align-items: center;
        justify-content: center;
        padding: var(--caf-space);
        border: 0;
        /* Transparent rather than paper-coloured, so the active rule is a colour change on one
           property and an inactive tab cannot be a 5px line of the wrong white. */
        border-top: 5px solid transparent;
        background: var(--caf-paper);
        color: var(--caf-ink);
        font-family: var(--caf-font);
        font-size: var(--caf-text);
        font-weight: 600;
        line-height: var(--caf-line-tight);
        text-align: center;
        text-transform: uppercase;
        cursor: pointer;
    }

    .caf-tabs__tab:hover,
    .caf-tabs__tab--active {
        border-top-color: var(--caf-orange);
        background: var(--caf-paper-alt);
    }

    /* The panels are the surface under the strip rather than a stack of rules, so the accordion's own
       separator goes, its summary goes, and the padding belongs to the body instead. */
    .caf-tabs .caf-accordion { border-bottom: 0; }
    .caf-tabs .caf-accordion__title { display: none; }
    .caf-tabs .caf-accordion__content { padding: 0; }
}

/*
    The body of one of those panels, which is the client's own two-column block: a .twoThirds of
    heading, words and a link beside a .oneThird holding one picture. NEITHER CLASS HAD A SINGLE RULE
    IN THIS FILE, so all 19 panels carrying them stacked the picture under the words at every width.
    Their child theme reads

        .tabStories .twoThirds { display:flex; max-width:60%; float:left; padding:25px 10% 25px 25px }
        .tabStories .oneThird img { object-fit:cover; min-width:100%; min-height:100% }

    so the names are 60/40 rather than the thirds they say, and the float is dead inside a flex parent.
    The shape is what is reproduced - text beside picture, picture filling its column, stacking at the
    same width everything else here stacks at - and the spacing comes from the tokens.

    .bottomBorderLeft rides along on all 19 oneThirds and is defined NOWHERE in either live stylesheet,
    so there is nothing to carry and no border is missing.

    Not scoped to .caf-tabs: this is the panel's own layout, so it is the same whether the group drew a
    strip or stayed an accordion.
*/

.tabStories .oneThird img {
    display: block;
    width: 100%;
    height: auto;
}

@media (min-width: 981px) {
    .tabStories .caf-accordion__content {
        display: flex;
        align-items: stretch;
    }

    .tabStories .twoThirds {
        display: flex;
        flex: 0 1 60%;
        flex-direction: column;
        justify-content: center;
        padding: var(--caf-space-large) var(--caf-space-large) var(--caf-space-large) var(--caf-space);
    }

    .tabStories .oneThird { flex: 1 1 40%; }

    .tabStories .oneThird img {
        height: 100%;
        object-fit: cover;
    }
}

/* ---------------------------------------------------------------- listing */

/*
    The card picture. The Post Grid draws one on every card - 440 instances across 143 pages on
    America, 37 across 10 on Canada - and this listing drew none until the generated models caught up
    with the FeaturedImage field.

    A fixed ratio with object-fit rather than the image's own shape, because a grid of cards whose
    pictures are different heights is a ragged grid; 3/2 is the commonest shape in the media library.
    The tint holds the box while the image loads so the page does not reflow under the reader.
*/
.caf-listing__media { position: relative; display: block; margin-bottom: var(--caf-space-small); }
.caf-listing__image-link { display: block; }
.caf-listing__image {
    display: block;
    width: 100%;
    aspect-ratio: 3 / 2;
    object-fit: cover;
    background: var(--caf-paper-alt);
}

/*
    A HEADSHOT IS SQUARE, and the rule above cost it a third of its height.

    Every portrait in the library is square or within 2% of it - the 19 on /staff are 270x270, 268x273,
    2560x2560 and 5504x5504 - so a square source into a 3:2 box loses 33% of its height, 16.7% off each
    end. Measured at 1440 that took the tops of the heads off Oscar Bazoberry, Oscar de Bruyn Kops and
    Matt Hammerstein and clipped Jane Peebles' hair. cafamerica.org/staff crops none of them: its
    picture is 258x258 against our 270x178.

    Square rather than height:auto, which is what the live site does. Two of the 19 are 268x273, so the
    source's own shape would stand them 5px proud of their row; cover at 1:1 takes 1.8% off those two
    instead and keeps the row even.

    This does NOT address the dither on the small headshots, and the dither was not what was reported:
    before and after are identical on the same patch, 8 colours and a 0.966 delta. At real size that is
    about one level in 255. The crop was the visible defect. The files are still small - see finding 184.

    AND IT STOPPED WORKING TWO DAYS LATER, which is the shape every vendored-layer defect has. The rule
    below was one class, (0,1,0), and that was enough while site.css was the only stylesheet. The
    supplied design arrived on 8 October with

      .caf-listing--grid:not(.caf-listing--carousel) .caf-listing__image { height: 320px; aspect-ratio: auto }
      .caf-listing--carousel .caf-listing__image                        { height: 360px; aspect-ratio: auto }

    at (0,3,0) and (0,2,0), and a fixed height beats a ratio outright: aspect-ratio is ignored once both
    axes are given. Nothing was reverted - the modifier is still on all 19 cards - it was outranked. The
    probe read 255x320 at 1440, 204x320 at 1185 and 648x320 at 768, where a square face is squeezed into
    a 2:1 box and loses a quarter off each end, which is worse than the 3:2 crop this rule was written
    to fix.

    So the selectors below mirror the two they correct and add the modifier, (0,4,0) over (0,3,0) and
    (0,3,0) over (0,2,0), and no !important - the same way the three vendored-rule corrections of
    13 October win. height: auto is half the fix and the more important half: without it the ratio is
    inert however specific the selector gets.
*/
.caf-listing__image--portrait { aspect-ratio: 1 / 1; }

.caf-listing--grid:not(.caf-listing--carousel) .caf-listing__image.caf-listing__image--portrait,
.caf-listing--carousel .caf-listing__image.caf-listing__image--portrait {
    height: auto;
    aspect-ratio: 1 / 1;
}

/*
    THE CATEGORY BADGE, which every card on both live sites wears over its picture and ours printed as
    grey text under the title when it printed it at all.

    One treatment because the source declares one: of the 35 grid configurations that show a category,
    28 set tpg_category_position="top_left" with tpg_category_style="style2" and tpg_category_bg
    "#092729", 4 put it above the title and 3 say nothing. The live ARCHIVES agree — /news-insights
    draws "Blogs" over its thumbnail too — so this is not a grid-only shape.

    Every figure is computed off cafamerica.org's home page on 23 September 2026: #092729 ground, white,
    13px Outfit uppercase at 0.39px tracking, padding 4px 8px 3px, and the badge overhanging the
    picture's left edge by 15px. The overhang is carried because it is what makes it read as a label
    ON the photograph rather than a caption inside it, and it cannot cause sideways scroll: the media
    element is inside the listing's own column, not against the edge of the page.

    #092729 is a literal rather than --caf-teal-dark (#0b2d2e), which is close and is not it. The value
    is the GRID's own setting rather than a brand colour, so a token would claim a relationship the
    export does not state.
*/
.caf-listing__badge {
    position: absolute;
    top: 15px;
    left: -15px;
    padding: 4px 8px 3px;
    background: var(--caf-teal-dark);
    color: var(--caf-paper);
    font-family: var(--caf-font);
    font-size: 0.8125rem;
    letter-spacing: 0.39px;
    text-transform: uppercase;
}

.caf-listing__item { padding-block: var(--caf-space); border-bottom: 1px solid var(--caf-rule); }
.caf-listing__text > :first-child { margin-top: 0; }
.caf-listing__text > :last-child { margin-bottom: 0; }
.caf-listing__title { margin: 0 0 0.25rem; font-size: 1.25rem; }
.caf-listing__title a { text-decoration: none; }
.caf-listing__title a:hover { text-decoration: underline; }

/* The archive meta line: date and category, as the live archives print them under a title. Separated by
   a rule on the category rather than by punctuation in the markup, so a missing category leaves no
   stray divider - the live page writes "date | category" and an item with neither renders no line. */
.caf-listing__meta { margin: 0 0 0.35rem; font-size: var(--caf-text-small); color: var(--caf-ink-muted); }
.caf-listing__date { font-size: inherit; color: inherit; }
.caf-listing__category::before,
.caf-listing__date:not(:first-child)::before { content: " | "; }
.caf-listing__category:first-child::before { content: ""; }

/*
    The byline, which the post slider prints first: "By Joe Crome, CAP® | Aug 26, 2026". Measured on
    cafamerica.org's home page as 16px Source Serif 4 at weight 700 in #354559 — the module's own
    meta_font, meta_font_size and meta_text_color, all three declared and none of them read until now.

    The separator is on the DATE rather than in the markup, matching what the category already does, so
    an item with a byline and no date and one with a date and no byline both come out clean.
*/
.caf-listing__author { font-family: var(--caf-font-serif); font-weight: 700; }
.caf-listing__summary { margin: 0; }

/*
    A staff member's position title, which the live site sets as italic serif where an article's excerpt
    is upright. Measured on cafamerica.org/staff against /news-insights rather than inferred: the theme
    styles The Post Grid's ACF custom-field output and its excerpt output differently, and ours had both
    as upright sans because they arrive in the same field here.
*/
.caf-listing__summary--role { font-family: var(--caf-font-serif); font-style: italic; }

/*
    THE READ-MORE CONTROL, which 13 of the 42 grids ask for and none of them got. An orange square with
    a white arrow in it and no words - measured on the home page's GRN box: #ff3b21 ground, white,
    59 x 68, padding 15px 15px 15px 20px around a 20px icon.

    The arrow is drawn rather than set in a font. The live site uses Font Awesome, which this project
    does not load and will not load for one glyph; a CSS triangle-and-bar is the same shape at any size
    and inherits the colour, so the hover state needs no second rule.

    Live positions it absolutely at right: -20px, bottom: -30px - hanging outside its own card. That is
    NOT carried, for the reason the button section gives about the chevron at right: -28px: a box that
    contains its own control has a hit area matching what a visitor sees, and an overhang measured
    against Divi's box is measured against a box we do not have. Right-aligned in the flow instead,
    which is what tpg_read_more_button_alignment="right" asks for.
*/
.caf-listing__more { margin: 0.9rem 0 0; text-align: right; }

.caf-listing__more-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 59px;
    height: 68px;
    background: var(--caf-orange);
    color: var(--caf-paper);
}

/* The site's own button hover rather than the grid's #d4311c: this is a button, .caf-button turns teal
   on hover, and one design system answers "what does a button do when you point at it" once. */
.caf-listing__more-link:hover { background: var(--caf-teal); color: var(--caf-paper); }

/* The arrow: a 2px shaft with a rotated square for the head, so one element draws both and the whole
   thing scales with the box rather than with a loaded font. */
.caf-listing__arrow {
    position: relative;
    display: block;
    width: 18px;
    height: 2px;
    background: currentColor;
}

.caf-listing__arrow::after {
    content: "";
    position: absolute;
    top: 50%;
    right: 0;
    width: 8px;
    height: 8px;
    border-top: 2px solid currentColor;
    border-right: 2px solid currentColor;
    transform: translateY(-50%) rotate(45deg);
}

/* The archive pager. Newer on the left and older on the right, which is the order the live sites put
   them in - their pagination floats one each way. */
.caf-pager { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.75rem 1.5rem; margin: 2rem 0 0; padding-top: 1rem; border-top: 1px solid var(--caf-rule); }
.caf-pager__position { order: 2; font-size: var(--caf-text-small); color: var(--caf-ink-muted); }
.caf-pager__newer { order: 1; }
.caf-pager__older { order: 3; }
.caf-pager a, .caf-pager__newer, .caf-pager__older { font-weight: 600; text-decoration: none; }
.caf-pager a:hover { text-decoration: underline; }
.caf-listing__empty { color: var(--caf-ink-muted); }

/*
    A GRID'S COLUMN COUNT IS THE SOURCE'S, NOT A CONSTANT. The Post Grid stores one per grid and this
    rule used to be a flat repeat(3): right for 16 of the 26 grid listings and wrong for the other 10,
    /staff among them, where cafamerica.org runs four cards to a row against our three. The widget
    writes --caf-listing-columns and --caf-listing-columns-medium onto the container; the fallbacks
    below keep any listing that predates them rendering as it did.

    Two steps rather than one, because the desktop count can now be 4: four cards across a 768px
    viewport are about 180px each, so the medium count - 2 on every grid in both exports - holds from
    768px and the full count waits for 1024px. Below 768px the items stay stacked, which is what the
    source's own mobile count says.
*/
@media (min-width: 769px) {
    .caf-listing--grid {
        display: grid;
        grid-template-columns: repeat(var(--caf-listing-columns-medium, 2), minmax(0, 1fr));
        gap: var(--caf-space);
    }

    .caf-listing--grid .caf-listing__item { border-bottom: 0; }

    /*
        An archive lists rather than grids, and the live archives put the thumbnail beside the text
        rather than above it. Scoped with :has() to the items that actually have a picture, so an
        archive holding both kinds does not leave an empty first column on the ones that do not.
    */
    .caf-listing--list .caf-listing__item:has(.caf-listing__media) {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
        gap: var(--caf-space);
        align-items: start;
    }

    .caf-listing--list .caf-listing__media { margin-bottom: 0; }

}

/*
    THE POST SLIDER, which is what every ba_post_list on both sites is: all nine carry
    module_class="pr-post-slider" and the client forces the plugin's list into a flex track with their
    own injected CSS, whatever list_type each module declares.

    A scroll-snap row rather than a transform track. The browser does the animation, the momentum, the
    touch and the keyboard; wwwroot/js/carousel.js only adds the arrows, and with it absent the row still
    scrolls. Their version is 200 lines of pointer capture and click suppression to arrive at the same
    reading.

    The card width is their formula rather than a guess: --pr-visible cards across with --pr-gap between
    them, which is what `flex: 0 0 calc((100% - (n - 1) * gap) / n)` says, at their own three
    breakpoints - 3 cards at 30px, 2 at 24px below 980px, 1 at 20px below 767px. Read out of the <style>
    block the client pastes beside the list, so these are their numbers and not an interpretation of
    them.

    OUTSIDE THE BREAKPOINT THE OTHER TWO LAYOUTS SIT IN, because a phone carousel is one card wide and
    still a carousel; the grid and the list have a stacked form below 768px and this does not.
*/
.caf-listing--carousel {
    --caf-carousel-visible: 3;
    --caf-carousel-gap: 30px;

    display: flex;
    gap: var(--caf-carousel-gap);
    overflow-x: auto;
    scroll-snap-type: x mandatory;

    /* The row is the scroll container, so its own scrollbar is the only thing that should move. */
    overscroll-behavior-x: contain;
}

.caf-listing--carousel .caf-listing__item {
    flex: 0 0 calc((100% - (var(--caf-carousel-visible) - 1) * var(--caf-carousel-gap)) / var(--caf-carousel-visible));
    scroll-snap-align: start;
    border-bottom: 0;
}

/* Only once carousel.js has bound the arrows - see the note it carries. Before that, and with the file
   absent, the scrollbar is the only thing telling a reader the row moves. */
/*
    THE SUPPLIED LAYER BLEEDS THE CAROUSEL 30px EACH SIDE AT EVERY WIDTH, and on a phone the right
    half of that bleed is off the screen.

    caf-overrides.min.css carries
      .caf-content-listing--carousel:not(:has(.caf-heading--display)) .caf-listing--carousel
        { width: calc(100% + 60px); margin-inline: -30px }
    with no media query. At desktop the column is inset far enough that the bleed lands on the page and
    is the design. At 360 the column already reaches the gutter, so the carousel sits at x = -13 and
    371px wide in a 311px column; the left half costs nothing, because leftward overflow does not grow
    scrollWidth in a left-to-right document, and the right half took /news-insights 13px sideways.

    THE BLEED IS UNDONE RATHER THAN CLIPPED, AND THE REASON IS CANADA.

    Clipping the wrapper was tried first and it worked on America - and it cost Canada a finding it
    never had. site.css serves both channels and the markup carries no channel marker, so a clip here
    lands on cafcanada too, where this carousel is not bled at all and was quietly spilling 5px of its
    own (scrollWidth 293 against clientWidth 288). America gained nothing visible and Canada lost 5px
    of something nobody had asked a question about. A fix that reaches a channel it was not written
    for is a fix that has to be aimed better.

    Cancelling the bleed is aimed exactly right, because it is a no-op wherever the bleed is absent:
    on Canada width: 100% and margin-inline: 0 are already the computed values, so this changes
    nothing there, and on America it returns the carousel to its column.

    BEATEN ON SPECIFICITY, NOT ORDER. The vendored selector counts three classes - the two names plus
    :not(:has(.caf-heading--display)), since :not() and :has() each take their argument's specificity
    - and this one counts four, so it wins although it is declared in the file that loads first.

    Phone only. Above 768px the column is inset far enough that the bleed lands on the page and is
    the design.
*/
@media (max-width: 768px) {
    .caf-content-listing.caf-content-listing--carousel .caf-listing.caf-listing--carousel {
        width: 100%;
        margin-inline: 0;
    }
}

.caf-listing--carousel.caf-carousel-wired { scrollbar-width: none; }
.caf-listing--carousel.caf-carousel-wired::-webkit-scrollbar { display: none; }

@media (max-width: 980px) {
    .caf-listing--carousel { --caf-carousel-visible: 2; --caf-carousel-gap: var(--caf-space); }
}

@media (max-width: 768px) {
    .caf-listing--carousel { --caf-carousel-visible: 1; --caf-carousel-gap: 20px; }
}

/* 981px rather than the 1024px this carried: a grid changing its column count is layout, and layout
   re-forms at Divi's own boundary everywhere else in this file. 1024 measured nothing. */
@media (min-width: 981px) {
    .caf-listing--grid { grid-template-columns: repeat(var(--caf-listing-columns, 3), minmax(0, 1fr)); }
}

/* The related-posts strip under every article. The body layout has emitted this hook since it was
   generated and nothing has ever styled it. */
.caf-body__related { margin-block-start: var(--caf-space-large); }

/* ---------------------------------------------------------------- divider */

/*
    et_pb_divider. Measured on our own served pages rather than on the live census: 57 <hr> across 20
    pages, all of which drew the browser's default inset 3D rule because nothing styled them. (The
    live sites carry far more - 153 instances on 136 pages on America - but that is their page count,
    not ours, and the two are different questions.)

    The same line as .caf-body__rule, because a divider in a page body and a divider in a generated
    body layout are the same thing to a reader.
*/
.caf-divider {
    border: 0;
    border-top: 1px solid var(--caf-rule);
    margin-block: var(--caf-space);

    /* An <hr> carries margin-inline:auto in the UA stylesheet. Harmless in normal flow, and fatal
       inside a flex column: the auto margins absorb every pixel of free space, so the rule computes
       to width 0 with the whole column's width split between its margins. Measured on /what-we-do,
       whose .caf-pinned-buttons columns are display:flex - all three dividers read 0px wide with 172px of
       margin each side, and had done since before this rule existed. An invisible divider is the
       blank-column shape again: present, correct and drawing nothing. */
    width: 100%;
    margin-inline: 0;
}

/*
    A spacing-only divider draws nothing and must still take up room. The height was written INLINE in
    the view, which is the exact trap this file's own comments warn about twice - an inline declaration
    beats every rule here, so the space could not be changed or made responsive from the stylesheet.
    It is a class now and the view carries no style attribute.

    DORMANT: measured across all 410 served pages, zero instances render today - every converted
    divider so far has ShowLine set. The rule is here because the inline style had to go, not because
    anything is using it. Exercised by hand before committing rather than trusted; see the note on the
    unset-content block, and .darkGreenBox and .caf-nav for why that is not optional in this file.
*/
.caf-divider--space {
    border: 0;
    margin: 0;
    height: var(--caf-space);
}

/* ---------------------------------------------------------------- raw html */

/*
    et_pb_code, emitted verbatim: embeds, iframes and inline scripts that only work unescaped. A flow
    root so a floated embed cannot escape into the next widget, and the same first/last margin trim
    .fr-view gets, since an author's block usually opens with its own paragraph.
*/
.caf-html { display: flow-root; }
.caf-html > :first-child { margin-top: 0; }
.caf-html > :last-child { margin-bottom: 0; }
.caf-html iframe { max-width: 100%; }

/* ---------------------------------------------------------------- image and gallery */

.caf-image { margin: 0 0 var(--caf-space); }
.caf-image__caption { margin-top: 0.5rem; font-size: var(--caf-text-small); color: var(--caf-ink-muted); }

/* What a gallery slide is before wwwroot/js/gallery.js reaches it, and what it stays in the Page
   Builder and with JavaScript off: a row re-formed out of sibling widgets that have no wrapper. */
.caf-image--gallery {
    display: inline-block;
    vertical-align: top;
    width: min(100%, 18rem);
    margin-right: var(--caf-space);
}

/*
    THE CAROUSEL, built at runtime by wwwroot/js/gallery.js out of the slides sharing one gallery name.

    EVERY RULE HERE IS SCOPED INSIDE .caf-gallery, and that is load-bearing twice over. The supplied
    design layer draws a gallery slide as a fixed 51%-wide, 340px-tall floated tile, and every one of
    its rules is written .caf-section__column > .caf-image--gallery - a DIRECT child. Moving the figures
    into the track below stops all of them matching, so the tile geometry is undone without editing a
    vendored file that the next recopy would discard (hard rule 2). The two rules above are ours and are
    undone here explicitly, because a descendant selector does not care about the wrapper.

    object-fit: contain, NOT cover. The fixed-height crop is what made three 2.5:1 banners on
    /give/corporate-aid-for-ukraine lose 63% of their width. A gallery holds whatever an editor picked -
    on the case studies 3:2 photographs and one portrait, here wide banners - so the band is a constant
    height and the picture is fitted inside it rather than filled into it. Nothing is ever cropped.
*/
.caf-gallery {
    --caf-gallery-height: 400px;
    position: relative;
    margin-block: var(--caf-space);
}

.caf-gallery__viewport {
    display: flex;
    gap: var(--caf-space);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    /* The row scrolls by drag, wheel and keyboard whatever happens here: the arrows are an addition to
       something that already works, which is the rule carousel.js was written to. */
    -webkit-overflow-scrolling: touch;
}

.caf-gallery--wired .caf-gallery__viewport { scrollbar-width: none; }
.caf-gallery--wired .caf-gallery__viewport::-webkit-scrollbar { display: none; }

.caf-gallery .caf-image--gallery {
    flex: 0 0 100%;
    display: block;
    width: auto;
    margin: 0;
    scroll-snap-align: start;
}

.caf-gallery .caf-image--gallery img {
    display: block;
    width: 100%;
    height: var(--caf-gallery-height);
    object-fit: contain;
}

/* Centred on the picture rather than on the box, because a slide carrying a caption is taller than one
   that does not and a gallery may hold both. */
.caf-gallery__arrow {
    position: absolute;
    top: calc(var(--caf-gallery-height) / 2);
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--caf-teal-dark);
    color: var(--caf-paper);
    cursor: pointer;
}

.caf-gallery__arrow:hover { background: var(--caf-orange); }
.caf-gallery__arrow--previous { left: var(--caf-space-small); }
.caf-gallery__arrow--next { right: var(--caf-space-small); }

.caf-gallery__arrow svg {
    width: 1.25rem;
    height: 1.25rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.5;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* A row that fits its slides has nothing to press. Hidden rather than removed, so a resize that makes
   the row scrollable again brings them back without rebuilding anything. */
.caf-gallery--idle .caf-gallery__arrow { display: none; }

@media (max-width: 767px) {
    .caf-gallery { --caf-gallery-height: 240px; }
    .caf-gallery__arrow { width: 2.25rem; height: 2.25rem; }
}

/* ---------------------------------------------------------------- video */

.caf-video { margin-block: var(--caf-space); }
.caf-video__frame { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; }
.caf-video__player { display: block; width: 100%; height: auto; background: #000; }

/* ---------------------------------------------------------------- testimonial */

.caf-testimonial {
    margin-block: var(--caf-space-large);
    padding-left: 1.25rem;
    border-left: 4px solid var(--caf-orange);
}
.caf-testimonial__quote { margin: 0; font-size: var(--caf-text-lead); }
.caf-testimonial__quote > :first-child { margin-top: 0; }
.caf-testimonial__quote > :last-child { margin-bottom: 0; }
.caf-testimonial__attribution { margin-top: 0.9rem; font-size: 0.95rem; }
.caf-testimonial__author { display: block; font-weight: 600; color: var(--caf-teal); }
.caf-testimonial__role,
.caf-testimonial__company { display: block; color: var(--caf-ink-muted); }

/* ---------------------------------------------------------------- social */

/* Each link is its own widget, so inline-block is what makes the run read as a row again. The pill is
   the fallback shape, for a link whose icon the media library does not hold - every "other" network by
   definition, since the client owns icons for four. */
.caf-social {
    display: inline-block;
    margin: 0 0.75rem 0.5rem 0;
    padding: 0.35rem 0.75rem;
    border: 1px solid currentColor;
    border-radius: 999px;
    text-decoration: none;
    font-size: var(--caf-text-small);
}
.caf-social:hover { background: var(--caf-teal); color: var(--caf-paper); }

/*
    THE TILE, and both halves of it are measured rather than chosen.

    The glyph is the CLIENT'S OWN - 2024/08/facebook-1.png and its three siblings, the same files their
    footer renders on every page - because Divi paints these from ETmodules, which is not ours to ship,
    and reproducing a platform's mark from memory is how a wrong one gets shipped. See SocialIcon.

    The tile behind it is not decoration. Sampled through a canvas, the imported files are 46%, 19% and
    13% transparent with every remaining pixel pure white: white glyphs, drawn for the dark footer they
    sit in. These rows sit on white, where the glyph alone would be invisible - the third time in this
    project that correct artwork on the wrong ground would have shipped as nothing at all.

    Geometry and colour from cafamerica.org/contact, computed: 60x60, radius 3px, and one brand colour
    per network - facebook rgb(59,89,152), twitter rgb(0,0,0), linkedin rgb(0,123,182), instagram
    rgb(234,44,89). Those are Divi's own per-network defaults, which is why they are the live values.
*/
.caf-social--tile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3.75rem;
    height: 3.75rem;
    margin: 0 0.5rem 0.5rem 0;
    padding: 0;
    border: 0;
    border-radius: 3px;
    background: var(--caf-social-tile, var(--caf-teal));
    transition: background var(--caf-transition);
}

.caf-social--tile:hover { background: var(--caf-teal); }
.caf-social__icon { width: 1.5rem; height: 1.5rem; object-fit: contain; }

.caf-social--facebook { --caf-social-tile: #3b5998; }
.caf-social--twitter { --caf-social-tile: #000000; }
.caf-social--linkedin { --caf-social-tile: #007bb6; }
.caf-social--instagram { --caf-social-tile: #ea2c59; }

/* ---------------------------------------------------------------- search box widget

   The module on /give-now - "Search our charity database" - and everything Divi's et_pb_search maps to.
   It owns .caf-search-widget__; the header owns .caf-search, the results page owns .caf-search-page__.
   Three components with one name is what this file used to have, and it is what flexed the results page
   into a row from a rule written for the header.

   THE BOX AND ITS BUTTON ARE ONE CONTROL, so there is no gap between them. Measured on
   cafamerica.org/give-now: the input's right edge and the SEARCH button's left edge are the same
   coordinate to the pixel - Divi's et_pb_searchform is one white field with the submit sitting flush
   inside its right end - and ours had 8px of page showing between them.

   The band behind it is NOT drawn here. On the live page the teal stripe and the orange block at its
   left end are the row's own background, which this project carries as the imported section's stored
   configuration - so the widget paints a field and a button and lets the page supply the ground it
   sits on. A widget that painted its own band would draw a second one inside the first.

   IT MUST NOT PAINT A BAND AND IT MUST NOT ASSUME ONE EITHER, which is the half this block had wrong.
   The field's ink, the field's edge and the loading line's colour were all written for /give-now's
   dark stripe, so the widget was legible on exactly one of the grounds it is offered on - and it is
   registered for every zone of every section on four content types. Each of the three now resolves
   correctly on a dark ground and a light one; see the field tokens at :root for the mechanism. */

.caf-search-widget {
    display: flex;
    flex-wrap: wrap;
    column-gap: 0;

    /* ROW-GAP 0, not 0.35rem. The gap was there for a wrap nobody had looked at: when the button drops
       to its own row it is still half of one control, and 5.6px of band showing between the field and
       the button is the same defect the column-gap above exists to prevent, turned ninety degrees.
       Flush below reads as one thing exactly as flush beside does. The loading line keeps its own
       margin-top, so nothing else closes up. */
    row-gap: 0;
    align-items: stretch;
}
.caf-search-widget__input {
    /* 11rem, DOWN FROM 18rem, AND THE BASIS IS THE WRAP THRESHOLD RATHER THAN A PREFERENCE. Flex wraps
       on base sizes before it shrinks anything, so this number alone decides when the button leaves the
       row - and 18rem (288px) put it on its own line in every three- and four-column section at every
       width, which is most of the places an editor can drop this widget.

       Measured against the only columns that exist, since the grid collapses to one below 981px. The
       button was read off the rendered page rather than estimated: 130px for SEARCH and 177px for
       RECHERCHER, so the control needs 306px in English and 353px in French at this basis. Against the
       real column widths - 2 columns are 371/454/580px at 981/1200/1536, 3 columns 235/287/367 and
       4 columns 166/203/260 - that is one row at one and two columns at every desktop width in BOTH
       languages, three columns only at the widest, and four never. No basis whatever fits four, so the
       control HAS a stacked state and the choice is only where it starts. 11rem is the smallest field
       worth typing into, which makes the rule sayable: one row wherever the field can be 11rem,
       stacked flush below that.

       NO max-width AND NO @media, deliberately. The basis adapts to the COLUMN, which is what a widget
       an editor can put in any zone needs and what a viewport query cannot express. */
    flex: 1 1 11rem;
    min-width: 0;
    padding: 0.6rem 0.9rem;

    /* A hairline rather than none. It was borderless because the band behind it on /give-now is dark,
       where a near-white box needs no help - but on a white section a borderless --caf-field-paper
       field is an orange SEARCH button standing next to nothing at all. --caf-rule is not remapped by
       any on-dark scope, so one edge serves both grounds, and it is the edge the header's own field
       already draws. box-sizing is border-box globally and the row is align-items: stretch, so it costs
       no height and the field and button stay the same height to the pixel. */
    border: 1px solid var(--caf-rule);
    font: inherit;

    /* The field tokens rather than --caf-ink and --caf-paper, and this is the fix for a defect that
       shipped: inside .caf-section__grid--on-dark - which /give-now's own section carries, because its
       gradient ends #0d393b - --caf-ink resolves to the paper colour and this field painted #fcfcfc on
       #fcfcfc. See the tokens' declaration at :root for why they are the right altitude. */
    color: var(--caf-field-ink);
    background: var(--caf-field-paper);
}

/* STATED RATHER THAN LEFT TO THE BROWSER, because the two engines disagree and one of them disagrees
   invisibly. Chrome paints ::placeholder its own `darkgray` from its UA sheet, as an independent
   declaration that never saw the remapped ink; Firefox uses currentColor at 54%, which took it. So the
   same page showed a faint placeholder in one and no placeholder at all in the other. opacity: 1 is
   needed as well as the colour - Firefox's UA rule sets 0.54 and a colour alone does not clear it. */
.caf-search-widget__input::placeholder {
    color: var(--caf-field-ink-muted);
    opacity: 1;
}

/* No chevron: a chevron means "this goes somewhere" in the migrated button vocabulary, which is what
   every converted link-button does and what a submit control does not - and the asymmetric right
   padding exists only to make room for it. */
.caf-search-widget__submit::after { content: none; }
/* Natural width, stated rather than inherited: when the button wraps it sits under the left edge of
   the field at its own size, which reads as a form. Growing it to the full width needs a flex-grow
   here against a far larger one on the field to stop it eating the free space when the two DO share a
   row - a magic number bought for a nicety. */
.caf-search-widget__submit { flex: 0 0 auto; padding-inline: 1.875rem; }

/* The loading line, which appears under the field while the results page is being fetched. flex-basis
   100% puts it on its own row below the control rather than squeezing the field. [hidden] is restated
   for the reason the results page's panel restates it: `display: flex` outranks the UA rule. */
.caf-search-widget__loading[hidden] { display: none; }
.caf-search-widget__loading {
    display: flex;
    flex-basis: 100%;
    gap: 0.5rem;
    align-items: center;
    margin: 0.5rem 0 0;

    /* --caf-ink, NOT --caf-paper, and it is the exact inverse of the field above it. This line IS text
       on the ground, so it is precisely what the on-dark scopes exist to lighten; hard-coding the paper
       colour opted it out of that mechanism and made "Searching..." white on white on every ground that
       is not dark. On /give-now the two resolve to the same colour, so this changes nothing a visitor
       sees there and everything on the white section an editor can place this widget in. */
    color: var(--caf-ink);
    font-size: var(--caf-text-small);
}
.caf-search-widget__loading-text { margin: 0; }

/* THE RESULTS ARE A LIGHT ISLAND, AND THE TOKENS HAVE TO SAY SO.

   Decision 205 moved the charity results off /search and into this widget, which on /give-now sits in
   .caf-section__grid--on-dark over the brand-split gradient. That scope lightens --caf-ink,
   --caf-ink-muted, --caf-teal, --caf-link and --caf-paper-alt so text stays legible on the dark band.
   A facet rail, a page of cards and a teal pager are not text on that band - they paint their own
   light grounds - so they were inheriting the lightened ink onto them: a white facet head under white
   text, a pager strip with white text on white.

   Re-declaring the five tokens from their :root aliases is the fix that does NOT list elements, which
   is the move .caf-section--on-dark's own comment forbids - a rule that names the elements will one
   day miss one, and this component has four nested blocks with their own grounds. See --caf-panel-*
   at :root for why the aliases are read through var() rather than retyped.

   The visible consequence is deliberate and was shown to the client rather than inferred: the results
   render as a white panel inside /give-now's orange-and-teal frame. That is the honest reading of
   "the results appear under the search box" when the search box is in a dark band. */
.caf-search-widget__results {
    --caf-ink: var(--caf-panel-ink);
    --caf-ink-muted: var(--caf-panel-ink-muted);
    --caf-teal: var(--caf-panel-teal);
    --caf-link: var(--caf-panel-link);
    --caf-paper-alt: var(--caf-panel-paper-alt);

    color: var(--caf-ink);
    background: var(--caf-paper);
    margin-top: var(--caf-space);
    padding: var(--caf-space);
}

/* The prose lines, twins of the results page's four. Named for this component rather than borrowed
   from .caf-search-page__, because borrowing that namespace is what the three-components-one-name bug
   above was - and .caf-search-page > :not(.caf-search-page__band) would cap this widget's children at
   the content measure inside a section that already has its own. */
.caf-search-widget__notice,
.caf-search-widget__empty { color: var(--caf-ink-muted); }

/* ---------------------------------------------------------------- search results page

   THE SHAPE IS cafamerica.org/?s=grant's, DRAWN IN THIS FILE'S OWN VOCABULARY, which is the bargain
   front-end.md strikes everywhere else: the design transfers and the code cannot. Read off the live
   page on 18 September 2026 - the full-bleed band, the "Search Result:" pills, two equal columns on
   All, the grey result panels, the "Filter by:" accordion and the pagination bar are all live's; the
   colours, type, spacing and buttons are this file's.

   EVERY CLASS HERE IS .caf-search-page__ OR .caf-charity/.caf-facet/.caf-pager, AND THAT IS DELIBERATE.
   The results page used to be class="caf-search", which is also the header widget's form, and the two
   blocks fought: a `display: flex` written for the header flexed the whole results page into a row
   until it was scoped under .caf-header. Two components with one name is the defect; this renames one
   of them rather than adding a third scope. The header block below keeps .caf-search to itself. */

/*
    THE PAGE'S OWN SHELL CONSTRAINS NOTHING, so the search band can run edge to edge.

    .caf-page > :not(.caf-section, .caf-body) caps a direct child at the content measure, which is
    right for an archive listing and wrong for this page: the live search band is a teal stripe the
    full width of the viewport with the field inside the container. So this root joins the exceptions
    and constrains its own children instead - the same division .caf-section / .caf-section__grid makes.
*/
.caf-search-page { width: 100%; }

.caf-search-page > :not(.caf-search-page__band) {
    width: min(90%, var(--caf-container));
    margin-inline: auto;
}

@media (min-width: 981px) {
    .caf-search-page > :not(.caf-search-page__band) { width: min(80%, var(--caf-container)); }
}

/* The band. Live draws an orange block at its left end too; that is the hero furniture of /give-now's
   search module rather than of the results page, and it is not reproduced on a page that has no hero. */
.caf-search-page__band {
    background: var(--caf-teal);
    padding-block: var(--caf-space);
    margin-bottom: var(--caf-space);
}

/*
    THE BOX AND ITS BUTTON ARE ONE CONTROL, so there is no gap between them. Measured on
    cafamerica.org/give-now: the input's right edge and the SEARCH button's left edge are the same
    coordinate to the pixel - Divi's et_pb_searchform is one white field with the submit sitting flush
    inside its right end - and ours had 8px of page showing between them.

    SHOW ALL is the exception and keeps its gap: on the live charities tab it is a separate grey button
    standing away from the field, not part of the control.
*/
.caf-search-page__form {
    display: flex;
    flex-wrap: wrap;
    column-gap: 0;
    row-gap: 0.5rem;
    align-items: stretch;
    width: min(90%, var(--caf-container));
    margin-inline: auto;
}

@media (min-width: 981px) {
    .caf-search-page__form { width: min(80%, var(--caf-container)); }
}

.caf-search-page__input {
    flex: 1 1 18rem;
    min-width: 0;
    padding: 0.6rem 0.9rem;
    border: 0;
    font: inherit;

    /* The field tokens. This one is NOT reachable by any of the five scopes that remap --caf-ink -
       the results page is a controller view, and .caf-search-page__band paints --caf-teal without
       remapping a token - so this is not a fix, it is one vocabulary. Written so the next reader does
       not have to work out which of this file's four fields were exempt and why. */
    color: var(--caf-field-ink);
    background: var(--caf-field-paper);
}

/*
    The search, facet and pager submits borrow .caf-button and are the one place it should not carry a
    chevron. A chevron means "this goes somewhere", which is what every migrated button does and what a
    submit control does not - and the asymmetric right padding exists only to make room for it.
*/
.caf-search-page__submit::after,
.caf-facets__apply::after,
.caf-facets__clear::after,
.caf-pager__go-button::after,
.caf-search-widget__show-all::after { content: none; }

.caf-search-page__submit { padding-inline: 1.875rem; }

/* SHOW ALL moved to the widget with the charity database on 16 October 2026 - it means "search with
   no keyword", and there is nothing on /search left to search with no keyword. It is a link rather
   than a submit, so it needs the chevron suppressed for the reason above and its own spacing here. */
.caf-search-widget__show-all { margin-left: 0.75rem; padding-inline: 1.25rem; }

/* A second button colour, for the controls live draws grey beside a red one - SHOW ALL and CLEAR ALL.
   Kept as a modifier on .caf-button so the site still has one button component. */
.caf-button--muted {
    background: var(--caf-paper-alt);
    color: var(--caf-teal);
    border: 1px solid var(--caf-rule);
}
.caf-button--muted:hover { background: var(--caf-rule); color: var(--caf-teal); }

.caf-search-page__prompt,
.caf-search-page__empty,
.caf-search-page__notice,
.caf-search-page__more { color: var(--caf-ink-muted); }
.caf-search-page__more { font-size: var(--caf-text-small); margin-top: var(--caf-space); }

/* THE TABS ARE PILLS AFTER A LABEL, which is what "Search Result: [All][Charities][CAF America's
   Website]" is on the live page - li.filter buttons, not an underlined tab strip. Server-rendered
   links, not a JavaScript tab control, so the active one is an anchor with aria-current. */
.caf-search-page__tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    margin-block: var(--caf-space);
}
.caf-search-page__tabs-label { font-weight: 600; margin-right: 0.25rem; }
.caf-search-page__tab {
    padding: 0.4rem 0.9rem;
    text-decoration: none;
    color: var(--caf-teal);
    background: var(--caf-paper-alt);
    border: 1px solid transparent;
}
.caf-search-page__tab:hover { color: var(--caf-orange); border-color: var(--caf-rule); }
.caf-search-page__tab--active {
    background: var(--caf-teal);
    color: var(--caf-paper);
    font-weight: 600;
}
.caf-search-page__tab--active:hover { color: var(--caf-paper); }

/*
    THE TWO-COLUMN All TAB WAS HERE AND IS GONE, with the tabs themselves, on 16 October 2026. It put
    the charity results and the website results side by side at 593px each in a 1217px row, measured on
    the live page. There is one list on this page now - the website's - so there is nothing to pair it
    with. .caf-search-col__heading and .caf-search-col__layout below are still used: the first by this
    page's own heading and by the widget's, the second by the widget alone.
*/
.caf-search-col__heading { font-size: 1.4rem; margin: 0 0 var(--caf-space); color: var(--caf-teal); }

/* The charity results: a facet rail beside the cards, collapsing to one column on a phone.
   The --unfaceted modifier went with the All tab - the rail renders whenever there are results now,
   because there is one view of the charity database rather than two. */
.caf-search-col__layout { display: grid; grid-template-columns: 1fr; gap: var(--caf-space-large); }

@media (min-width: 981px) {
    .caf-search-col__layout { grid-template-columns: 16rem 1fr; }
}

/* The sentence that replaced the Charities tab. It points at /give-now, where the charity database
   now lives, and it renders on the bare landing page as well as over results - a visitor who has
   typed nothing is the one most likely to want the other search. */
.caf-search-page__invite { margin-block: var(--caf-space); color: var(--caf-ink-muted); }

/* The count line, which came back with the pager. It was dropped when this column showed five results
   and offered no way to reach a sixth, where a total above five of them would have been a worse lie
   than no total at all. */
.caf-search-page__count { margin: 0 0 var(--caf-space); font-size: var(--caf-text-small); color: var(--caf-ink-muted); }

/* ---- the loading state, WHICH MOVED TO THE WIDGET WITH THE DATABASE THAT NEEDED IT

   This page used to wait on the external charity database - 28.5 seconds when that was first measured
   and about 4.5 after the query was rewritten - and a control that looks inert for that long gets
   clicked again. It waits on nothing now: the website index is in memory behind IProgressiveCache and
   answers in milliseconds, so a spinner here would flash and be a distraction rather than an
   explanation. The rules live on .caf-search-widget__ instead, where the wait went.

   The [hidden] restatement went with them and is the half worth repeating here, because it shipped
   broken once: `display: flex` outranks the UA stylesheet's `[hidden] { display: none }`, so without
   an explicit rule the spinner and the word "Searching..." sit on the page from the moment it loads -
   precisely the lie the component exists to avoid telling. Caught by looking; every structural check
   passed. See .caf-search-widget__loading[hidden]. */

/* The stale results stay on screen and go quiet, rather than being blanked. Live replaces its list
   with the spinner because it has nothing else to show; a navigating page still has the last answer,
   and keeping it is the difference between "working" and "gone". */
.caf-search-widget-page[data-loading] .caf-search-widget__results {
    opacity: 0.45;
    pointer-events: none;
}

/*
    DRAWN IN CSS, NOT SET AS AN ICON. The live spinner is FontAwesome's fa-refresh fa-spin, and
    Elegant Themes' and FontAwesome's icon artwork is deliberately absent from this project - the same
    reason the buttons' chevron is two borders rather than Divi's icon character. A rotating ring off a
    transparent border costs nothing and needs no font.
*/
.caf-spinner {
    display: inline-block;
    width: 1.75rem;
    height: 1.75rem;
    border: 3px solid var(--caf-rule);
    border-top-color: var(--caf-orange);
    border-radius: 50%;
    animation: caf-spin 0.8s linear infinite;
}

@keyframes caf-spin { to { transform: rotate(360deg); } }

/* The small ring, which the search box widget's loading line asks for. IT LIVES HERE, AFTER THE BASE
   RULE, AND THE MOVE IS THE FIX RATHER THAN THE TIDYING.

   It was written 200 lines above .caf-spinner, inside the widget's own block, so the base rule's
   `border: 3px solid var(--caf-rule)` shorthand and its 1.75rem box came LATER at the same specificity
   and won every declaration in it: the "small" spinner rendered at full size and 3px beside 15px text,
   and the rgba(255,255,255,0.4) ring it declared for a dark band never painted once. A modifier that
   loses to the thing it modifies is the dormant-rule failure in a second shape - the rule matched, and
   nothing it said survived the cascade.

   The colour is simply the base's --caf-rule now, which no on-dark scope remaps, so the ring reads on
   the dark band this widget was drawn for AND on a white section. */
.caf-spinner--small { width: 1.1rem; height: 1.1rem; border-width: 2px; }

/* A spinner is decoration for anyone who has asked not to be moved; the word "Searching..." beside it
   carries the meaning, so the ring simply stops. */
@media (prefers-reduced-motion: reduce) {
    .caf-spinner { animation: none; border-top-color: var(--caf-rule); }
}

/* ---- the facet panel */

.caf-facets { align-self: start; font-size: var(--caf-text-small); }
.caf-facets__head {
    background: var(--caf-teal);
    color: var(--caf-paper);
    padding: 0.6rem 0.9rem;
}
.caf-facets__title { margin: 0; font-size: 1rem; color: inherit; }

/* The values already chosen, each with its own ×. Live puts these at the top of the panel, above the
   groups, which is the only place a visitor can see at a glance what is narrowing the list. */
.caf-facets__chosen { list-style: none; margin: 0.5rem 0 0; padding: 0; display: grid; gap: 0.25rem; }
.caf-facets__chosen-item { display: flex; gap: 0.5rem; align-items: baseline; text-transform: capitalize; }
.caf-facets__chosen-name { flex: 1; }
.caf-facets__remove { color: var(--caf-paper); text-decoration: none; font-size: 1.1rem; line-height: 1; }
.caf-facets__remove:hover { color: var(--caf-orange); }

/* <details> rather than a scripted accordion, which is what Bootstrap's collapse.js is doing on live.
   list-style and ::-webkit-details-marker both, because the triangle is drawn by different mechanisms
   in different engines and one of them alone leaves it showing - the same note the header's disclosure
   carries. */
.caf-facet { border-bottom: 1px solid var(--caf-rule); }
.caf-facet__summary {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.6rem 0.9rem;
    font-weight: 600;
    color: var(--caf-teal);
    background: var(--caf-paper-alt);
    cursor: pointer;
    list-style: none;
}
.caf-facet__summary::-webkit-details-marker { display: none; }
.caf-facet__summary:hover { color: var(--caf-orange); }

/* The +/− the live headings carry, drawn from the element's own state rather than from a class the
   script would have to keep in step. */
.caf-facet__summary::after { content: "+"; font-weight: 400; font-size: 1.1rem; line-height: 1; }
.caf-facet[open] > .caf-facet__summary::after { content: "\2212"; }

.caf-facet__items {
    list-style: none;
    margin: 0;
    padding: 0.5rem 0.9rem;
    max-height: 14rem;
    overflow-y: auto;
}
.caf-facet__label {
    display: flex;
    gap: 0.4rem;
    align-items: baseline;
    padding: 0.15rem 0;
    cursor: pointer;

    /* The stored values are lower-cased - "north america", "europe" - and the live panel capitalises
       them in CSS rather than in the data. Reproduced here for the same reason: the value has to go
       back to the database exactly as it came out, so it cannot be title-cased on the way in. */
    text-transform: capitalize;
}
.caf-facet__name { flex: 1; }
.caf-facet__count { color: var(--caf-ink-muted); font-variant-numeric: tabular-nums; }

.caf-facets__actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: var(--caf-space); }
.caf-facets__apply,
.caf-facets__clear { padding-inline: 1.25rem; }

/* ---- the pagination bar

   Live draws this as a teal strip above the cards and again below them, carrying two arrows, a
   sentence and a box to type a page into: paginationjs with showPageNumbers false, showNavigator,
   showGoInput and showGoButton. Views/Search/_CharityPager.cshtml is that configuration in markup. */

/*
    SCOPED TO THE SEARCH PAGE, because .caf-pager was already taken. The archive pager - the
    "Older Entries" row under a listing container - has owned that block name since it was built,
    and this rule is later in the file, so it won: every archive pager became a teal strip with a
    teal link on it. INVISIBLE TEXT, on /story on both channels and /fr/story-of-impact-fr.

    Found by --visual-sweep on 22 September 2026 as 6 "same-colour" findings, which is the check
    written for exactly this and which read zero on 17 September - the day before this block
    arrived. Neither pager changed; the stylesheet did.

    Only the bare .caf-pager selector collided. The element classes below are the charity pager's
    own - __arrows, __arrow, __count, __go - where the archive pager uses __position, __newer and
    __older, so they are left unscoped. ADDING ONE OF THOSE NAMES TO THE ARCHIVE PAGER WOULD BRING
    THIS BACK.

    THE SECOND SELECTOR IS THE CHARITY PAGER'S NEW HOME, added 16 October 2026 with decision 205.
    The charity results moved from /search into the CAF.Search widget, so the pager that sits above
    and below them is no longer inside .caf-search-page - and with only the first selector it fell
    through to the archive pager's rule above: border-top, space-between, no teal, silently losing
    its design on the one page that has it. The scoping that fixed one bug would have caused another
    the moment the markup moved, which is the cost of scoping by ancestor rather than by modifier.
*/
.caf-search-page .caf-pager,
.caf-search-widget__results .caf-pager {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: center;
    padding: 0.6rem 0.9rem;
    margin-block: var(--caf-space);
    background: var(--caf-teal);
    color: var(--caf-paper);
    font-size: var(--caf-text-small);
}
.caf-pager__arrows { display: flex; gap: 0.25rem; }
.caf-pager__arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.75rem;
    padding: 0.15rem 0.4rem;
    background: var(--caf-orange);
    color: var(--caf-paper);
    text-decoration: none;
    line-height: 1.4;
}
.caf-pager__arrow:hover { background: var(--caf-paper); color: var(--caf-teal); }

/* An arrow with nowhere to go is shown and inert rather than removed, so the bar does not change width
   between page one and page two. */
.caf-pager__arrow--off { background: var(--caf-rule); color: var(--caf-ink-muted); cursor: default; }

.caf-pager__count { margin: 0; flex: 1 1 auto; }
.caf-pager__go { display: flex; gap: 0.4rem; align-items: center; }
.caf-pager__go-label { display: flex; gap: 0.4rem; align-items: center; }
.caf-pager__go-input {
    width: 4rem;
    padding: 0.2rem 0.4rem;
    border: 0;
    font: inherit;
    font-size: var(--caf-text-small);
    color: var(--caf-ink);
    background: var(--caf-paper);
}
.caf-pager__go-button { padding: 0.2rem 0.75rem; font-size: var(--caf-text-small); }

/* ---- the site results */

.caf-search-results { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--caf-space); }

/* A GREY PANEL PER RESULT, which is what the live card is - #eee with padding, no rule and no border.
   Both columns use it, so a charity and a page read as the same kind of object. */
.caf-search-result,
.caf-charity {
    background: var(--caf-paper-alt);
    padding: var(--caf-space);
}

.caf-search-result__title { margin: 0 0 0.35rem; font-size: 1.25rem; }
.caf-search-result__title a { text-decoration: none; }
.caf-search-result__title a:hover { text-decoration: underline; }

/* "August 20, 2024 | PAGE | Reports" - date, post type and category on one line with a pipe between
   them, which is every live card's meta line. The separator is drawn by ::before on the parts after
   the first, the same way the listing cards do it, so a missing date or a missing category cannot
   leave a stray pipe. */
.caf-search-result__meta { margin: 0; font-size: var(--caf-text-small); color: var(--caf-ink-muted); }
.caf-search-result__meta > * + *::before { content: " | "; }
.caf-search-result__snippet { margin: 0.5rem 0 0; }

/* What matched, marked as the live site marks it - the live card wraps it in a span and bolds it,
   which is legible inside a heading and invisible inside body copy, so this keeps the background it
   already had and adds the weight only where the live card has it. */
.caf-search__match { background: var(--caf-orange-pale); }
.caf-search-result__title .caf-search__match { background: none; font-weight: 700; }

/* ---- the charity cards */

.caf-charities { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--caf-space); }
.caf-charity__name { margin: 0; font-size: 1.2rem; text-transform: uppercase; }
.caf-charity__name a { text-decoration: none; }
.caf-charity__name a:hover { text-decoration: underline; }

/* The topics, bold, between the name and the address - #cafa-org-template puts a bare <strong> there
   and nothing else, which is a row this card used to print below the address instead. */
.caf-charity__topics { margin: 0.35rem 0 0; }

/*
    THE ADDRESS, ONE LINE PER PART. The live card renders street, city, state and postal code as four
    lines inside an <address>, in the body serif and ITALIC - measured on cafamerica.org's ?s=grant card
    for 1 FARM OUTREACH INC. Ours showed "GRANT, NE" and nothing else, because the view used two of the
    five columns it was already selecting; phone and fax were the same omission one level down.

    The italic is theirs and is kept: it is the one thing separating the address from the body copy
    around it. font-style is set explicitly rather than left to the browser's default for <address>,
    because that default is exactly what a reset removes.
*/
.caf-charity__address {
    margin: 0.35rem 0 0;
    font-family: var(--caf-font-serif);
    font-style: italic;
    color: var(--caf-ink-muted);
    line-height: var(--caf-line);
}
.caf-charity__address abbr { margin-right: 0.25rem; text-decoration: none; }

.caf-charity__foot {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: center;
    justify-content: space-between;
    margin: var(--caf-space) 0 0;
}

/* The regulator that vouched for the charity. Live right-aligns it opposite DONATE NOW in plain body
   text - not a badge, which is what this used to draw, with six labels that were all guesses. */
.caf-charity__source { font-size: var(--caf-text-small); color: var(--caf-ink-muted); text-align: right; }

/*
    DONATE NOW, borrowing .caf-button so the site has one button and not two. The live control is its own
    `.caf-buttn`: #ff3b21, white, 17px weight 400, padding 5px 15px, square, uppercase. Ours is the
    migrated filled button - the same colour and the same square corner, at this file's own 18px/600 and
    its own padding - so it reads as the same component as every other button on the site rather than as
    a reproduction of one page's CSS.

    No chevron, for the reason the search submit has none: a chevron means "this goes somewhere" in the
    migrated vocabulary, and while this DOES leave the site, the asymmetric right padding that makes room
    for it is the live control's one clear difference from a link.
*/
.caf-charity__give::after { content: none; }
.caf-charity__give { padding-inline: 1.25rem; }

/* ---------------------------------------------------------------- form */

.caf-form { max-width: 42rem; }
/* Kentico's own Form widget, styled to match the custom renderer above.

   The widget emits its own class names - form-control on every input, control-label on every label,
   editing-form-value-cell around each field. Scoped to .caf-form, the wrapper the placement widget
   emits, so these class names - which are generic - cannot leak into anything else.

   THESE ARE A FRAMEWORK CONTRACT, NOT DEAD RULES, and that is worth saying because they look exactly
   like dead rules: form-control, control-label, editing-form-value-cell, ktc-radio, ktc-checkbox,
   field-validation-error and form-widget-display-text appear in no .cshtml or .cs file in this
   repository, because Kentico emits them at runtime. A cross-reference of selectors against the source
   tree finds every one of them and is wrong about every one of them. Deleting them is how this
   section's whole appearance disappears. */
.caf-form form { max-width: 42rem; }
.caf-form .form-field,
.caf-form .editing-form-value-cell { margin-bottom: 1.25rem; }
.caf-form .control-label { display: block; margin-bottom: 0.35rem; font-weight: 600; }

/* THE ASTERISK ON A REQUIRED FIELD, added 16 October 2026.

   The class is put on the label by CAF.Forms.RequiredFieldMarkup, from Kentico's own
   FormFieldRenderingConfiguration event, for every field whose stored definition says it is required.
   Before this, required was enforced on the server and said nothing on the page: a visitor filled in
   eighteen fields and found out on submit.

   Orange rather than the live site's red, because this project has one attention colour and the
   old custom renderer already marked a missed field in it. */
.caf-form .control-label.caf-form-required::after {
    content: " *";
    color: var(--caf-orange);
    font-weight: 700;
}

.caf-form input[type="text"].form-control,
.caf-form input[type="email"].form-control,
.caf-form input[type="tel"].form-control,
.caf-form input[type="number"].form-control,
.caf-form textarea.form-control,
.caf-form select.form-control {
    width: 100%;
    padding: 0.65rem 0.75rem;
    border: 1px solid var(--caf-rule);

    /* The field tokens, for the reason their declaration gives. This exposure is LATENT rather than
       live - all 28 Form placements sit in sections with no background today - but it is the same two
       declarations that made the search box unreadable, and this one is worse where it lands: the
       border is --caf-rule, which no scope remaps, so a form on a teal band shows a correctly outlined
       white field that a visitor cannot read their own typing in. Changes nothing on any current page,
       because outside an on-dark scope these resolve to the values that were here. */
    background: var(--caf-field-paper);
    font: inherit;
    color: var(--caf-field-ink);
}

/* --caf-teal is remapped to the paper colour by every on-dark scope, so the focus ring went white on a
   white field - the same family as the ink above, and invisible for the same reason. --caf-orange is
   what the site-wide :focus-visible rule already uses, and its comment gives the reason this one
   needed: inside a dark band the orange is the one palette colour that holds against both the teal and
   the paper. So this rule now only differs from the global one in its offset. */
.caf-form .form-control:focus { outline: 2px solid var(--caf-orange); outline-offset: 1px; }

/* A checkbox or radio must not stretch to the full width its text inputs use. */
.caf-form input[type="checkbox"].form-control,
.caf-form input[type="radio"].form-control {
    width: auto;
    margin-right: 0.5rem;
}

/* One option per line. Kentico wraps each option in a SPAN - span.ktc-radio-list > span.ktc-radio -
   which is inline, so options run together into a paragraph. On short options that is merely untidy.
   On the KYC forms' Authorization field it is a defect: the two options are "I agree to Privacy
   Policy/Terms of Conditions including verification of my identity with third parties" and a
   60-word "I do not agree...", and inline they read as one continuous sentence with a stray radio
   button in the middle of it. A person consenting to third-party identity verification has to be able
   to see where one choice ends and the other begins. Found by looking at the rendered form, after the
   field counts and the labels had all passed. */
.caf-form .ktc-radio,
.caf-form .ktc-checkbox {
    display: block;
    margin-bottom: 0.4rem;
}

.caf-form .ktc-radio > label,
.caf-form .ktc-checkbox > label {
    display: inline;
    font-weight: 400;
}

/* The submit label is the client's own wording and one of them is 32 characters long, so the button
   has to be allowed to wrap and to shrink. SUBMIT YOUR GRANT RECOMMENDATION measures 319px of text
   plus 51px of padding, which is wider than a 360px phone: at that width the whole page scrolled
   sideways, and --visual-sweep named the input as the outermost element sticking out.

   white-space DOES work on an input in Chrome - measured on the page itself, 48px tall on one line
   becoming 99px on three at a 200px cap - which is what makes the pair enough. max-width alone would
   fit the box and clip the label, since an input crops its value rather than reflowing it. */
.caf-form input[type="submit"] {
    max-width: 100%;
    padding: 0.7rem 1.6rem;
    border: 0;
    background: var(--caf-orange);
    color: var(--caf-paper);
    font: inherit;
    font-weight: 600;
    white-space: normal;
    cursor: pointer;
}

.caf-form .field-validation-error { display: block; margin-top: 0.35rem; color: var(--caf-orange); }

/* Kentico renders its own after-submit message in place of the form. */
.caf-form .form-widget-display-text { font-weight: 600; }

/* ---------------------------------------------------------------- staff */

.caf-staff__header { padding: var(--caf-space-large) 0 1rem; border-bottom: 1px solid var(--caf-rule); }
.caf-staff__name { margin: 0; font-size: 2.25rem; }
.caf-staff__position { margin: 0.4rem 0 0; font-size: 1.1rem; color: var(--caf-ink-muted); }

.caf-staff__bio { margin-block: var(--caf-space-large); }

/*
    The generated "2024 - All Staff" template, measured against cafamerica.org/staff/andras-kosaras at a
    2048px viewport. Divi keeps this template's type and spacing in module settings - the section's
    custom_padding, the heading's size, the text module's italic 30px - and the generated partial carries
    structure rather than module typography, so the values are set here under the staff scope.

    Live: section padding 50px, the row's own 16px above its columns, so the content starts 66px under
    the header; the image fills its quarter column; the title is Outfit 54px at 500 in the source's own
    case with 10px beneath it; the position is Source Serif italic 30px on a 27.2px line with 15px
    beneath it; the biography follows at the column's full width.
*/
/* The wrapper is a direct child of .caf-page, which gives every such child the page measure - the row
   inside already carries one, and taking it twice made a 1300px row 1040px. */
.caf-page > .caf-staff { width: auto; margin-inline: 0; }

/* Less the page's own padding, which .caf-page adds above and below every template. */
.caf-staff .caf-body__section {
    margin-block: 0;
    padding-block: calc(66px - var(--caf-space)) calc(50px - var(--caf-space));
}
.caf-staff .caf-body__featured-image { display: block; width: 100%; }

.caf-staff .caf-body__title {
    margin: 0;
    padding-bottom: 10px;
    font-size: clamp(2.25rem, 4vw, 3.375rem);
    font-weight: 500;
    line-height: 1;
    text-transform: none;
}

.caf-staff .caf-body__text:has(.caf-body__meta--positiontitle) { margin-bottom: 15px; }
.caf-staff .caf-body__text:has(.caf-body__meta--positiontitle) p { margin: 0; }
.caf-staff .caf-body__meta--positiontitle {
    display: block;
    font-size: clamp(1.4rem, 2.5vw, 1.875rem);
    font-style: italic;
    line-height: 0.9;
}

/*
    The biography is the page's own Page Builder area, whose sections carry the page measure and band
    padding - right on a page, and a second indent inside a quarter-and-three-quarter row. Divi's
    post_content module sits flush in its column, so the nested section does too.
*/
.caf-staff .caf-body__column .caf-section { padding-block: 0; }
.caf-staff .caf-body__column .caf-section__grid { width: auto; margin-inline: 0; }

/* ------------------------------------------------- layout background colours */

/*
    Divi keeps a panel's colour in a section, row or column SETTING rather than in a stylesheet, and the
    converted layouts - header, footer and body - carry 68 of them across the two sites. Nothing read
    any of them until the header was built, which went unnoticed because the footer paints itself teal
    from this stylesheet and happened to agree with what its sections declared.

    The header is where the two disagreed. Both sites put the logo in a column declaring #FF3B21 and the
    file is CAF-America-logo-CMYK-White.png - a white logo drawn for that orange panel - so dropping the
    colour rendered it white on the near-white page: present, correct and invisible. Third time in this
    project that a missing background has produced a page passing every structural check and looking
    wrong, after the 148 blank Divi columns and the teal-on-teal darkGreenBox, and all three were found
    by looking at the page rather than by measuring it.

    One class for every prefix, because the rule does not vary by which layout it came from. A fully
    transparent value never reaches here - see LayoutRenderer.Background.
*/
.caf-tinted { background-color: var(--caf-background-color); }

/*
    The picture a converted layout's container carries as a SETTING. Read from 11 September 2026; before
    that LayoutRenderer read the colour and not the image, so the article template's own
    .caf-body__column.bgImage - a column named after the thing it holds - rendered as a hole beside the
    heading on EVERY article. Found by the visual sweep's first real run, which reported it on page
    after page; one such page reads as an odd page, forty reads as a mechanism.

    A min-height for the same reason the page sections have one: a column whose only content is its
    background has nothing to give it a height once the grid collapses.
*/
.caf-backdrop {
    background-image: var(--caf-background);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}

/*
    :empty IS NOT "HOLDS NOTHING", and this rule did nothing at all until 11 September 2026.

    A backdrop column is generated as an open tag, a newline and a close tag, and :empty does not match
    an element containing a text node - whitespace included - in Chrome 153, which is where this was
    measured. So the min-height never applied, and since the column's only content is a background
    image it has no intrinsic height: at the two-column width the text beside it held the row open and
    hid that, and BELOW 981px, WHERE THE GRID STACKS, THE BANNER PHOTOGRAPH OF EVERY ARTICLE ON BOTH
    SITES RENDERED 0px TALL. Measured on /blog/one-year-of-the-global-relief-navigator by collapsing
    its row: 182px beside the text, 0 stacked.

    The visual sweep cannot see this one - a zone 0px tall is below the 80px floor blank-zone starts
    at, and a picture that is absent because its box has no height looks, to every structural check,
    exactly like a column doing what it was told. It is the fourth dormant rule in this stylesheet, and
    the third that was wrong the day it first mattered.

    :not(:has(*)) is the test that means what :empty was written to mean here - no ELEMENT inside -
    and it is what the generated column actually is.
*/
.caf-backdrop:not(:has(*)) { min-height: 18rem; }

/*
    And where there is no picture to paint, the column must not hold the space open.

    An article with no featured image resolves the dynamic background to nothing, so its column holds
    neither text nor picture: half of the page header, blank, on three articles across the two sites.
    The renderer names that case - caf-backdrop--none, written where it knows the answer - rather than
    leaving the stylesheet to infer it from emptiness, which is the trap the rule above records.

    The grid track comes from the ROW, so a column cannot withdraw from one on its own: the row has to
    stop dealing a second track, which is what :has does here.

    It sets grid-template-columns rather than --caf-columns, and that is the difference between working
    and not: the row writes --caf-columns INLINE, which no stylesheet rule can outrank without
    !important. Overriding the property the custom property feeds needs neither, because the selector
    carrying :has is more specific than the .caf-body__row rule that reads it. Measured before the
    change: the column was hidden and the row still dealt 528px to it.
*/
.caf-body__row:has(> .caf-backdrop--none) { grid-template-columns: 1fr; }
.caf-backdrop--none { display: none; }

/*
    Painting a dark panel without lightening its text is not half the job, it is a worse page than not
    painting it at all - the article body's teal column carried near-black text on dark teal for exactly
    one build. The threshold is CssColor's, the same one the page sections use, and this redefines the
    tokens rather than listing elements for the reason .caf-section--on-dark's comment gives: listing
    them means missing one.
*/
.caf-tinted--on-dark {
    --caf-ink: var(--caf-paper);
    --caf-ink-muted: var(--caf-ink-muted-on-dark);
    --caf-teal: var(--caf-paper);

    /* Body links, for the reason .caf-section--on-dark gives. */
    --caf-link: var(--caf-paper);
    --caf-paper-alt: rgba(255, 255, 255, 0.12);
    color: var(--caf-ink);
}

/* ---------------------------------------------------------------- header */

/*
    The site header, converted from the export's own Divi Theme Builder layout.

    Its navigation renders. It did not for most of this project - a Divi header references its menus
    by id and no export carried the items until round 8 delivered menus.json on 27 August 2026,
    closing K2. Worth keeping because of what happened next: the .caf-nav rules below had been
    written dormant against markup nothing emitted, and they were WRONG the day they started
    matching - they flattened three levels into one row, a 430px sitemap in the header of every page.
    That is the second dormant-rule failure in this file after .darkGreenBox, and the comment that
    stood here had named the trap without avoiding it. They have been rewritten; see the navigation
    block.

    Divi puts the logo in the THIRD column of a 3_5,1_5,1_5 row on both sites, with the menu first, so
    the rendered order is menu, search, logo. That is reproduced rather than corrected - it is the
    structure the client authored, and the row uses the same --caf-columns custom property every other
    converted row does, so it collapses on a narrow screen like the rest of the site.
*/

.caf-header {
    /* NO INLINE PADDING, for the reason the footer has none: the band spans the viewport and the row
       carries the measure. Live's header row is width="100%" max_width="100%" and runs edge to edge -
       its .headMainMenu starts at x=0 and its logo panel ends at the viewport's right edge - where 24px
       here held both 24px inside, so the orange block never touched the edge. */
    padding: 0;

    /* WHITE, and measured rather than chosen: live's #mainHeader computes rgb(255,255,255) while the
       header element around it is transparent. Ours painted --caf-paper (#fcfcfc) with a 1px --caf-rule
       underneath, and production has neither the tint nor the rule - its separation from the page comes
       from the logo block alone. The background stays on this element rather than moving inward to
       .caf-header__section, because this is the one that spans the viewport and the one that is stuck:
       a sticky header with a transparent strip either side would show the page sliding under it. */
    background: var(--caf-paper);

    /* Divi sets sticky_position="top" on the header section of both sites. */
    position: sticky;
    top: 0;
    z-index: 100;
}

/*
    A link to a #section lands below the sticky header rather than under it. The menus' "Who We Serve"
    and "Our Services" links are the reason (decision 135): with no padding, /what-we-do#services put
    the section's top at 0, behind the header, and its heading out of sight. The values are the taller
    of the two sites' headers, measured on /what-we-do: 187px on America and 202px on Canada up to
    980px, where the menu stacks. Above it the value is --caf-header-height itself, which is the whole
    point of the token - the desktop figure used to be 5.5625rem, hand-copied from a header whose own
    height came from the export, and the two could drift apart without anything noticing.
    It also keeps an element focused from the keyboard clear of the header.
*/
html { scroll-padding-top: 12.625rem; }

@media (min-width: 981px) {
    html { scroll-padding-top: var(--caf-header-height); }
}
/* The SECTION is the band and the ROW is the measure, the same arrangement as the footer and the page
   sections. The cap that used to be here is on the row, from the row's own declaration. */
.caf-header__section { max-width: none; margin: 0; }
.caf-header__row {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--caf-space);
    align-items: center;

    /* margin-block: 0.75rem was here and is gone - 24px of header height that production does not have
       and the export does not declare. The height is --caf-header-height now, set on this row in the
       desktop block below. It used to be whatever max_height the export had put on the one logo <img>,
       which is how a generated partial came to decide the chrome of every page. */
}
.caf-header__column {
    display: flex;
    align-items: center;
    gap: var(--caf-space);

    /* NO min-width: 0 HERE, and the reason is the point.

       A grid item's automatic minimum size is its min-content, so `1fr` is really `minmax(auto, 1fr)`
       and a column cannot shrink below what it holds. The header declares `3fr 1fr 1fr` - the export's
       own 3_5,1_5,1_5 - and resolves to 526 / 388 / 175 of 1089px, which is 48/36/16 against the
       60/20/20 it asks for and against production's 58/20/20.

       min-width: 0 was added on 15 September 2026 and taken out the same hour. It makes the fractions
       resolve exactly - 653 / 218 / 218 - and then the middle column's contents do not fit in 218px:
       the Login/Subscribe list wraps to two lines and overflows LEFT across the main navigation, and
       the search form renders 287px wide inside a 218px track. The sweep did not catch it because
       nothing scrolls sideways; a style probe of the column's own children did.

       It does not fit because production does not ask it to. Live's middle column is 185px and holds
       the same menu plus a search ICON; ours holds the same menu plus a 207px text input, which is the
       open design question in front-end.md. Until that is settled the column has to take the width its
       contents need, and the declared fractions cannot be honoured. This is one decision with two
       halves, not two independent fixes - which is how it was first written up, wrongly. */
}
.caf-header__image { max-width: 100%; height: auto; }
.caf-header__image-link { display: inline-flex; align-items: center; }

/* THE ORANGE IS THE MARK'S PANEL, NOT THE COLUMN, and this is the one change here about the brand
   rather than about spacing. Both exports paint --caf-background-color on this COLUMN, so the #ff3b21
   block ran the full width of its track: 222x65 of a colour the brand quick reference says to use
   sparingly, and whose stated preferred logo is the green one. The background moves onto the link -
   the mark's own box - and the block goes to roughly 116x80. Still the corner block live draws, still
   reaching the viewport edge, with about a third less of it.

   align-items: stretch so the panel is the full height of the band and keeps that corner-block read.
   The column's own align-items: center would leave it floating with white above and below, which is a
   button rather than a lockup.

   justify-content: flex-end rather than center, and the reason is the viewport edge. This is the last
   column and it runs to the edge; once the panel is narrower than its track, centring it would pull
   the orange off that edge and leave a white margin live does not have. The MARK is still centred,
   from .caf-header__image-link's own align-items.

   The old note here said the vertical padding had to be zero because live's logo column is 65px. That
   was true and is superseded: the band is --caf-header-height and the mark is sized to sit inside it,
   so neither one depends on the other any more. */
/* CENTRED IN ITS COLUMN, from the module's own menu_style="inline_centered_logo" - which both sites
   declare on their main menu and this file left-aligned. margin-inline: auto rather than
   justify-content on the column, because the column is a flex container that may hold more than this
   one child and centring the container would move whatever else is in it.

   It shows at width. At 1185px live's list is fractionally wider than its column and sits at x=-8, so
   centred and left-aligned look the same; at 1521px live's first item starts about 90px in and ours
   started hard against the edge. */
.caf-header .caf-nav--center { margin-inline: auto; }

.caf-header .headLogo { background: none; justify-content: flex-end; align-items: stretch; align-self: stretch; padding: 0; }
.caf-header .headLogo .caf-header__image-link { background-color: var(--caf-background-color); padding-inline: var(--caf-space); }
/* THE MIDDLE COLUMN WRAPS, WHICH IS HOW LIVE KEEPS IT NARROW. Measured at 1185px before and after:
   live's .headSearch is 185px and ours was 294px, and the 109px came straight off the main menu - 633px
   against live's 685px - which was enough to wrap six menu items onto two rows where live holds one.
   Our links are the same 127px as live's, so the wrapping was purely the width it was left.

   Live does not fit three controls in 185px by making them smaller. It WRAPS: on cafcanada.ca the
   magnifier sits on a second line under SUBSCRIBE and ENGLISH, which is why that column measures 55px
   tall against the row's 80px. A flex row that refuses to wrap sets its column's min-content to the sum
   of its children; one that wraps sets it to the widest single child. That is the whole difference, and
   it is also why min-width: 0 could not be made to work here on 15 September - the contents genuinely
   did not fit, because nothing let them wrap. */
.caf-header .headSearch {
    justify-content: flex-end;
    flex-wrap: wrap;
    row-gap: 0;

    /* TIGHTER THAN THE ROW'S GAP, AND IT DECIDES HOW MANY LINES THIS COLUMN TAKES. Once the row's
       tracks became Divi's own percentages this column is exactly live's 185px at a 1185px viewport,
       and at 24px apart its three controls need 229px for the first two and 194px for the last two -
       so all three wrapped onto separate lines and the header stood at 96px against live's 80px. At
       8px the switcher and the search icon share a line (130 + 8 + 40 = 178 in 185) and the column
       takes two lines, which is what live's takes: SUBSCRIBE and ENGLISH above, magnifier below. */
    column-gap: 0.5rem;
}

@media (min-width: 981px) {
    .caf-header__row { grid-template-columns: var(--caf-columns, 1fr); column-gap: var(--caf-gutter, var(--caf-space)); }

    /* THE BAND IS A HEIGHT NOW, NOT A CONSEQUENCE. min-height rather than height, so a menu that
       wraps to two lines still grows the row the way it always did - this sets a floor, not a cap.

       And the mark is sized here rather than left at whatever the export declared. height wins over
       the inline max-height because 44px is below both of them (65px America, 60px Canada), so no
       !important is needed and neither generated partial is touched. Canada's <img> also carries 10px
       of inline padding with box-sizing: content-box, which CSS cannot reach without one, so its
       panel runs about 20px larger than America's. Each header reads correctly on its own; taking
       those two declarations out of the generator is the root fix and is written up in
       site-furniture.md. */
    .caf-header__row { min-height: var(--caf-header-height); }
    .caf-header .headLogo .caf-header__image { height: 2.75rem; width: auto; }

    /* A wrapped menu gets no vertical gutter. .caf-nav__list sets `gap: var(--caf-space)`, which is
       24px on BOTH axes, and 24px between menu items across is right where 24px between wrapped rows
       of them is not - live's Canada menu wraps to two lines in 54px and ours took 92px for the same
       two lines. Canada's header is the only place it shows, because America's menu fits on one line
       and a row-gap with nothing to separate costs nothing. */
    /* 22px BETWEEN ITEMS, WHICH IS LIVE'S OWN RHYTHM and not a nudge to make something fit. Its menu
       items carry padding: 0 11px, so neighbours sit 22px apart; ours sat at the global 24px. The
       difference is 2px per gap and 10px over the row, and at 1185px our six items needed 692px in a
       690px column - so the menu wrapped to a second line for the sake of ten pixels it never had.
       Measured after: 682px of content in 690px, one row, matching live's one row.

       row-gap stays 0 for the reason below it: 24px between wrapped ROWS of menu items is wrong where
       24px across them is right, and Canada's is the menu where that shows. */
    .caf-header .caf-nav__list { row-gap: 0; column-gap: 22px; }

    /* NO flex-wrap: nowrap on the header's menus, and this is the third thing tried and reverted here
       on 15 September 2026. Forcing the secondary Login/Subscribe list onto one line does reach
       production's 65px - measured - and it does it by RAISING that column's min-content from 75px to
       144px, which starves the main menu: the row is 1137px, the split went 476/455/159, and the seven
       main items then wrapped to two lines. Applied to every header menu instead of just the secondary
       one it is worse again, and invisible - the main menu holds one line by wrapping its own LABELS,
       "HOW WE WORK" over two lines at 82px against production's 107px on one, while the header stays
       65px because the logo sets that and the height check says nothing.

       The cause was removed on 15 September 2026 rather than worked around: the search is now an icon
       with an out-of-flow panel, so the middle column's min-content is the secondary menu plus a 40px
       button and the row has width to spare. The fractions still are not forced here, because they no
       longer need to be - and because min-width: 0 would silently reintroduce the overflow the moment
       somebody puts something wide back in a column. Measure before adding it. */
}

/* ---------------------------------------------------------------- the block heading

   The listing's "Block heading" treatment, which the client's own pages reach for on a heading that
   introduces a row of cards. It was carried under THEIR name, `.pr-blog-module-title`, from the
   conversion until 5 October 2026, and until 15 September 2026 nothing landed on it at all.
   Production draws "Our Insights" at 36px, weight 500, #0a0101 and -0.1px of tracking; we drew a 48px
   bold teal sentence off the global h2. Measured with --style-probe.

   The name is ours now and the treatment is still theirs. Renaming it is what lets the admin dialog
   and this rule say the same word: the editor picks "Block heading" and this is what draws it.

   Four of those five values are here because they are THEME - they describe how this kind of heading
   looks, not what this heading says. The fifth, uppercase, is per-instance and comes from the module's
   own title_font through the converter, so it is deliberately absent from this rule: one owner each.

   36px rather than the 54px the module declares. Divi's own generated rule for it says 54px and the
   page renders 36px - stable across runs with the page settled, and 36px appears nowhere in the CSS
   the page loads, so a client rule we have not located is winning. This matches what a visitor sees
   today, which is the thing being asked for; it will want re-checking if CAF ever resolve that clash.

   Six instances across the two exports - 2 America, 4 Canada - so this is a real reused class rather
   than one page's hook. */
.caf-heading--block {
    font-size: 2.25rem;
    font-weight: 500;
    line-height: 1;
    letter-spacing: -0.1px;
    color: var(--caf-ink);
    padding-bottom: 0.625rem;
}

/* ---------------------------------------------------------------- header search

   Scoped under .caf-header on purpose. The compact header widget's form is class="caf-search" and so
   is the results page's top-level container, and this block's `display: flex` and `__input` rules were
   flexing the whole results page into a row - a latent collision the single-column site-search page hid
   and the three-tab charity page exposed. Confining them to the header leaves the results page's own
   .caf-search / .caf-search__input rules (above) to style it. */

/* THE ICON, AND WHY THE PANEL LEAVES THE FLOW.

   The header's search was a permanent text input until 15 September 2026, and it was the reason the
   header measured 114px against production's 65px. The input claims width wherever it sits: as a flex
   item it would not go below its content, given min-width: 0 it shrank and the Login/Subscribe list
   beside it wrapped to two lines instead, and forcing that list not to wrap raised its own column's
   min-content and starved the main menu into two lines. Three shapes, one cause.

   Live does not have the problem because its field does not exist until asked for. The disclosure is
   the icon; the panel is absolutely positioned, so it contributes NOTHING to the grid's track sizing
   and the row gets its width back. That is the whole fix - the rest of this block is appearance. */

.caf-search-disclosure { position: relative; }

/* list-style and ::-webkit-details-marker both, because the triangle is drawn by different mechanisms
   in different engines and one of them alone leaves it showing. */
.caf-search__toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;

    /* 32px, DOWN FROM 40px, AND IT IS A HEIGHT FIX RATHER THAN A STYLE ONE. Once the row's tracks
       became Divi's own percentages this column is exactly live's 185px, and America's holds a 142px
       menu beside this button: at 40px the two needed 190px and wrapped, which put the column at 74px
       and - because America's logo is only 65px - made the whole header 74px against production's 65.
       At 32px they need 182px, share a line, and the header is 65px again. Canada is unaffected: its
       column still takes two lines and its 80px logo still sets the height.

       Still LARGER than production, which draws 29x27, so this moves towards live rather than past it.
       Do not take it below 32px for a pixel: it is the header's only icon-sized tap target. */
    width: 2rem;
    height: 2rem;
    color: var(--caf-ink-muted);
    cursor: pointer;
    list-style: none;
}
.caf-search__toggle::-webkit-details-marker { display: none; }
.caf-search__toggle:hover { color: var(--caf-orange); }
.caf-search__toggle:focus-visible { outline: 2px solid var(--caf-orange); outline-offset: 2px; }
.caf-search__glyph { display: block; }

/* CLOSED MEANS CLOSED, stated rather than inherited. A closed <details> hides its contents through
   ::details-content { content-visibility: hidden } in modern engines, not through display - which the
   navigation disclosure already records - and that does NOT hide this panel, because taking it out of
   flow takes it out of what gets skipped. Measured, not assumed: with only the UA rule the panel
   computed display: block at 313x63 beside a closed summary, so the search box was simply always on
   screen. Live's equivalent container computes display: none. */
.caf-search-disclosure:not([open]) .caf-search__panel { display: none; }

/* Anchored to the right edge, because this control sits at the right of the header and a panel that
   opened leftward would run off the viewport on a narrow screen. max-width keeps it inside one. */
.caf-search__panel {
    position: absolute;
    top: calc(100% + 0.25rem);
    right: 0;
    z-index: 10;
    padding: 0.75rem;
    max-width: calc(100vw - 2 * var(--caf-space));
    background: var(--caf-paper);
    border: 1px solid var(--caf-rule);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}

.caf-header .caf-search { display: flex; gap: 0.5rem; align-items: center; }
.caf-header .caf-search__input {
    /* flex: 1 1 18rem CAME FROM A RULE THAT NO LONGER EXISTS. The results page used to be
       class="caf-search" too and defined a bare .caf-search__input that this block only partly
       overrode; renaming the results page to .caf-search-page__ took that rule with it, and the field
       inside .caf-header .caf-search { display: flex } would have stopped growing. Stated here rather
       than left to be rediscovered. */
    flex: 1 1 18rem;
    min-width: 0;
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--caf-rule);
    border-radius: 2px;
    font: inherit;
    font-size: var(--caf-text-small);

    /* The field tokens, and like the results page's field this is one vocabulary rather than a fix:
       .caf-header is site furniture outside .caf-page, so none of the five scopes that remap --caf-ink
       can be an ancestor of it. Checked rather than assumed, and left in the same spelling as the two
       fields that WERE broken so no reader has to rediscover which were which. */
    color: var(--caf-field-ink);
    background: var(--caf-field-paper);
}
.caf-header .caf-search__input:focus-visible { outline: 2px solid var(--caf-orange); outline-offset: 1px; }
.caf-header .caf-search__button {
    padding: 0.4rem 0.9rem;
    border: 0;
    border-radius: 2px;
    background: var(--caf-orange);
    color: var(--caf-paper);
    font: inherit;
    font-size: var(--caf-text-small);
    cursor: pointer;
}
.caf-header .caf-search__button:hover { background: var(--caf-teal); }

/* ---------------------------------------------------------------- navigation */

/*
    Written dormant when the header was built and REWRITTEN on 27 August 2026, the day round 8 delivered
    the menus and they finally matched something. What was here flattened every level into one wrapping
    row: correct-looking against an imagined flat list, and against the real one a 430px sitemap in the
    header of every page, with all 22 items and all three levels permanently open.

    That is the second dormant-rule failure in this stylesheet - the first was .darkGreenBox painting
    teal text on its own teal ground - and it is the same lesson twice: a rule written against data that
    does not exist yet is a guess, and it should be checked the day it starts matching.

    Dropdowns open on hover AND on focus-within, which is not decoration: without the second, a keyboard
    visitor can tab into a submenu they cannot see. There is no JavaScript here, so :focus-within is the
    whole of the keyboard support.
*/

.caf-nav__list { display: flex; flex-wrap: wrap; gap: var(--caf-space); list-style: none; margin: 0; padding: 0; }
.caf-nav__item { position: relative; }
/* 14px and uppercase, both from the export: the header's menu module carries
   menu_font="Outfit|700||on|||||", which is family|weight|italic|UPPERCASE - the same fourth field the
   heading converter now reads. Ours rendered 17px sentence case off the body size against production's
   14px shout. The weight was already right at 700, which is the second field of the same string.

   The padding stays. Production has none, because Divi spaces its items on the list rather than the
   link, and 0.35rem here is a hit target rather than a look - it costs nothing in header height, which
   the 65px logo sets. */
.caf-nav__link {
    display: block;
    padding: 0.35rem 0;
    color: var(--caf-ink-muted);
    font-size: var(--caf-text-small);
    font-weight: 700;
    text-transform: uppercase;
    text-decoration: none;
}
/* A hovered link FADES rather than turning orange, which is production's: Divi's menu takes a link to
   opacity 0.7 and leaves its #464646 alone, measured on both sites on 29 September 2026. Orange is the
   module's active_link_color, so it marks the current page and nothing else. */
.caf-nav__link:hover { color: var(--caf-ink-muted); opacity: 0.7; }  /* the colour beats the global a:hover */

/* A top-level item stays faded while its panel is in use, as production's does: Divi fades on the
   item's hover, so moving down into the dropdown keeps "What We Do" at 0.7. */
:is(.caf-nav, .caf-nav__panel) > .caf-nav__list > .caf-nav__item:is(:hover, :focus-within) > .caf-nav__link { opacity: 0.7; }
.caf-nav__link--current,
.caf-nav__link--current:hover { color: var(--caf-orange); }

/* An item whose target the export does not carry. It reads as navigation and does nothing, which is
   honest: a link with no href announces itself as a link. */
.caf-nav__link--unlinked { color: var(--caf-ink-muted); opacity: 0.55; cursor: default; }

/*
    THE DROPDOWNS ARE PRODUCTION'S, measured on cafamerica.org and cafcanada.ca on 29 September 2026
    after the user compared them and ours did not match. Ours was a bordered 15rem card with a 24px
    inset, which Divi's is not, and - the part that mattered - America's "What We Do" is a MEGA MENU
    and we drew it as a two-line dropdown with its seventeen pages hidden a level further in.

    Divi's plain dropdown, both sites: a 240px white panel aligned to its item, a 3px orangered rule on
    top, a 0 2px 5px shadow and 10px of padding above the first link. Each link is 14px/700 uppercase on
    a 28px line in #464646 - the menu's own type, which .caf-nav__link already sets - padded 6px and
    inset 40px, the 20px of the item plus the 20px of the link. A hovered link gets a grey ground rather
    than a fade; that colour is read off production's pixels, because the rule is in a stylesheet the
    browser will not let a script read.

    The orangered is not the brand orange. Divi's module says #0c71c3 and the client's theme overrides it
    to #ff4500 on both sites; --caf-orange is #ff3b21. Kept as measured, and named here once.
*/
.caf-nav { --caf-dropdown-rule: var(--caf-orange); }

@media (min-width: 981px) {
    .caf-nav__children {
        position: absolute;
        top: 100%;
        left: -11px;  /* production's item carries 0 11px of padding, and its panel starts at that edge */
        z-index: 110;
        display: none;
        width: 240px;
        padding: 10px 0 0;
        background: var(--caf-paper);
        border-top: 3px solid var(--caf-dropdown-rule);
        box-shadow: 0 2px 5px rgb(0 0 0 / 10%);
    }

    .caf-nav__item:hover > .caf-nav__children,
    .caf-nav__item:focus-within > .caf-nav__children { display: block; }

    /* Inside a dropdown the list stacks, with no gap: the links' own padding is the rhythm. */
    .caf-nav__children .caf-nav__list { flex-direction: column; flex-wrap: nowrap; gap: 0; }
    .caf-nav__children .caf-nav__item { padding: 0 20px; }
    .caf-nav__children .caf-nav__link { padding: 6px 0 6px 20px; line-height: 28px; }
    /* --caf-paper-alt rather than the #e4e4e4 this used to carry: two greys ten units apart are one grey,
   and the opacity change is most of what says "hover" here anyway. */
.caf-nav__children .caf-nav__link:hover { opacity: 1; background-color: var(--caf-paper-alt); }
    .caf-nav__children .caf-nav__link--unlinked:hover { background-color: transparent; }

    /* A third level opens beside its parent rather than under it, because it is already inside a panel
       that is itself positioned. Neither site has one outside a mega menu; kept so a menu an editor
       deepens still opens somewhere. */
    .caf-nav__children .caf-nav__children { top: -13px; left: 100%; }

    /*
        THE MEGA MENU: an item carrying the client's `mega-menu` class, which the seeded "What We Do" on
        both sites does and which an editor can give any item in the admin. Divi opens it as one panel
        the width of the whole MENU COLUMN - 879px of .headMainMenu at 1521px, left edge on the column's
        edge, measured the same on both sites - with each child a column of equal width and ITS children
        listed beneath it, always open. So the panel is positioned against the column rather than the
        item, which is why nothing between the two may be positioned while it is open.

        Each column's link is a heading: the same type, 0 20px 6px, over a hairline rule; its list starts
        10px lower. Divi divides by the number of children (mega-menu-parent-2 is two halves), which a
        grid with auto columns does without being told the count.
    */
    .caf-header .headMainMenu { position: relative; }
    .caf-header .caf-nav__disclosure { position: static; }
    .caf-nav__item:has(> .caf-nav__link.mega-menu) { position: static; }

    .caf-nav__item:has(> .caf-nav__link.mega-menu) > .caf-nav__children {
        left: 0;
        width: 100%;
    }

    .caf-nav__item:has(> .caf-nav__link.mega-menu) > .caf-nav__children > .caf-nav__list {
        display: grid;
        grid-auto-flow: column;
        grid-auto-columns: 1fr;
        align-items: start;
    }

    .caf-nav__item:has(> .caf-nav__link.mega-menu) > .caf-nav__children > .caf-nav__list > .caf-nav__item { padding: 0; }

    .caf-nav__item:has(> .caf-nav__link.mega-menu) > .caf-nav__children > .caf-nav__list > .caf-nav__item > .caf-nav__link {
        padding: 0 20px 6px;
        border-bottom: 1px solid rgb(0 0 0 / 3%);
    }

    .caf-nav__item:has(> .caf-nav__link.mega-menu) .caf-nav__children .caf-nav__children {
        position: static;
        display: block;
        width: auto;
        padding: 10px 0 0;
        border: 0;
        box-shadow: none;
    }

    .caf-nav__item:has(> .caf-nav__link.mega-menu) .caf-nav__children .caf-nav__children .caf-nav__item { padding: 0; }
    .caf-nav__item:has(> .caf-nav__link.mega-menu) .caf-nav__children .caf-nav__children .caf-nav__link { padding: 6px 20px; }

    /* AMERICA'S CHEVRON. cafamerica.org marks an item that opens with Divi's arrow - an ETmodules glyph,
       16px, at the link's right edge inside 20px of padding - and cafcanada.ca's child theme blanks the
       same glyph, so Canada's parents carry none. Drawn rather than taken from the icon font, as the
       language tray's chevron is, so it takes the link's colour and needs no font. The TOP LEVEL only -
       the list directly in the nav or its disclosure panel - because inside the panel a parent is a
       mega-menu heading, and production marks none of those. */
    .caf-header :is(.caf-nav[data-channel="cafamerica"], .caf-nav[data-channel="cafamerica"] .caf-nav__panel) > .caf-nav__list > .caf-nav__item:has(> .caf-nav__children) > .caf-nav__link {
        position: relative;
        padding-right: 20px;
    }

    .caf-header :is(.caf-nav[data-channel="cafamerica"], .caf-nav[data-channel="cafamerica"] .caf-nav__panel) > .caf-nav__list > .caf-nav__item:has(> .caf-nav__children) > .caf-nav__link::after {
        content: "";
        position: absolute;
        right: 4px;
        top: 50%;
        width: 0.3rem;
        height: 0.3rem;
        border-right: 0.1rem solid currentColor;
        border-bottom: 0.1rem solid currentColor;
        transform: translateY(-70%) rotate(45deg);
    }
}

/*
    The disclosure control, built 27 August 2026 after the navigation shipped without one.

    <details>/<summary> rather than a checkbox or a script: <summary> is a real disclosure button that
    the browser announces with its expanded state, it works from the keyboard, and it keeps this project
    at zero lines of first-party JavaScript. The desktop half is the part that needed checking rather
    than assuming - a closed <details> hides its content through ::details-content in current browsers
    rather than through display, so BOTH overrides are here and the pair was tested in a browser before
    being relied on.

    Only a menu of more than four links gets one; the component decides. A toggle in front of Login and
    Subscribe would be a control that costs more than it saves.
*/

.caf-nav__disclosure { position: relative; }

@media (min-width: 981px) {
    /* No control at all on desktop: the summary is gone and the panel is always open. */
    .caf-nav__toggle { display: none; }
    .caf-nav__disclosure > .caf-nav__panel { display: block !important; }
    .caf-nav__disclosure::details-content { content-visibility: visible !important; }
}

@media (max-width: 980px) {
    .caf-nav__toggle {
        display: inline-flex;
        align-items: center;
        gap: 0.5rem;
        padding: 0.5rem 0.9rem;
        border: 1px solid var(--caf-rule);
        border-radius: 2px;
        background: var(--caf-paper);
        color: var(--caf-ink);
        font-family: var(--caf-font);
        font-weight: 700;
        font-size: var(--caf-text-small);
        cursor: pointer;
        list-style: none;
    }

    /* Safari still draws the default triangle through a pseudo-element of its own. */
    .caf-nav__toggle::-webkit-details-marker { display: none; }

    /* The affordance is drawn rather than fetched: this project has no icon font, and inventing one
       glyph is cheaper and more honest than shipping a typeface for it. */
    .caf-nav__toggle::after {
        content: "";
        width: 0.55rem;
        height: 0.55rem;
        border-right: 2px solid currentColor;
        border-bottom: 2px solid currentColor;
        transform: rotate(45deg) translate(-0.1rem, -0.1rem);
    }

    .caf-nav__disclosure[open] > .caf-nav__toggle::after {
        transform: rotate(-135deg) translate(-0.15rem, -0.15rem);
    }

    .caf-nav__toggle:focus-visible { outline: 2px solid var(--caf-orange); outline-offset: 2px; }

    /* Open, the menu stacks - which is the right shape once it is behind a control, and the reason the
       scrolling row below is only needed by the menus that have no control. */
    /* Padding only while open. On the panel unconditionally it adds its own height to a CLOSED
       disclosure, because content-visibility hides the contents and keeps the box. */
    .caf-nav__disclosure[open] > .caf-nav__panel { padding-top: var(--caf-space); }
    .caf-nav__disclosure .caf-nav__list { flex-direction: column; flex-wrap: wrap; gap: 0.25rem; overflow-x: visible; }
    .caf-nav__disclosure .caf-nav__children { padding-left: var(--caf-space); }
    .caf-nav__disclosure .caf-nav__item:focus-within > .caf-nav__children { position: static; border: 0; padding: 0 0 0 var(--caf-space); background: none; }
}

@media (max-width: 980px) {
    /*
        A menu with no disclosure control stays a ROW and scrolls sideways, rather than stacking.

        Stacking was tried first and measured: it made the header 419px tall on a phone, against 110px
        for the header that had no navigation at all - so the navigation would have pushed every page's
        content below the fold and been a regression for mobile visitors rather than a feature. A row
        that scrolls keeps it at roughly the desktop height, keeps every top-level item reachable, and
        needs no markup this component does not already emit.

        The deeper levels stay closed and open on focus, so a keyboard or screen-reader user reaches
        them. What is still missing is a real disclosure control - a button that opens the whole menu -
        and that genuinely does need markup, so it is recorded rather than half-built. Same reasoning
        that kept the toggle out while the menu was empty; the difference is that the cost is now
        measured rather than assumed.
    */
    /*
        min-width: 0 is what makes the scrolling work at all, and without it the fix is worse than the
        problem. A grid and a flex child both default to min-width: auto, meaning "never shrink below
        your content" - so the row of items forced its column wider than the screen and the whole PAGE
        scrolled sideways instead of the nav. Measured at 390px: horizontal overflow on the document
        before this line, none after.
    */
    .caf-header__column,
    .caf-nav { min-width: 0; max-width: 100%; }

    /*
        And the column has to WRAP, not just shrink. The export's middle column holds two things - the
        small top menu and the search form - and on a phone they were competing for one row: the menu
        was squeezed to a single clipped letter with its own scrollbar while the search box kept its
        width. Found in a screenshot; every measurement of heights and overflow had read clean, because
        nothing overflowed - one child had simply been crushed.
    */
    .caf-header__column { flex-wrap: wrap; row-gap: 0.75rem; }

    /* THE LOGO GOES FIRST, because the DOM order is the export's and it puts the mark LAST. That is
       invisible at width, where the three columns are a row and the logo is simply the right-hand
       one; stacked it means a phone met the navigation, then the search, then the mark - and the
       orange panel, which at width is a corner block, became a band the full width of the screen.

       Measured 3 October 2026: header 187px on America and 202px on Canada, with the panel spanning
       every pixel of the viewport. The width half of that is fixed by the panel moving onto the link
       (see .headLogo above); this is the order half. order works because .headLogo is a grid item of
       .caf-header__row, so it reorders without touching the markup - and the markup is generated, so
       reordering it there would mean a build.

       flex-start, unlike at width: stacked there is no right-hand edge for the panel to hold, and the
       mark belongs at the same inset as the menu below it. */
    .caf-header .headLogo { order: -1; justify-content: flex-start; }

    .caf-nav__list {
        flex-wrap: nowrap;
        gap: var(--caf-space);
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .caf-nav__item { flex: 0 0 auto; }
    .caf-nav__children { display: none; }
    .caf-nav__item:focus-within > .caf-nav__children {
        position: absolute;
        z-index: 110;
        display: block;
        min-width: 14rem;
        padding: var(--caf-space);
        background: var(--caf-paper);
        border: 1px solid var(--caf-rule);
    }
}

/* ------------------------------------------------------------- unset content */

/*
    The placeholders a widget renders when its source carried nothing to show - "Image not set",
    "Card not set", "Hero banner not set", "Testimonial not set", "Video not set", "<Network> link not
    set". Every one of them is deliberate: the widgets chose to surface a conversion gap rather than
    swallow it, and their comments say so.

    None of them had a rule, so all six rendered as ordinary black body copy at body size, on live
    pages, indistinguishable from something the client wrote. A placeholder that looks like content is
    worse than no placeholder, because it is the one thing on the page nobody questions.

    Styled as an editorial note rather than as an error: dashed, muted, small. Loud enough to catch a
    reviewer, quiet enough that it is obviously not prose.

    ALL OF THEM ARE DORMANT TODAY. Measured across all 410 served pages on both channels: not one of
    them renders. So this block is defensive - it is what a re-import or an edited widget would land in
    - and it is written against markup nobody has seen on a page. That is the shape of the two rules
    this file has already got wrong the day they first matched (.darkGreenBox painting teal on teal,
    .caf-nav flattening the header into a 430px sitemap), so each selector here was exercised by hand
    against a real page before it was committed rather than reasoned about.

    .caf-panel--empty joined on 2 October 2026 and was exercised the same way: a Panel widget placed
    with no heading, text, picture or button, looked at in the Page Builder.

    NOT included: .caf-video--unplayable. It looks like a sibling and is not - it renders a working
    link to an address this widget cannot embed (a Vimeo page, say), so the content is reachable and
    styling it as a hole would be a regression.
*/
.caf-donation--unset,
.caf-downloads--empty,
.caf-downloads__empty,
.caf-downloads__missing,
.caf-image--missing,
.caf-panel--empty,
.caf-social--empty,
.caf-testimonial--empty,
.caf-video--empty {
    display: block;
    padding: var(--caf-space-small) var(--caf-space);
    border: 1px dashed var(--caf-rule);
    color: var(--caf-ink-muted);
    font-family: var(--caf-font);
    font-size: var(--caf-text-small);
    font-style: italic;
}

/* The unplayable video is a link, not a hole: an address the embed cannot play, kept reachable. */
.caf-video--unplayable { font-size: var(--caf-text-small); }

/*
    The donation button's caption. UNLIKE EVERY SELECTOR ABOVE IT, this one is not a hole in the
    content - the button beside it is correct and will work. It is the editor being told why clicking
    it here does nothing, and it is emitted only in Page Builder preview, so no visitor ever meets it.
    Quiet, and on its own line so it does not sit inside the button's own row.
*/
.caf-donation__note {
    display: block;
    margin-top: var(--caf-space-small);
    color: var(--caf-ink-muted);
    font-family: var(--caf-font);
    font-size: var(--caf-text-small);
}

/*
    The in-place donation form's marker, and it is load-bearing rather than decorative. What that
    placement renders on the live site is an empty hidden anchor for the platform to draw over, which
    in Page Builder would be a widget with no height and nothing to click - impossible to select, move
    or delete. This is emitted only in the editor, so again no visitor meets it. Boxed rather than
    bare, because it stands for an area of the page rather than a line of it.
*/
.caf-donation__slot {
    display: block;
    padding: var(--caf-space) var(--caf-space);
    border: 1px dashed var(--caf-rule);
    color: var(--caf-ink-muted);
    font-family: var(--caf-font);
    font-size: var(--caf-text-small);
    text-align: center;
}

/* ---------------------------------------------------------------- motion */

/*
    The colour changes this site makes, given a duration. Only the elements that already had a hover
    or focus colour are listed - this adds no new movement, it softens changes that were instant.

    Behind prefers-reduced-motion: no-preference, so a visitor who has asked their system for less
    motion gets the instant change rather than the transition. A 160ms colour fade is mild, but the
    query costs one line and the alternative is deciding on someone else's behalf.

    Transitioning the named properties rather than `all`: `all` would animate the layout properties
    the grid and the disclosure control change, which is how a menu ends up sliding.

    outline-color is deliberately NOT in the list, and it was until it was measured. With it there,
    the focus ring fades in from the browser's default colour rather than appearing in the brand
    orange - caught by reading the computed outline-color during a real Tab press and getting the
    teal it was transitioning FROM while the screenshot showed the orange it was heading TO. A focus
    ring that arrives at full contrast late is a focus ring that is briefly hard to see, which is the
    one thing it exists not to be.
*/
@media (prefers-reduced-motion: no-preference) {
    a,
    .caf-button,
    .caf-social,
    .caf-accordion__title,
    .caf-search-page__tab,
    .caf-header .caf-search__button {
        transition: color var(--caf-transition), background-color var(--caf-transition);
    }

    /* The tab adds border-color, because the rule along its top is the whole of what marks it open
       and a ground that moves while the rule snaps reads as two separate things happening. */
    .caf-tabs__tab {
        transition: color var(--caf-transition), background-color var(--caf-transition), border-color var(--caf-transition);
    }

    /* Opacity too, because a menu link fades on hover rather than changing colour. */
    .caf-nav__link {
        transition: color var(--caf-transition), background-color var(--caf-transition), opacity var(--caf-transition);
    }
}

/* ---------------------------------------------------------------- focus */

/*
    THE FOCUS RING THIS FILE NEVER HAD. Until now exactly three elements drew one - a form control,
    the header search input and the mobile navigation toggle - so every link on every page, every
    button, every accordion summary and every listing title fell back to whatever the browser draws,
    which on a coloured band is frequently nothing a visitor can see.

    :where() so it carries NO specificity: the three existing rings still win without !important, and
    anything added later overrides this by existing rather than by fighting it.

    :focus-visible rather than :focus, so a mouse click does not leave a ring behind - that is the
    behaviour the three earlier rules already chose, and this follows them.

    The offset is 2px so the ring clears the underline on a text link. Inside a dark band the orange
    is the one palette colour that holds against both the teal and the paper, which is why the ring
    does not switch to currentColor there - checked on /financial-advisors and the /news-insights
    banner rather than assumed.
*/
:where(a, button, summary, input, select, textarea, [tabindex]):focus-visible {
    outline: 2px solid var(--caf-orange);
    outline-offset: 2px;
}

/* The skip link's target takes focus programmatically and must not draw a ring as though the visitor
   had tabbed to it. Declared after the rule above because :where() cannot be relied on to lose. */
.caf-page:focus,
.caf-page:focus-visible { outline: none; }

/* ---------------------------------------------------------------- utilities */

/*
    Hidden from sight, kept for a screen reader. Never display:none, which removes it from the
    accessibility tree as well - the search box's label is the whole of its accessible name, and the
    social links carry the same requirement in their own block.
*/
.caf-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Off-screen until focused, then pinned to the top-left over the sticky header. */
.caf-skip-link {
    position: absolute;
    left: -9999px;
    z-index: 200;
    padding: 0.6rem 1rem;
    background: var(--caf-teal);
    color: var(--caf-paper);
    font-weight: 700;
    text-decoration: none;
}
.caf-skip-link:focus {
    left: 0.5rem;
    top: 0.5rem;
}

/* The skip link's target takes focus programmatically, so it must not draw a focus ring as though it
   were interactive. */
.caf-page:focus { outline: none; }

/* ---------------------------------------------------------------- footer */

.caf-footer {
    margin-top: 3rem;

    /* NO INLINE PADDING. It used to be var(--caf-space) on both sides, which held every band 24px
       short of the viewport and made a full-bleed panel inside one impossible. The measure now comes
       from .caf-footer__row, the same place the page and the body layouts take theirs.

       AND NO PADDING AT THE BOTTOM. The bands paint themselves, so any padding here is the footer's
       own teal showing through underneath them - a strip of it below the copyright bar, where live
       ends the page on the bar itself. Both exports agree: the top section declares
       custom_padding="40px||0px" and the bottom one "0px||0px", so the 40px above is real and the
       space below is ours. */
    padding: var(--caf-space-large) 0 0;
    background: var(--caf-teal);
    color: var(--caf-paper);
    font-size: var(--caf-text-small);
}
.caf-footer a { color: var(--caf-paper); }
.caf-footer a:hover { color: var(--caf-orange); }
.caf-footer h1,
.caf-footer h2,
.caf-footer h3,
.caf-footer h4,
.caf-footer h5 { color: var(--caf-paper); }
/* The SECTION is the band and the ROW is the measure - Divi's own arrangement, and the page sections
   have followed it since the full-bleed work. The cap that used to be here is on the row instead. */
/* display: flow-root SO A ROW'S MARGIN STAYS INSIDE ITS OWN BAND, and without it one escaped the
   page. .caf-footer__row carries margin-block: var(--caf-space); this section has no padding and no
   border to stop it collapsing through, and .caf-footer's own padding is 40px 0 0 - nothing at the
   bottom. So the last row's bottom margin came out of the section, out of the footer, and rendered
   as 24px of PAGE BACKGROUND below the teal.

   Measured 3 October 2026 on /, /what-we-do and /search, both channels: scrollHeight sat exactly
   24px past the footer's own bottom edge on every one of them. It is the white strip below the
   footer, and it was never a padding. */
.caf-footer__section { max-width: none; margin: 0; display: flow-root; }
.caf-footer__row { display: grid; grid-template-columns: 1fr; gap: var(--caf-space); margin-block: var(--caf-space); }

/* THE COLUMN IS A FLOW WITH ONE RHYTHM, and before this it had whatever the children's own margins
   happened to leave. Measured 3 October 2026 in the first footer column: the logo panel and the
   paragraph below it sat 7px apart, and the paragraph and the seals row 17px. Both read as crowding
   rather than as spacing, which is most of what "the footer looks squashed" was.

   align-items: flex-start keeps .pr-footer-logo at its content width, which is what display:
   inline-block gave it before - so the client's own .pr-footer-logo::after, the rule that bleeds the
   orange leftward to the viewport edge, still measures from the same box. Check that bleed after
   touching this: an earlier version of it put the footer's scrollWidth 136px past clientWidth and
   --visual-sweep read a clipped child on all 24 swept pages.

   .pr-footer-base-social keeps its own display: flex and align-items: center - it is two classes deep
   and wins on specificity, which is why the social icons stay in a row. */
.caf-footer__column { display: flex; flex-direction: column; align-items: flex-start; gap: var(--caf-space); }

/* AND THE LAST BAND ENDS THE PAGE, so it keeps no row margin to paint underneath the bar. This is
   what .caf-footer's padding comment already asks for - "live ends the page on the bar itself" -
   which was true of the padding and had never been true of the margin. The bottom band was
   asymmetric because of it: 24px of dark above the copyright row and none below.

   On the last SECTION rather than on .pr-footer-base, so it does not depend on a class that reaches
   us only because the export happens to carry one. */
.caf-footer__section:last-child > .caf-footer__row { margin-block: 0; }
.caf-footer__text ul { list-style: none; margin: 0; padding: 0; line-height: 1.9; }
.caf-footer__image { max-width: 100%; height: auto; }

.caf-footer__space { height: var(--caf-space); }

@media (min-width: 981px) {
    .caf-footer__row { grid-template-columns: var(--caf-columns, 1fr); column-gap: var(--caf-gutter, var(--caf-space)); }

    /* AND THE INSET GOES INSIDE THE TRACK, because a column-gap here cannot work. Both footers
       declare --caf-gutter: 0% on this row - Divi gutter 1 - so the three columns butt straight
       together: measured 3 October 2026 at 1424px, column one's paragraph ended at x=712 and "Links"
       began at x=712. Nothing between them.

       The gap cannot simply be raised. The tracks are percentages that already sum to 100 (50/25/25
       on both channels), so any column-gap is added to a row that is already full and the last
       column overflows its measure. padding-inline-end is inside the track, so the columns keep their
       declared widths and only the text moves: column one's measure goes from 570px to 530px.

       It reaches .pr-footer-base too, which is wanted - the copyright line ran straight into the
       orange social block. The orange itself does not move, because that block is the last column. */
    .caf-footer__row > .caf-footer__column:not(:last-child) { padding-inline-end: var(--caf-space-large); }
}

/* The seals row, which the source keeps in a code module as three loose images. */
.caf-footer .footer-logos img { max-height: 64px; width: auto; margin: 0 1rem 1rem 0; }

/* ---------------------------------------------------------------- the client's own footer

   ADOPTED RULES, which this stylesheet does almost nowhere else, and the exception is deliberate.
   front-end.md's position on the preserved hooks is that most of the client's rules are !important
   patches whose geometry assumes Divi's row and arrive here one level above it - true of the 154
   America rules as a body, and NOT true of this block. The footer rules are typography and two
   coloured panels, they name hooks our markup already carries, and they are the whole of what makes
   a footer look like CAF's footer. Asked and answered on 16 September 2026: the ask was "the footer
   doesn't match production", and matching production here means these rules.

   Both child themes carry them BYTE-IDENTICALLY - divi-child-caf/style.css and
   Divi-Canada-Child/style.css have the same footer block, under the same banner comment, which is
   consistent with Canada's theme declaring "Theme Name: CAF America Child Theme 2024" in its own
   header. So one block here serves both channels, and that is a fact about the source rather than a
   convenience.

   (And that sentence used to quote the client's banner comment verbatim, which closed THIS comment
   two lines early and silently swallowed every rule down to the first heading rule - the footer copy
   stayed sans while the headings moved, which reads as a specificity problem and is not one. A
   comment marker inside a comment is the same family as the 0x08 that a word-boundary escape becomes through a shell
   heredoc: invisible in the editor, fatal to the parser.)

   PORTED, NOT PASTED. Every value below is the client's; the SELECTORS and a few layout declarations
   are rewritten for our DOM, because theirs was written against et_pb_* wrappers we do not emit.
   Each departure is noted where it happens. Measured against live with --style-probe at 1185px.
*/

/* Body copy. Live's footer paragraphs are Source Serif 4 at 17px/27.2 weight 500; ours were Outfit
   at 14px/22.4 weight 400, because .caf-footer set --caf-text-small and the serif face was wired to
   .fr-view and .caf-body__text only - the footer was simply never in that list. Same omission the
   token's own comment describes: a declared face that a rule does not reach. */
.caf-footer__text { font-family: var(--caf-font-serif); font-size: 1.0625rem; line-height: 1.6; font-weight: 500; }

/* The column headings. 30px Outfit weight 500, sentence case - ours were 16px bold uppercase off the
   global h5. text-transform is stated rather than left off, because the global rule uppercases and
   this has to beat it. */
.caf-footer .footer-actions h5 {
    font-family: var(--caf-font);
    font-size: 1.875rem;
    font-weight: 500;
    line-height: 1;
    text-transform: none;
    margin: 0;
    padding-bottom: 0.625rem;
}

/* The link list. Uppercase, bold, Outfit, and no underline - the underline is ours, from the global
   a rule, and live has none. The hover underline is kept: removing the only affordance a link has
   left is not part of the ask. */
.caf-footer .footer-actions ul { margin: 0; padding: 0; list-style: none; }
.caf-footer .footer-actions li { margin-bottom: 0.5rem; }
.caf-footer .footer-actions li a {
    font-family: var(--caf-font);
    text-transform: uppercase;
    font-weight: 700;
    text-decoration: none;
}
.caf-footer .footer-actions li a:hover { text-decoration: underline; }

/* DEPARTURE 1. The client writes `.footer-actions { display: flex; justify-content: space-between }`,
   and the reason is not layout - it is that the two divider modules above "Contact Us" become
   zero-width flex items and stop pushing the heading down, so Contact Us aligns with Links. Measured:
   live's divider box is 0x23, ours was 272x24 stacked twice, which is the 48px our Contact Us sat
   lower by. Reproduced by taking the spacers out of flow instead, which says what it is for and does
   not put our text block in a flex row it was not written for. */
.caf-footer .footer-actions > .caf-footer__space { display: none; }

/* The two coloured panels, and the bleed is the point of them. The client paints each block and then
   extends it to the viewport edge with an ::after - the logo's runs 200% to the left, the social
   block's 100% to the right - so on live the orange runs off the page on both sides. The colour on
   the logo itself now comes from the export, which declares background_color on that image module;
   only the bleed is from here.

   .pr-footer-logo is the module PANEL rather than the <img>, which is why the ::after below can exist
   at all: a replaced element renders no pseudo-element, so this same rule against the image painted
   the colour and silently dropped the bleed. The converter emits Divi's own module/image split for an
   image that declares a background, and the class lands where the client wrote it.

   AND THE FOOTER HAS TO CLIP, which the first attempt got backwards by reasoning that clipping would
   kill the bleed. It does not: .caf-footer spans the viewport, so clipping at ITS box removes only the
   part that is off screen and leaves the orange running edge to edge. Without it the two ::after
   elements pushed the document 88px wider than the viewport and the whole page scrolled sideways -
   caught by looking at the screenshot, and it is one of --visual-sweep's own checks. clip rather than
   hidden, because hidden on one axis forces the other to auto and would make the footer a scroll
   container. */
.caf-footer { overflow-x: clip; }
.caf-footer .pr-footer-logo-seals { position: relative; }
.caf-footer .pr-footer-logo { position: relative; display: inline-block; }
.caf-footer .pr-footer-logo .caf-footer__image { display: block; }
.caf-footer .pr-footer-logo::after {
    content: "";
    position: absolute;
    top: 0;
    right: 100%;
    width: 200%;
    height: 100%;
    background-color: var(--caf-orange);
}

/* The copyright strip. Live pads it 16px top and bottom and lets the social block shrink to its icons;
   ours split the row 50/50, which left the orange block half the page wide.

   THE ORANGE REACHES THE EDGE BY BEING THERE, not by a pseudo-element chasing it. This row breaks out
   of the measure - full width, no padding on the right - and puts the centring inset on its own left
   padding instead, so the last track simply ENDS at the viewport edge. The first version bled it with
   an ::after 100% wide, which painted the same pixels and left the footer's scrollWidth 136px past its
   clientWidth: the page did not scroll, because overflow-x: clip, but --visual-sweep read the footer as
   clipping a child on all 24 pages it swept and that noise would hide the next real one.

   The percentage in the padding resolves against the SECTION, which is now the full width - which is
   why the band change above had to come first. It mirrors the row measure at both breakpoints because
   it IS that measure: (viewport - row) / 2 is the inset the centred rows sit at. */
.caf-footer .pr-footer-base {
    width: 100%;
    padding-right: 0;

    /* --caf-container-wide, because that is the cap the footer's rows actually declare: every one of
       them carries max_width="1600px" and so resolves through .caf-row--wide. The inset has to be the
       one its sibling rows sit at or the copyright line stops aligning with the columns above it, and
       the two only diverge above a ~1625px viewport - which is exactly where nobody looks. */
    padding-left: calc((100% - min(90%, var(--caf-container-wide))) / 2);
}

@media (min-width: 981px) {
    .caf-footer .pr-footer-base { padding-left: calc((100% - min(80%, var(--caf-container-wide))) / 2); }
}

.caf-footer .pr-footer-base-copy { padding-block: 1rem; }
.caf-footer .pr-footer-base-social {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    padding: 1rem 0 1rem 1rem;
    background-color: var(--caf-orange);
}
.caf-footer .pr-footer-base-social .footer-social { display: flex; align-items: center; }

/* 32px, and the selector carries .footer-social so it beats the general footer-social rule below,
   which caps every icon at 28px and would otherwise win on source order. */
.caf-footer .pr-footer-base-social .footer-social img { max-height: none; width: 32px; margin: 0 0 0 1rem; }

/* DEPARTURE 2. `.pr-footer-base { display: flex; justify-content: center }` with `width: 120%` on the
   copy is Divi column arithmetic - two 1_2 columns forced apart. Our row is a grid, so the same
   result is one track sizing to its content. The hook is on the ROW, which is why rows had to start
   carrying their module_class at all; before that there was nothing here to select. */
.caf-footer .pr-footer-base { grid-template-columns: 1fr auto; gap: 0; }

/* Their two breakpoints, kept as theirs. 1024px is where the logo column goes full width and 768px is
   where the link columns stack; this file's own breakpoint is 981px and these are not moved onto it,
   because the widths they release are the client's own. */
@media (max-width: 1024px) {
    .caf-footer .pr-footer-logo-seals { margin-bottom: 1.5rem; }
}
.caf-footer .footer-social img { max-height: 28px; width: auto; margin: 0 0.75rem 0 0; }

/* ---------------------------------------------------------------- language switcher

   Two placements, one control. Canada's footer has carried it since the footer was built; its HEADER
   gained it on 16 September 2026, which is where the live site actually keeps its switcher - WPML
   injects English and Francais into menu-header-2, beside Subscribe and in front of the search icon.

   The header treatment is a TOGGLE rather than live's desktop dropdown. Live's own inline
   wpml-menu-item stylesheet paints .wpml-ls-slot-67 links #ff3b21 and the current language #4c4444,
   and the SHAPE of that is reproduced - one language live, the other grey and inert - but the orange
   is not. --visual-sweep flagged #ff3b21 on white at 14px as low contrast the first time this was
   built, which it is (about 3.4:1), and the file already has an answer to that question: every link
   on this site is --caf-teal at rest and --caf-orange on hover. So the available language takes the
   site's own link colour and the current one takes --caf-ink-muted, which is #464646 against live's
   #4c4444 - near enough that this is live's grey, and unlike live's orange it is a colour a visitor
   can read. Reproducing a contrast failure is not fidelity.

   WIDTH IS THE THING TO WATCH HERE, not appearance. This sits in .headSearch, the middle column of the
   header's 3fr 1fr 1fr row, and that column has NO min-width: 0 for reasons recorded at length in the
   header block: it takes the width its contents need, and whatever it takes comes off the main menu.
   So it was measured with --style-probe at 1185px before being committed, against the same page with
   this rule forced to display: none:

       without    header 80px   .headMainMenu 653x67   .headSearch 218x40   .headLogo 218x80
       with       header 80px   .headMainMenu 597x67   .headSearch 294x40   .headLogo 199x80

   The control itself is 130x22. The main menu loses 56px of width and NOT a row - its height is
   identical either way, which is the check that matters, because every previous thing put in this
   column paid for itself by wrapping the main menu onto a second line. The header stays at 80px,
   which is production's 80px exactly. Anything added here has to be measured the same way.

   MEASURE WITH THE APP'S CONTENT ROOT AT THE PROJECT DIRECTORY. The first version of this note read
   67px and blamed the database, because the run behind it was started as bin/Debug/net10.0/CAF.exe
   from inside that folder - so the content root was bin/Debug/net10.0, assets/ is at the project
   root, and EVERY /getContentAsset/ answered 404. The logo column was then sized by an empty img and
   the header came out 13px short. Nothing was wrong with the page or the database; the measurement
   was taken against a site with no images. A 404 on the logo is the shape of that mistake.
*/

.caf-language__list { display: flex; gap: 1rem; list-style: none; margin: 0; padding: 0; }
.caf-language__link--current { text-decoration: none; opacity: 0.7; cursor: default; }

/*
    THE HEADER TRAY - decision 141, 29 September 2026, replacing the flat toggle described above. The
    current language is the <summary>, with a chevron; the other opens in a panel beneath it, dressed as
    the main navigation's dropdowns (.caf-nav__children) so the header has one kind of tray. Scoped to
    the placement, because the footer's instance stays a flat pair.

    Narrower than the toggle it replaces - one language name and a chevron against two names and a
    rule - so the .headSearch width note above only gets easier. The panel is out of flow and changes
    nothing's width.
*/
.caf-language__tray { position: relative; font-size: var(--caf-text-small); white-space: nowrap; }

.caf-language__current {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0 0.5rem;
    color: var(--caf-teal);
    cursor: pointer;
    list-style: none;
}

.caf-language__current::-webkit-details-marker { display: none; }

/* The chevron, drawn rather than a glyph, so it takes the text colour and needs no font. It turns to
   point up while the tray is open. */
.caf-language__current::after {
    content: "";
    width: 0.4rem;
    height: 0.4rem;
    border-right: 0.1rem solid currentColor;
    border-bottom: 0.1rem solid currentColor;
    transform: translateY(-0.15rem) rotate(45deg);
}

.caf-language__tray[open] > .caf-language__current::after { transform: translateY(0.1rem) rotate(-135deg); }
.caf-language__current:hover { color: var(--caf-orange); }
.caf-language__current:focus-visible { outline: 2px solid var(--caf-orange); outline-offset: 2px; }

.caf-language--header .caf-language__list {
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 0;
    z-index: 110;
    flex-direction: column;
    min-width: 8rem;
    padding: 0.5rem 0;

    /* The navigation's dropdown shell, so the header keeps one kind of tray - WPML puts this list in the
       same Divi menu on cafcanada.ca, and it opens in the same panel there. */
    background: var(--caf-paper);
    border-top: 3px solid var(--caf-orange);
    box-shadow: 0 2px 5px rgb(0 0 0 / 10%);
}

.caf-language--header .caf-language__link {
    display: block;
    padding: 0.35rem 1rem;
    color: var(--caf-teal);
    text-decoration: none;
}

.caf-language--header .caf-language__link:hover { color: var(--caf-orange); text-decoration: underline; }

/* ---------------------------------------------------------------- preserved hooks */

/*
    Classes the old site's own CSS targets, which the Divi conversion carries onto the widget it
    produces. Only the ones whose intent is unambiguous and self-contained are reproduced here; the
    rest are left as hooks with no rule, because most of their rules are !important patches whose
    geometry assumes Divi's layout (a button at margin-left: -50px assumes the banner it sat in).

    See analysis/ for the measured position: of America's 154 child-theme rules, 51 of the 64 that name a
    preserved hook now land on this markup - none of them adopted, because reviewing them found that
    even the ones that apply were written for Divi's row and arrive on our section one level above it.

    These rules matched NOTHING until 25 August 2026. They were written against hooks the conversion was
    believed to carry, and it carried only two of the five levels - so .darkGreenBox and .topBannerQuote
    sat dormant here while the pages they describe rendered unstyled. That is worth knowing before
    editing them: they had never been seen working, and the first one to be seen was wrong.

    WHAT IS LEFT IN THIS SECTION IS .darkGreenBox AND NOTHING ELSE OF THE BANNER FAMILY - 3 October 2026.
    .topBannerQuote's one rule was folded into the global h5 four thousand lines above; .homeBannerLeft
    and .header-image styled the Divi page banner that HeroLift now lifts into the Hero fields, and both
    are gone. Measured both ways before removing them: ZERO occurrences across all 6,355 version rows of
    stored Page Builder configuration on both channels, and emitted by no .cshtml.

    .darkGreenBox stays, and NOT because of stored configuration - it has none either. It stays because
    Views/Shared/_Body.cafamerica.CAF.Article.cshtml emits it on every America article's header column.
    THAT IS THE CHECK TO MAKE BEFORE REMOVING ANY HOOK FROM HERE: a hook can be dead in the database and
    alive in a generated partial, and the partial is the one that still renders.
*/

/*
    Redefining the tokens, exactly as .caf-section--on-dark does and for the reason its comment gives:
    listing the elements to lighten means missing one. The first version of this rule lightened h1, h2
    and h3 - and the page that first exercised it, /financial-advisors, opens with an h5, which arrived
    as teal text on the teal ground this rule paints. Nothing measured it: the words are all present and
    correct, so the fidelity sweep reads the page at full marks, which is the 148-blank-columns shape
    again.

    The background is --caf-teal-dark rather than --caf-teal because --caf-teal is remapped to the paper
    colour just below: a panel that painted its own background from a token it then redefines would
    paint white on white.
*/
.darkGreenBox {
    padding: 30px;
    background: var(--caf-teal-dark);

    --caf-ink: var(--caf-paper);
    --caf-ink-muted: var(--caf-ink-muted-on-dark);
    --caf-teal: var(--caf-paper);

    /* Body links, for the reason .caf-section--on-dark gives. */
    --caf-link: var(--caf-paper);
    --caf-paper-alt: rgba(255, 255, 255, 0.12);
    color: var(--caf-ink);
}

/*
    A BUTTON THAT STRADDLES THE BOTTOM-RIGHT CORNER OF ITS PANEL, which is what the hook is named for
    and which this file rendered as an ordinary button at the left of the flow.

    Reported off the home page's Make Your Gift Count panel. Measured on cafamerica.org at a 2048px
    viewport: the panel spans x 216-1816 and its bottom is 478; the button's right edge is 1836 and its
    bottom is 498 - so it hangs 20px past the panel on both axes and sits ON the corner.

    Anchored to the PANEL rather than to the column live anchors it to. Live writes right: -70px against
    a column inset 50px from the row; ours is inset --caf-space, so a carried -70px would land somewhere
    else. -20px against the panel is the same rendered position expressed against the box that is
    actually painted, which is the only one that stays right when the inset changes.

    ABOVE DIVI'S BREAKPOINT ONLY. Absolute positioning takes the button out of the flow, and on a phone
    the panel is barely taller than its own text - the button would sit on top of the last line. Below
    981px it stays in the flow and right-aligns, which is the same reading without the overhang.
*/
@media (min-width: 981px) {
    .caf-section__grid:has(.caf-button--corner) { position: relative; }

    .caf-button--corner {
        position: absolute;
        right: -20px;
        bottom: -20px;
    }
}

@media (max-width: 980px) {
    .caf-section__column:has(> .caf-button--corner) { text-align: right; }
}

/* Their own small-heading treatment. The rule that used to be here restated the global h5 rule's
   uppercase and the global heading rule's font-family, so it is gone rather than kept agreeing - the
   hook still means what the source means by it, it just no longer needs saying twice. */

/*
    A full-height column so buttons line up along the bottom of a row of unequal cards.

    align-self is not decoration and it is the half this rule was missing. A flex item is blockified,
    so the inline-block button stretched to the whole column: 528px of teal on cafcanada.ca's
    /disaster-relief where the live site draws 210px. It was invisible while EVERY button was a filled
    block - a wide block among wide blocks reads as a design - and became obvious the moment the
    treatments were told apart. Measured against the live page, which is the only reason it is 210 and
    not "looks about right".

    TWO OWNERS, ONE RULE, which is why the name had to change in one pass across both of them. The
    Columns section emits it for the "Equal columns" style and the media-and-text widget emits it for
    "Keep the button at the foot of the text" - hence the two selectors, one reaching a section column
    and one reaching the widget's own text side. It was the client's `.who-we-serve` until 5 October
    2026: the name of the page it was first seen on, which said nothing about what it does.
*/
.caf-pinned-buttons .caf-section__column,
.caf-pinned-buttons .caf-media-text__text { display: flex; flex-direction: column; }
.caf-pinned-buttons .caf-button { margin-top: auto; align-self: start; }

/*
    THE FLAT ORANGE BUTTON — the client's own `.orange-button` until 5 October 2026, renamed into our
    own vocabulary and kept SEPARATE from `.caf-button--corner` above.

    THE SEPARATION IS THE POINT AND IT IS NOT TIDINESS. Fill and position are two different asks, and
    two different things ask for them: the corner button wants both, and `_TileGrid.cshtml` wants the
    fill ALONE. Fold them into one name and the tile grid's button inherits `position: absolute;
    right: -20px; bottom: -20px` and leaves its row. The old pair had this right by accident of being
    two client names; it is now right on purpose.

    Note this is the only button treatment that does NOT carry `.caf-button` on the tile grid, so it
    draws its own box there and gets no chevron. On the corner button it sits over `.caf-button` and
    overrides the fill while the chevron stays.

    It is worth keeping why the treatment exists. `.orange-button` is theirs, it is on 80 modules
    across the two exports (29 America, 51 Canada) plus the America body layout, and it arrived inside
    raw `et_pb_code` blocks that the HTML widget emits verbatim — so nothing this project wrote had
    ever styled it and every one of them was an unstyled inline link. On the home page's "Our Insights"
    row that was the whole of the difference from production: live shows an orange block at the right
    of the heading, ours showed dark teal body text. Those 80 are no longer carried under their own
    name — the standard button absorbed them — so this rule now draws exactly the corner placements.

    Every value is a COMPUTED value read off the rendered live home page on 17 September 2026, the
    same method the button variants used and for the same reason: `.orange-button` is in neither child
    stylesheet — it is generated per-module and appears on the page and in no file we can fetch.

        background #ff3b21, white, padding 10px 32px 9px, 17px/400 Outfit uppercase, radius 0, 46px tall

    Note 400 rather than the 600 `.caf-button` uses. They are different buttons: `.caf-button` is the
    Divi module button this project draws, and this is the client's own hand-written one.
*/
.caf-button--flat {
    display: inline-flex;
    align-items: center;
    padding: 10px 32px 9px;
    background: var(--caf-orange);
    color: var(--caf-paper);
    font-size: 1.0625rem;
    font-weight: 400;

    /* --caf-line, not 1: live's box is 46px tall from 17px text and 19px of vertical padding, which
       only adds up with the body line height. At line-height: 1 it came out 36px. */
    line-height: var(--caf-line);
    text-transform: uppercase;
    text-decoration: none;
    transition: background var(--caf-transition);
}

.caf-button--flat:hover { background: var(--caf-teal); }

/* Inside rich text, where `.fr-view a` is more specific and paints the text the link colour - orange on
   orange. It went unseen while every such button sat in a banner's dark panel, whose on-dark tokens make
   the link colour white; lifting the banners into the Hero left 26 of them on the page background. */
.fr-view .caf-button--flat { color: var(--caf-paper); }

/*
    The post slider's controls. `.pr-slider-controls` is the client's arrow pair and the link beside it.

    THE ARROWS USED TO BE HIDDEN OUTRIGHT and the reasoning is worth keeping, because half of it still
    stands: "a Page Builder widget renders in isolation and cannot own a control strip for a sibling",
    so drawing two controls that cannot do anything is worse than drawing none. What was wrong with it is
    that rendering in isolation says nothing about RUNTIME — the client's own script pairs the strip with
    the list after load, and wwwroot/js/carousel.js now does the same. Reported as "Our Insights should
    be a carousel with left and right buttons", which it is on the live site and now here.

    So the default is still hidden, and the script REVEALS the pair it has just bound by adding
    .caf-controls-ready. A page carrying a stray strip and no list draws nothing, and neither does a
    browser with JavaScript off, where the row still scrolls by drag and by wheel and the arrows would be
    the only dead thing on it. cafamerica.org itself gets this wrong: /what-we-do draws two live arrows
    whose script is not on the page.

    Measured on the live home page: two 47x46 squares in --caf-orange with 11px of padding around a 25px
    glyph, sitting immediately left of the orange link, the whole strip right-aligned. The glyph is the
    client's own PNG, which the media import already carries, so nothing here draws an arrow.

    The container keeps its layout either way, because the link lives inside it and live right-aligns the
    whole strip. Without this the block is `display: block` and the link sits at the left of a 800px
    column under two stray arrow images.
*/
.pr-slider-controls {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 1px;
}

.pr-slider-controls-left,
.pr-slider-controls-right { display: none; }

.pr-slider-controls.caf-controls-ready:not(.caf-controls-idle) .pr-slider-controls-left,
.pr-slider-controls.caf-controls-ready:not(.caf-controls-idle) .pr-slider-controls-right {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 47px;
    height: 46px;
    padding: 11px;
    background: var(--caf-orange);
    cursor: pointer;
    transition: background var(--caf-transition);
}

.pr-slider-controls-left:hover,
.pr-slider-controls-right:hover { background: var(--caf-teal); }

.pr-slider-controls-left:focus-visible,
.pr-slider-controls-right:focus-visible { outline: 2px solid var(--caf-teal); outline-offset: 2px; }

/* The glyph is inside a link-free div, so the pointer must not land on it and swallow the press. */
.pr-slider-controls img { display: block; pointer-events: none; }

/* --------------------------------------------------------------------- popups */

/*
    The migrated Popup Maker popups, rendered as native <dialog> and opened by wwwroot/js/popups.js.

    Sizing is the source's own: every record in both exports declares size "medium" and
    custom_width 640px. custom_height is deliberately NOT reproduced - all ten say 380px, and five of
    the eight built hold an embed declaring 350 to 515px, so honouring the cap would clip the form the
    popup exists to show. Each embed carries its own height as an attribute instead, which is where the
    source put it and keeps five numbers out of this file.

    No z-index rung is added. showModal() raises the dialog into the top layer, above every stacking
    context, so the existing ladder - search panel 10, header 100, nav dropdowns 110, skip link 200 -
    is untouched.

    No animation. Every record asks for a 350ms fade; this site's entire motion vocabulary is
    --caf-transition on colour, and neither live site moves anything into position.
*/
.caf-popup {
    width: min(640px, calc(100vw - 2 * var(--caf-space)));

    /* The UA default is calc(100% - 6px - 2em), which would win against the width above. */
    max-width: none;
    max-height: calc(100dvh - 2 * var(--caf-space));
    padding: 0;
    border: 0;
    background: var(--caf-paper);
    color: var(--caf-ink);
    box-shadow: 0 6px 18px rgb(13 13 13 / 12%);
}

.caf-popup::backdrop { background: rgb(13 13 13 / 60%); }

.caf-popup__panel {
    position: relative;
    max-height: inherit;
    overflow-y: auto;
    padding: var(--caf-space-large);
}

.caf-popup__content > :first-child { margin-top: 0; }

.caf-popup__close {
    position: absolute;
    top: var(--caf-space-small);
    right: var(--caf-space-small);
    padding: 0.25rem 0.5rem;
    border: 0;
    background: none;
    color: var(--caf-ink-muted);
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    transition: color var(--caf-transition);
}

.caf-popup__close:hover { color: var(--caf-orange); }

/* Width from here, height from the attribute the source declares on each embed. */
.caf-popup__frame {
    display: block;
    width: 100%;
    border: 0;
}

@media (max-width: 768px) {
    .caf-popup__panel { padding: var(--caf-space); }
}

/* ------------------------------------------------------------------- highlights

    A heading over three or four columns, each an optional icon, a figure and a label - the home
    pages' impact numbers, the reports' Key Findings, CAF American Donor Fund's giving options.

    THE SIZES ARE THIS SITE'S, NOT PRODUCTION'S. An earlier version of this block copied the live
    geometry rule for rule - a 100px icon, a 33px number, a 22px label - and the widget carried a
    per-page figure size so /advisers-report could keep its 81px and the Legacy Giving report its 55px.
    That is per-page replication, which analysis/status.md §5 decided against on 25 August 2026, and it
    was removed on 1 October. Every highlights row on the site now takes the same type scale whatever
    its source declared.

    WHAT IS REPRODUCED IS THE SHAPE: three or four equal columns, the icon beside the figure rather
    than above it, four-up becoming two-up on a tablet, and everything centring into one column at the
    stacking width. That is what makes the block recognisable; the exact number of pixels did not.
*/
.caf-highlights__items {
    display: grid;
    grid-template-columns: repeat(var(--caf-highlights-columns, 3), minmax(0, 1fr));
    gap: var(--caf-space);
}

.caf-highlights__heading { margin: 0 0 var(--caf-space); }

.caf-highlights__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--caf-space);
    text-align: left;
}

.caf-highlights__icon {
    flex: none;
    width: var(--caf-space-large);
    height: var(--caf-space-large);
    object-fit: contain;
}

.caf-highlights__value {
    margin: 0 0 var(--caf-space-small);
    font-size: var(--caf-text-h2);
    font-weight: 700;
    line-height: 1.2;
    color: var(--caf-teal);
}

.caf-highlights__label {
    margin: 0;
    font-family: var(--caf-font);
    line-height: var(--caf-line);
}

/* The options style is an icon ABOVE a sentence-case title, not a figure beside a label. */
.caf-highlights--option .caf-highlights__item { display: block; }

.caf-highlights--option .caf-highlights__icon {
    width: auto;
    margin-block-end: var(--caf-space);
}

.caf-highlights--option .caf-highlights__value { font-size: var(--caf-text-h3); }

/* A row with no icon anywhere centres its figures, which is the shape every report row has. */
.caf-highlights--figure .caf-highlights__item:not(:has(.caf-highlights__icon)) {
    display: block;
    text-align: center;
}

/* Four to a row is two to a row on a tablet, as a four-column row is everywhere else on the site. */
@media (max-width: 980px) {
    .caf-highlights--four .caf-highlights__items { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 768px) {
    .caf-highlights__items,
    .caf-highlights--four .caf-highlights__items { grid-template-columns: minmax(0, 1fr); }
    .caf-highlights__item > * { width: 100%; text-align: center; }
    .caf-highlights__icon { margin-inline: auto; }
}

/* ---------------------------------------------------------------- downloads

    A heading over a row of download tiles - a preview picture and the button that fetches the file.
    The three "Download our logos" groups on /using-the-caf-america-logo-and-badge, which converted
    to nine image widgets, nine button widgets and four rich texts over seven sections.

    THE FRAME COLOUR IS WHY A WHITE LOGO IS VISIBLE AT ALL, and it is carried, not invented. Divi
    declares background_color="#0d393b" on the et_pb_image of all three white variants; the image
    widget has nowhere to put it, so the converter dropped it on all three. CAF America and CAF
    Canada survived by accident - their preview art has the teal baked in - and Charities Aid
    Foundation did not, so it drew an invisible white square on a white page. No structural check
    sees that: a white picture on white is not low-contrast text, which is why --visual-sweep
    reported only the brand-orange findings every page has. Found by opening the file.

    THE SHAPE, NOT THE MEASUREMENTS. Divi drew these as 1_3 columns at 29.6667% with a 5.5% gutter.
    What is reproduced is three equal columns with the button under the picture, stacking the way
    every other grid on the site stacks; the gutter percentages are the design system's own spacing
    token. analysis/status.md section 5 decided against carrying per-page geometry on 25 August 2026.
*/
.caf-downloads { margin-block: var(--caf-space); }
.caf-downloads__heading { margin: 0 0 var(--caf-space); }

.caf-downloads__tiles {
    display: grid;
    grid-template-columns: repeat(var(--caf-downloads-columns, 3), minmax(0, 1fr));
    gap: var(--caf-space);
    margin: 0;
    padding: 0;
    list-style: none;
}

.caf-downloads__tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--caf-space-small);
    text-align: center;
}

/* What the slot colour paints. Transparent by default, so a tile that carries none is unchanged. */
.caf-downloads__frame {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    background-color: var(--caf-downloads-frame, transparent);
}

.caf-downloads__image {
    max-width: 100%;
    height: auto;
    object-fit: contain;
}

/* The button sits at the foot of every tile whatever its picture did, so a row of mismatched logo
   heights still reads as a row rather than a staircase. */
.caf-downloads__tile > .caf-button { margin-top: auto; }

/* Four to a row is two to a row on a tablet, as Divi draws a four-column row; three stack. */
@media (max-width: 980px) {
    .caf-downloads--four .caf-downloads__tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 768px) {
    .caf-downloads__tiles,
    .caf-downloads--four .caf-downloads__tiles { grid-template-columns: minmax(0, 1fr); }
}

/*
    THE ERROR PAGE
    ==============

    Views/Error/Index.cshtml, served for a 404, a 403 and an unhandled 500 - see ErrorController.

    It lands in <main> as a bare child, so .caf-page > :not(.caf-section, .caf-body, .caf-search-page)
    already gives it the site measure and centres it. Nothing here restates that; what is here is the
    vertical rhythm, which the rule above cannot know, and the one thing the page genuinely needs:
    enough height that a short message does not leave the footer riding up under the header on a tall
    screen. 40vh is that floor, chosen as a floor rather than a height so long copy still grows.
*/
.caf-error {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    min-height: 40vh;
    padding-block: var(--caf-space-large);
}

/* The number, above the heading and quiet. Letter-spaced because it is read as a label rather than as
   a word, which is the treatment the eyebrow in the page hero already uses. */
.caf-error__code {
    margin: 0 0 var(--caf-space-small);
    color: var(--caf-ink-muted);
    font-family: var(--caf-font);
    font-size: var(--caf-text-small);
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

/*
    The brand h1 is 54px and uppercase, which is right for the page and wrong at 375px - "SOMETHING
    WENT WRONG" breaks to four lines there. The clamp is the page hero's own pattern (5vw between a
    floor and the brand size), so the error heading shrinks exactly as a hero title does rather than
    inventing a second scale.
*/
.caf-error__title {
    margin: 0;
    font-size: clamp(2rem, 5vw, var(--caf-text-h1));
    line-height: var(--caf-line-tight);
}

.caf-error__message {
    max-width: 48ch;
    margin: var(--caf-space) 0 0;
    font-size: var(--caf-text-lead);
    color: var(--caf-ink-muted);
}

/* Two buttons, wrapping rather than overflowing on a phone - at 375px the pair is wider than the
   measure, and a row that cannot wrap is the sideways scroll --visual-sweep reports. */
.caf-error__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--caf-space-small);
    margin: var(--caf-space-large) 0 0;
}

/* ---------------------------------------------------------------------------------------------- */
/* Page gate                                                                                        */
/* ---------------------------------------------------------------------------------------------- */

/*
    The password form that stands in place of a gated page's body. It sits INSIDE the page's own hero
    and furniture - the filter keeps those - so this styles the panel alone and inherits everything
    above it.

    Narrower than the error panel on purpose: this is one short sentence and one input, and a full
    measure makes a lone password box look like an oversight. The min-height stops a short panel
    leaving the footer high up a tall viewport, which is the shape --visual-sweep reads as a blank
    zone.
*/
.caf-page-gate {
    max-width: 34rem;
    min-height: 32vh;
    margin-inline: auto;
    padding-block: var(--caf-space-large);
    padding-inline: var(--caf-space);
}

/* Clamped on the page hero's pattern, for the error title's reason: the brand h1 is 54px and
   uppercase, which breaks to four lines at 375px. */
.caf-page-gate__title {
    margin: 0;
    font-size: clamp(1.75rem, 5vw, var(--caf-text-h1));
    line-height: var(--caf-line-tight);
}

.caf-page-gate__message {
    max-width: 48ch;
    margin: var(--caf-space) 0 0;
    font-size: var(--caf-text-lead);
    color: var(--caf-ink-muted);
}

/* The refusal, in the colour this site already refuses things in: .caf-form .field-validation-error
   (line 4128) is --caf-orange, so a wrong password reads the same as any other rejected field rather
   than introducing a second error colour. Given weight because it is the one thing on the page that
   has changed since the visitor last looked at it. */
.caf-page-gate__error {
    margin: var(--caf-space) 0 0;
    font-weight: 600;
    color: var(--caf-orange);
}

.caf-page-gate__form {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--caf-space-small);
    margin-block-start: var(--caf-space-large);
}

.caf-page-gate__label {
    font-family: var(--caf-font);
    font-size: var(--caf-text-small);
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

/*
    Full width of the panel at every size. A password box sized to a guess at the password's length is
    the one input that must not be, and box-sizing keeps the padding inside the measure so this cannot
    be the element that makes the page scroll sideways.
*/
.caf-page-gate__input {
    width: 100%;
    box-sizing: border-box;
    padding: var(--caf-space-small);
    font-family: var(--caf-font);
    font-size: var(--caf-text-lead);
    border: 1px solid var(--caf-rule, #c9c9c9);
    border-radius: 2px;
}

.caf-page-gate__button {
    margin-block-start: var(--caf-space-small);
}

/* ---------------------------------------------------------------------------------------------- */
/* Print                                                                                            */
/* ---------------------------------------------------------------------------------------------- */

/* Nothing here had a print stylesheet until 19 October 2026, so printing any page carried the header,
   the footer, the donation widget and - on 335 pages - a marketing dialog, then dropped every
   background tint to white and left light text on it unreadable.

   These sites are printed. The grant guidance, the wiring instructions, the fact sheets and the KYC
   pages are reference documents that people take to a bank or a board, which is why this is not
   cosmetic.

   Scoped entirely to @media print: nothing below changes a pixel on screen. */
@media print {
    /* The furniture, and the two things that are not content at all. A dialog is display:none unless
       open, but one a visitor opened before printing is in the top layer and would otherwise be the
       whole of the first page. */
    .caf-header,
    .caf-footer,
    .caf-skip-link,
    .caf-popup,
    dialog {
        display: none !important;
    }

    /* Paint nothing. A tint printed as a pale wash costs ink and gains nothing, and an "on dark" panel
       whose background drops out prints near-white text on white - the defect this whole block exists
       to prevent. Both revert to the document's own ink. */
    .caf-tinted,
    .caf-tinted--on-dark,
    .caf-backdrop {
        background: none !important;
        color: #000 !important;
    }

    .caf-tinted--on-dark a {
        color: #000 !important;
    }

    body {
        background: #fff;
        color: #000;
    }

    /* The address behind a link, since a printed page cannot be clicked. Only for real destinations:
       an in-page anchor prints "(#section)", which is noise, and a javascript: or mailto: href already
       reads as what it is. */
    .caf-page a[href^="http"]::after,
    .caf-page a[href^="/"]::after {
        content: " (" attr(href) ")";
        font-size: 0.85em;
        word-break: break-all;
    }

    /* A heading stranded at the foot of a sheet with its text overleaf is the commonest print defect
       in long guidance, which is most of what gets printed here. */
    h1, h2, h3, h4 {
        break-after: avoid-page;
    }

    img, figure, table, blockquote {
        break-inside: avoid;
    }

    /* The band paddings are sized for a screen and waste most of a sheet. */
    .caf-section {
        padding-block: 0.5rem !important;
    }
}
