/* HBA of Dothan — authored lane, COMPONENT layer.
 *
 * Cascade position (hba-site.php): site.css → body.css → THIS FILE → hero.css → motion.css.
 * It may rely on site.css (chrome, container ladder) and body.css (fields, sections, headings,
 * grids, lists) having run, and it restates nothing from either.
 *
 * PROVENANCE. Every value below is sourced, in this order of authority:
 *   H   hba-capture/content/html/*.html   — the LIVE DOM exactly as served: real Tailwind
 *                                           classes and inline styles. Highest authority; where
 *                                           it disagrees with the token files, it wins.
 *   C   hba-capture/screenshots/w1440|w390/*.png — exact-pixel read of the capture
 *   O   docs/design/measurements/observed-tokens.json
 *   M   docs/design/measurements/tokens-measured.json
 *   T   docs/design/tokens.json
 *   D   DECISIONS.md / COMPONENT_MAP.md / INTERACTIONS.md / STYLE_GUIDE.md
 * Anything that could not be sourced is marked ⚠ UNSOURCED with what was done instead. There
 * are no silent guesses in this file.
 *
 * ⛔ NO `rem` ANYWHERE, DELIBERATELY. Bricks' frontend-layer.min.css ships
 * `html { font-size: 62.5% }`, so this build's root is 10px while the live source's Tailwind ran
 * at 16px. A live value transcribed as `rem` renders at 0.625× and still looks plausible. Every
 * length here is px. Tailwind's rem-based scale is converted at the SOURCE's 16px root:
 * text-xs 12 · text-sm 14 · text-base 16 · text-lg 18 · text-xl 20 · text-2xl 24 · text-3xl 30;
 * p-5 20 · p-6 24 · p-7 28 · p-8 32; gap-3 12 · gap-4 16 · gap-5 20 · gap-8 32 · gap-14 56.
 *
 * The Bricks colour palette is already published as :root custom properties (verified in the
 * rendered `bricks-frontend-inline` block), so tokens are referenced through them with literal
 * fallbacks — one fact, one home.
 *
 * SPECIFICITY, MEASURED NOT ASSUMED (STYLE_GUIDE trap 6):
 *   Bricks emits per-element ID rules at (1,0,0). Verified on the rendered page:
 *       #brxe-bb780d { border: 1px solid #f3f4f6 }
 *   compose-pages.php's `$card()` sets that border on EVERY card, including the two H shows with
 *   no border at all and the stub H does not render as a card. No class chain can beat (1,0,0),
 *   so exactly two rules here use `!important` — with the winning rule proven first, never as a
 *   default reach. Every other rule wins at plain class specificity.
 *
 * EASING. H shows every hover in this file uses Tailwind's default timing function, which is the
 * standard `cubic-bezier(0.4, 0, 0.2, 1)`. The expressive `cubic-bezier(0.23, 1, 0.32, 1)` is
 * NOT used anywhere in this file — H confirms its consumers are the hero's `fadeInUp` entrances
 * and the scroll reveal, not these components (STYLE_GUIDE §5 / trap: do not spread it).
 */

/* =========================================================================
 * CARDS
 * =====================================================================  */

/* ⛔ THE BASE CARD HAD NO RULE AT ALL UNTIL 2026-08-21, AND IT IS THE LARGEST
 * SINGLE DEFECT IN THE OWNER'S INTERIOR REVIEW.
 *
 * compose-pages.php's `$card()` gives every card `hba-card` plus a Bricks
 * per-element border (`1px solid #f3f4f6`, (1,0,0)) and NOTHING else. Twelve call
 * sites; five pass no modifier — /about Core Values, /events Featured Events,
 * /news local news, /news HBAA items, /become-a-member Membership Types — so five
 * card families rendered as unfilled, unpadded, square-cornered text blocks
 * separated from the field by an invisible hairline. The modifiers inherited the
 * same hole: `--dark` set a fill but never a padding, because COMPONENT_MAP C-20
 * says "padding is the base card's prop … left to body.css" and body.css never
 * claimed it. One fact, NO home. Confirmed by grep across all four stylesheets
 * before writing this: `.hba-card` appeared only in a transition, a hover
 * border and motion.css's lift.
 *
 * H, the modal live card: `bg-white rounded-xl p-7 shadow-md border border-gray-100`.
 * Padding tally over the captured routes: p-7 x11 (/benefits groups x6,
 * membership types x3, /about federation x2), p-8 x5, p-6 x4, p-5 x8. p-7 is the
 * modal box-card padding AND is exactly what both families that take this base
 * unchanged measure. Every family that differs overrides it below.
 * The BORDER is deliberately not set here: Bricks already paints it at (1,0,0)
 * and its colour is live's border-gray-100 to the byte. */
.hba-card {
  background: var(--hba-white, #ffffff);
  border-radius: var(--hba-radius-card, 12px); /* H rounded-xl */
  padding: 28px;                               /* H p-7 */
  box-shadow: var(--hba-shadow-card, rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.1) 0px 2px 4px -2px); /* H shadow-md */
}

/* ⛔ THE CARD INTERIOR HAD NO RHYTHM AT ALL UNTIL 2026-08-21 (RHYTHM ROUND), AND
 * IT IS THE DEFECT THE OWNER NAMED: "things need more room to breathe."
 *
 * body.css carries the type rhythm as DIRECT-CHILD rules on `.hba-section__inner
 * > *`. That stops at the first nesting level, so nothing inside a card ever
 * received a margin: the source line, the title and the excerpt sat flush against
 * one another at zero, and the excerpt kept .hba-body's 18/29.25 SECTION-LEAD
 * register where every live card runs 14/22.75. Correct content, correct colour,
 * correct section padding, every block jammed against the next — docs/design/
 * RHYTHM_TRUTH.md's whole subject.
 *
 * THE RULE THAT GENERALISES (RHYTHM_TRUTH §"The rule that generalises"): live
 * carries card rhythm as MARGINS ON THE TYPE ELEMENTS, not as gaps on the parent.
 * Restated the same way here.
 *
 * ⛔ ONE MECHANISM ONLY, AND THE REASON IS FLEXBOX. Bricks renders every card as a
 * `.brxe-container` flex column, where adjoining margins DO NOT COLLAPSE — a
 * margin-bottom of 12 above a margin-top of 16 paints 28px, not 16. So the whole
 * file states card rhythm as `margin-bottom` on the element above, and reserves
 * `margin-top` for a TRAILING link that has nothing below it. Mixing the two is
 * how this register silently doubles.
 *
 * THE MODAL REGISTER, counted over the twelve live card families in H:
 *   kicker / source line  mb-3 = 12   home news x3
 *   card title h3         mb-3 = 12   home news x3, core values x3, affiliate x2,
 *                                     membership types x3, /news local x3
 *                         mb-2 = 8    home savings x2, /about federation x2
 *                         mb-4 = 16   /benefits groups x6
 *   card body copy        text-sm leading-relaxed = 14/22.75 — ALL of them, with
 *                                     no exception on any route
 *   trailing card link    mt-4 = 16   home news, /news local; the two families
 *                                     that instead carry mb-4 on the paragraph
 *                                     above measure the same 16 either way
 * 12 / 14-22.75 / 16 are authored as the BASE. The three families live measures
 * differently restate their own value below, exactly as the padding tally does.
 *
 * PLACEMENT IS DELIBERATE. This block sits immediately after the base card and
 * BEFORE every family, so a family rule of equal specificity wins on source order
 * and nothing below has to inflate its selector to keep the value it measured. */
.hba-card > .hba-kicker  { margin-bottom: 12px; } /* H mb-3 */
.hba-card > .hba-heading { margin-bottom: 12px; } /* H mb-3 */
.hba-card > .hba-cta     { margin-top: 16px; }    /* H mt-4 */

/* ⛔ THE :not() LIST IS LOAD-BEARING, AND EVERY ENTRY IS A REGISTER LIVE MEASURES
 * SEPARATELY. Each of them rides on .hba-body — `<p class="hba-body hba-meta">` —
 * so a descendant rule aimed at a card's copy reaches them too, at a specificity
 * their own (0,1,0) rule cannot answer. Exactly the trap body.css documents for
 * .hba-meta / .hba-kicker and this file already documents twice, for
 * .hba-placeholder and .hba-timeline__marker. Sizes each one must keep:
 *   kicker 12/16 · meta 14/20 · chip 12/16 · card__label 24/32 ·
 *   eventcard__date 12/16 · statcard value/label/sub 24/30, 14/20, 12/16
 * Verified by walking every $para() call site in compose-pages.php that lands
 * inside a $card(), not by guessing at the list. */
.hba-card .hba-body:not(.hba-kicker, .hba-meta, .hba-chip, .hba-placeholder,
                        .hba-card__label, .hba-eventcard__date,
                        .hba-statcard__value, .hba-statcard__label, .hba-statcard__sub) {
  font-size: 14px;      /* H text-sm, every card family on live */
  line-height: 22.75px; /* H leading-relaxed, 14 x 1.625 */
}

/* C-20 on a dark ground. H, identical on both routes that use it:
 *   /news  `bg-white/5 hover:bg-white/10 border border-white/10 hover:border-amber-400/40
 *           rounded-xl p-5 transition-all duration-300`
 *   /      the same with `p-6`
 * ✅ PADDING — THE SPLIT THE OLD NOTE ASKED FOR IS NOW POSSIBLE, 2026-08-21
 * (rhythm round). The note that stood here read "p-5 = 20px is the majority: 5 of
 * the 8 live dark cards (/news' NAHB grid) carry p-5, 3 (home's news band) carry
 * p-6. ⚠ Home's three will be 4px tight; one class, two live registers, and no
 * structural difference between them — reported rather than split on a guess."
 * There IS a structural difference now: the interior round gave the /news grid its
 * own `hba-newscard` name and the /benefits pair `--icon --center`. So the base
 * takes home's p-6 and each of the other two restates its own measured value —
 * `.hba-newscard` p-5 and `--center` p-8, both further down this file. This is the
 * 4px the owner's Industry News pair was short.
 * NO SHADOW on live at any of the eight, so the base's shadow-md is cleared. */
.hba-card--dark {
  padding: 24px;      /* H p-6 (home news band; the two other --dark families restate their own) */
  box-shadow: none;   /* H: none of the eight carries one */
  background: var(--hba-white-white05, rgba(255, 255, 255, 0.051));
  border-color: var(--hba-white-white10, rgba(255, 255, 255, 0.102));
  border-radius: var(--hba-radius-card, 12px);
  color: var(--hba-white-white90, rgba(255, 255, 255, 0.902));
  transition: background-color var(--hba-duration-slow, 300ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1)),
              border-color var(--hba-duration-slow, 300ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-card--dark .hba-heading,
.hba-card--dark h2,
.hba-card--dark h3 { color: var(--hba-white, #ffffff); }
.hba-card--dark .hba-body { color: var(--hba-white-white70, rgba(255, 255, 255, 0.698)); }
/* The kicker rides on .hba-body (`<p class="hba-body hba-kicker">`), so the (0,2,0)
 * rule above beats body.css's (0,1,0) `.hba-kicker` ink and the dark cards' kickers
 * painted white/70. Owner caught it on home's Industry News. H (Home.tsx:522):
 * `text-amber-400` = amberInk. Restated here at (0,2,0) after the body rule. */
.hba-card--dark .hba-kicker { color: #ffb900; }
/* HOME INDUSTRY NEWS — the one --dark family whose h3 is not the body.css default.
 * H (Home.tsx:522-532), the card the owner reviewed, verbatim:
 *   kicker `text-amber-400 text-xs font-['Oswald'] tracking-wider uppercase mb-3`
 *   h3     `font-['Oswald'] font-semibold text-white text-lg leading-snug mb-3`
 *   p      `text-white/60 font-['Source_Sans_3'] text-sm leading-relaxed`
 *   link   `mt-4 text-amber-400 text-sm font-['Oswald'] flex items-center gap-1`
 * Everything but the h3 SIZE is already carried by the base interior register at
 * the top of this file (kicker mb 12, h3 mb 12, body 14/22.75, link mt 16). Live
 * runs this title at text-lg leading-snug SEMIBOLD where body.css's h3 register is
 * 20/28 bold, so only that is restated.
 * `:not(.hba-card--icon)` is the discriminator, and it is load-bearing: the
 * /benefits affiliate pair is also `--dark` with a direct-child h3, and live keeps
 * that one at text-xl. The /news NAHB grid needs no exclusion — its h3 sits inside
 * `.hba-newscard__copy`, so the child combinator never reaches it. */
.hba-card--dark:not(.hba-card--icon) > .hba-heading {
  font-size: 18px;      /* H text-lg */
  line-height: 24.75px; /* H leading-snug, 18 x 1.375 */
  font-weight: 600;     /* H font-semibold, not the h3 default 700 */
}
/* H `hover:bg-white/10 hover:border-amber-400/40`. Colour only — nothing reflows
 * (D INTERACTIONS I-04: reflow-on-hover is a DEFECT-FIX, not a parity target). */
.hba-card--dark:hover {
  background: var(--hba-white-white10, rgba(255, 255, 255, 0.102));
  border-color: rgba(255, 185, 0, 0.4); /* amber-400/40 = amberInk #ffb900 at 40% */
}

/* C-89 / C-30 icon card.
 * ⚠ ONE CLASS, TWO LIVE TREATMENTS. compose-pages.php gives `hba-card--icon` both to the six
 * /benefits group cards and to the two "affiliated" cards, which H shows are different:
 *   group      `bg-white rounded-xl p-7 shadow-md border border-gray-100
 *               hover:border-[#1e3a5f]/30 hover:shadow-xl transition-all duration-300`
 *   affiliated `bg-[#0d1b2a] rounded-xl p-8 flex flex-col items-center text-center
 *               hover:bg-[#1e3a5f] transition-colors duration-300`   ← no border at all
 * The base rule is the six-card treatment; the pair is reached through its own icon variants,
 * the only structural difference the DOM offers. A `hba-card--icon--dark` modifier in
 * compose-pages.php would remove the :has() dependency — raised with the TL. */
.hba-card--icon {
  border-radius: var(--hba-radius-card, 12px);
  padding: 28px; /* H p-7 */
}
.hba-card--icon:has(.hba-icon--house),
.hba-card--icon:has(.hba-icon--national) {
  background: var(--hba-charcoal, #0d1b2a);
  padding: 32px; /* H p-8 */
  box-shadow: none; /* H paints no shadow on this pair; clears the base card's shadow-md */
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  color: var(--hba-white-white70, rgba(255, 255, 255, 0.698));
  transition: background-color var(--hba-duration-slow, 300ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
  /* H paints NO border on this card. Removing the Bricks (1,0,0) `$card()` border is the one
   * thing a class chain cannot do — proven above, not assumed. */
  border: 0 !important;
}
.hba-card--icon:has(.hba-icon--house):hover,
.hba-card--icon:has(.hba-icon--national):hover { background: var(--hba-navy, #1e3a5f); }
.hba-card--icon:has(.hba-icon--house) .hba-heading,
.hba-card--icon:has(.hba-icon--national) .hba-heading { color: var(--hba-white, #ffffff); }
.hba-card--icon:has(.hba-icon--house) .hba-body,
.hba-card--icon:has(.hba-icon--national) .hba-body { color: var(--hba-white-white70, rgba(255, 255, 255, 0.698)); }

/* C-60 coming-soon stub. H: this is NOT a card on live — it is
 * `<div class="max-w-xl mx-auto text-center">` with an
 * `<div class="w-20 h-20 bg-amber-500/10 rounded-full … mx-auto mb-6">` holding a 40px lucide
 * clock in `text-amber-500`. No fill, no border, no shadow on the block itself. */
.hba-soon {
  max-width: 576px; /* H max-w-xl */
  margin-inline: auto;
  padding: 0;
  text-align: center;
  background: none;
  box-shadow: none;
  border: 0;   /* no !important needed since 2026-08-21: the composition no longer
                * builds this with $card(), so there is no (1,0,0) hairline to fight. */
}
/* The disc and its glyph are reproduced exactly: H gives the 80px amber-500/10 disc, and the
 * mark is lucide's `clock` — circle r=10 plus the polyline "12 6 12 12 16 14", 2px round stroke,
 * no fill, 40×40, stroked in amber-500 (T amberFill #fe9a00). */
.hba-soon::before {
  content: "";
  display: block;
  width: 80px;
  height: 80px;
  margin: 0 auto 24px; /* H mb-6 */
  border-radius: var(--hba-radius-pill, 9999px);
  background-color: var(--hba-ambertint-10, rgba(245, 147, 0, 0.102));
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23fe9a00' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 40px 40px;
}
/* RHYTHM ROUND: the stub's own type rhythm, which was never authored — the disc
 * carried its mb-6 and then the heading, the paragraph and the action row stacked
 * at zero. `.hba-soon` is a component wrapper, so body.css's section-flow rules
 * stop at it, exactly as they do at a card.
 * H (BoardOfDirectors.tsx:38/41, and identical on /find-a-member and
 * /client-portal), verbatim:
 *   h2  `font-['Oswald'] font-bold text-[#0d1b2a] text-3xl mb-4`
 *   p   `text-gray-600 font-['Source_Sans_3'] text-lg leading-relaxed mb-8`
 * The size on both is already right (body.css h2 30/36, .hba-body 18/29.25 — this
 * is one of the few paragraphs on the site that really is the section-lead
 * register), so only the margins are stated. The 32 also supplies the gap above
 * the action row without touching `.hba-actions`, which is body.css's. */
.hba-soon > .hba-heading { margin-bottom: 16px; } /* H mb-4 */
.hba-soon > .hba-body    { margin-bottom: 32px; } /* H mb-8 */

/* =========================================================================
 * QUICK-LINK TILES — C-82 (layout answer is OPEN O-1)
 * =====================================================================  */

/* H, verbatim: `portal-block bg-gradient-to-br from-[#1a3356] to-[#0f2240]
 * border border-amber-500/40 rounded-lg p-6 lg:p-7 flex flex-col items-center justify-center
 * text-center gap-3 min-h-[160px] lg:min-h-[175px] group relative overflow-hidden`
 * in a `grid grid-cols-2 gap-4` rail.
 *
 * ⚠ TWO UNRECORDED LITERALS. `#1a3356` and `#0f2240` are the tile's gradient stops and appear
 * NOWHERE in tokens.json — not in the palette, not in color.component. They are reported to the
 * TL for entry at source. The fill is OPAQUE (my earlier read of it as translucent navy was
 * wrong; the pixel variation across the tile is the gradient, not the photo showing through),
 * so the tile reads correctly on the navy field compose-pages.php puts it on and NO deviation
 * from live is needed here.
 *
 * ⚠ ONE THING IS MISSING AND IS NOT INVENTED: H puts a 56px `bg-white/10` disc holding a 26px
 * per-tile lucide icon above the title, hovering to `bg-amber-500/20` + `text-amber-400`.
 * compose-pages.php emits no element and no per-tile class for it, so there is no hook to hang
 * it on. Reported rather than approximated.
 *
 * The 3-up rail below is compose-pages.php's (live is 2×2 in the hero) and is O-1's to settle. */
.hba-tiles {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px; /* H gap-4 */
}
.hba-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* H's `gap-3` (12px) sits between the icon disc and the text block, and this markup has no
   * disc — so no gap here; the title/description spacing is H's `mt-1` on the description. */
  min-height: 160px; /* H min-h-[160px] */
  padding: 24px; /* H p-6 */
  text-align: center;
  text-decoration: none;
  border-radius: var(--hba-radius-input, 8px); /* H rounded-lg */
  background-image: linear-gradient(to bottom right, #1a3356, #0f2240);
  border: 1px solid var(--hba-ambertint-40, rgba(252, 152, 0, 0.400)); /* H border-amber-500/40 */
  position: relative;
  overflow: hidden;
  /* ✅ THE "UNSOURCED" MARKER THAT USED TO SIT HERE IS RESOLVED — 2026-08-21.
   * The previous note said the tile "carries no hover fill" and raised its border
   * to full amberFill as a stand-in, flagged as the file's one unsourced hover.
   * It was not unsourced; it was just not a utility class. Live's hover lives in
   * a hand-written rule in the app's own stylesheet (`client/src/index.css:144`),
   * which is invisible if you only read the JSX className:
   *
   *     .portal-block          transition: transform .2s cubic-bezier(.23,1,.32,1),
   *                                        box-shadow .2s cubic-bezier(.23,1,.32,1);
   *     .portal-block:hover    transform: translateY(-4px) scale(1.02);
   *                            box-shadow: 0 20px 40px rgba(0,0,0,.4);
   *     .portal-block:active   transform: scale(.97);
   *
   * The owner asked for the drop shadow by eye before anyone found the rule.
   * Lesson worth keeping: a Tailwind codebase still has hand-written CSS, and
   * "the class list is the whole story" is an assumption, not a fact. */
  transition: transform 200ms cubic-bezier(0.23, 1, 0.32, 1),
              box-shadow 200ms cubic-bezier(0.23, 1, 0.32, 1);
}
.hba-tile:hover {
  transform: translateY(-4px) scale(1.02);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
}
.hba-tile:active { transform: scale(0.97); }
/* H `font-['Oswald'] font-bold text-white text-base lg:text-lg leading-tight tracking-wide`. */
.hba-tile__title {
  font-family: var(--hba-font-display);
  font-size: 16px;
  line-height: 20px;
  font-weight: 700;
  letter-spacing: 0.4px; /* tracking-wide 0.025em at 16px */
  color: var(--hba-white, #ffffff);
  margin: 0;
}
/* H `text-white/55 text-xs font-['Source_Sans_3'] mt-1`.
 * ⚠ TOKENS.JSON DISAGREEMENT: T's alpha ladder calls white/55 "one footer micro-label … a live
 * inconsistency, carried" (12 occurrences). It is not a footer label — it is THIS, the home
 * quick-link tile description, 4 tiles × 3 sampled widths. Reported for correction at source. */
.hba-tile__desc {
  font-family: var(--hba-font-text);
  font-size: 12px;
  line-height: 16px;
  color: var(--hba-white-white55, rgba(255, 255, 255, 0.549));
  margin: 4px 0 0; /* H mt-1 */
}

/* =========================================================================
 * CATEGORY CHIPS — C-11
 *
 * ⛔ THE COLOUR MAP IS POSITIONAL, NOT SEMANTIC, AND THERE ARE TWO INDEPENDENT MAPS.
 * "Education" is amberFill on the event surfaces and EMERALD on /news. Both maps below are read
 * DIRECTLY out of the live DOM (H) — the class list on each chip span, not an inference — and
 * cross-checked against the 1440 capture by exact-pixel location and against
 * D DECISIONS.md HBA-D-9.
 * A single taxonomy-wide map repaints /news and is battery row B-13. Do not merge them.
 * =====================================================================  */

/* Geometry, H verbatim and identical on all three routes:
 *   `text-xs font-['Oswald'] font-semibold px-2.5 py-0.5 rounded-full <fill> text-white`
 * = 12px/16px Oswald 600, padding 2px 10px, pill radius, white ink, no tracking.
 * (T type.chip agrees. C confirms a 20px painted height on /events, /calendar and /news.) */
.hba-chip {
  display: inline-block;
  font-family: var(--hba-font-display);
  font-size: 12px;
  line-height: 16px;
  font-weight: 600;
  letter-spacing: normal;
  padding: 2px 10px;
  border-radius: var(--hba-radius-pill, 9999px);
  color: var(--hba-white, #ffffff);
  vertical-align: middle;
  margin: 0;
}

/* ---- MAP 1 — EVENT SURFACES (/events, /calendar) ------------------------
 * H, events.html and calendar.html, one chip span each:
 *   Board     → bg-[#1e3a5f]
 *   Education → bg-amber-500    (#fe9a00)
 *   Social    → bg-emerald-600  (#009966)
 *   Showcase  → bg-purple-600   (#9810fa) */
.hba-chip--board     { background: var(--hba-chipboard, #1e3a5f); }     /* Board     → navy    */
.hba-chip--education { background: var(--hba-chipeducation, #fe9a00); } /* Education → AMBER   */
.hba-chip--social    { background: var(--hba-chipsocial, #009966); }    /* Social    → emerald */
.hba-chip--showcase  { background: var(--hba-chipshowcase, #9810fa); }  /* Showcase  → purple  */

/* ---- MAP 2 — NEWS SURFACE (/news). INDEPENDENT OF MAP 1. ----------------
 * H, news.html, the only three chip spans on the route:
 *   "Association News" → bg-[#1e3a5f]
 *   "Events"           → bg-amber-500    (#fe9a00)
 *   "Education"        → bg-emerald-600  (#009966)   ← EMERALD, not amber
 * There is no purple anywhere on /news. */
.hba-chip--news-1 { background: var(--hba-chipboard, #1e3a5f); }     /* Association News → navy    */
.hba-chip--news-2 { background: var(--hba-chipeducation, #fe9a00); } /* Events           → amber   */
.hba-chip--news-3 { background: var(--hba-chipsocial, #009966); }    /* Education        → EMERALD */

/* =========================================================================
 * EVENTS — C-10 / C-06
 * =====================================================================  */

/* Home "Upcoming Events". H, verbatim:
 *   <a class="reveal flex items-center gap-5 p-5 rounded-xl border border-gray-100
 *             hover:border-[#1e3a5f]/30 hover:shadow-md bg-white transition-all duration-200">
 *     <div class="w-14 h-14 bg-[#1e3a5f] rounded-lg flex flex-col items-center justify-center">
 *       <div class="font-['Oswald'] font-bold text-white text-sm leading-none">Jul</div>
 *       <div class="font-['Oswald'] text-amber-400 text-xs">15</div>
 * NOTE: NO shadow at rest — the shadow appears only on hover.
 * The rail is `space-y-3` = 12px, which C confirms (row boxes 98px tall, 12px apart). */
.hba-eventrow {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.hba-eventchip {
  position: relative;
  display: block;
  min-height: 96px; /* 20 padding + 56 chip + 20 padding */
  padding: 20px 20px 20px 96px; /* H p-5 + the 56px chip + H gap-5 */
  background: var(--hba-white, #ffffff);
  border: 1px solid var(--hba-hairline, #f3f4f6);
  border-radius: var(--hba-radius-card, 12px);
  text-decoration: none;
  transition: box-shadow var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1)),
              border-color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-eventchip::before {
  content: "";
  position: absolute;
  left: 20px;
  top: 20px;
  width: 56px;  /* H w-14 */
  height: 56px; /* H h-14 */
  border-radius: var(--hba-radius-input, 8px); /* H rounded-lg */
  background: var(--hba-navy, #1e3a5f);
}
/* H `hover:border-[#1e3a5f]/30 hover:shadow-md` on both event lists. shadow-md is T shadow.card.
 * D INTERACTIONS I-05/I-07 asks for one hover treatment across the card families; this is that
 * treatment — border + shadow, no transform, and therefore no layout shift (I-04). */
.hba-eventchip:hover,
.hba-eventlist__row:hover {
  border-color: rgba(30, 58, 95, 0.3); /* H #1e3a5f/30 */
  box-shadow: var(--hba-shadow-card, rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.1) 0px 2px 4px -2px);
}

/* MONTH over DAY on the home chip — compose-pages.php emits month first here and so does live.
 * H: month `font-bold text-white text-sm leading-none` = 14px/1 700 #fff; day
 * `text-amber-400 text-xs` = 12px/16 400 #ffb900 (weight 400, NOT bold, and no tracking).
 * The pair is `flex flex-col justify-center` in a 56px box: 14 + 16 = 30px centred ⇒ 13px in. */
.hba-eventchip > .hba-eventchip__month,
.hba-eventchip > .hba-eventchip__day {
  position: absolute;
  left: 20px;
  width: 56px;
  margin: 0;
  text-align: center;
  font-family: var(--hba-font-display);
}
.hba-eventchip > .hba-eventchip__month {
  top: 33px;
  font-size: 14px;
  line-height: 14px; /* H leading-none */
  font-weight: 700;
  color: var(--hba-white, #ffffff);
}
.hba-eventchip > .hba-eventchip__day {
  top: 47px;
  font-size: 12px;
  line-height: 16px;
  font-weight: 400;
  color: var(--hba-amberink, #ffb900);
}
/* H `font-['Oswald'] font-semibold text-[#0d1b2a] text-lg … truncate`. M /calendar agrees
 * (h3 18/28 600). `truncate` is reproduced: live clips a long title to one line here. */
.hba-eventchip__title {
  font-family: var(--hba-font-display);
  font-size: 18px;
  line-height: 28px;
  font-weight: 600;
  color: var(--hba-charcoal, #0d1b2a);
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* H `text-gray-500 text-sm font-['Source_Sans_3']` = 14px, T inkMuted #6a7282 (gray-500), the
 * documented owner of meta lines. C's darkest ink sample rgb(106,114,130) matches exactly. */
.hba-eventchip__loc {
  font-family: var(--hba-font-text);
  font-size: 14px;
  line-height: 20px;
  color: var(--hba-inkmuted, #6a7282);
  margin: 0;
}

/* /events "All Upcoming Events" and /calendar "Upcoming Events" — the same component with the
 * larger chip. H, verbatim:
 *   <div class="flex items-start gap-5 p-5 rounded-xl border border-gray-100
 *               hover:border-[#1e3a5f]/30 hover:shadow-md bg-white transition-all duration-200">
 *     <div class="w-16 h-16 bg-[#1e3a5f] rounded-xl flex flex-col items-center justify-center">
 *       <div class="font-['Oswald'] font-bold text-white text-lg leading-none">15</div>
 *       <div class="font-['Oswald'] text-amber-400 text-xs uppercase">Jul</div>
 *     <div class="flex-1 min-w-0"><div class="flex items-center gap-3 mb-1 flex-wrap"> h3 + chip
 * C at 390 confirms the 64px chip stays 64px and stays beside the copy — live has no mobile
 * reflow for this component, and none is introduced here. */
.hba-eventlist {
  display: flex;
  flex-direction: column;
  gap: 12px; /* H space-y-3 */
}
.hba-eventlist__row {
  position: relative;
  /* `display: flow-root` CONTAINS THE FLOATS the copy block below uses to build
   * live's two-line copy column; without it a row whose title wraps spills its
   * copy out of the card. flow-root rather than `overflow: hidden` so nothing is
   * ever clipped. See the copy-block note further down. */
  display: flow-root;
  min-height: 106px; /* 20 + 64 chip + 20 + 2 border; live measures 106, not 104 */
  padding: 20px 20px 20px 104px; /* H p-5 + the 64px chip + H gap-5 */
  background: var(--hba-white, #ffffff);
  border: 1px solid var(--hba-hairline, #f3f4f6);
  border-radius: var(--hba-radius-card, 12px);
  transition: box-shadow var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1)),
              border-color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-eventlist__row::before {
  content: "";
  position: absolute;
  left: 20px;
  top: 20px;
  width: 64px;  /* H w-16 */
  height: 64px; /* H h-16 */
  border-radius: var(--hba-radius-card, 12px); /* H rounded-xl */
  background: var(--hba-navy, #1e3a5f);
}
/* DAY over MONTH here — compose-pages.php emits day first on these two routes and so does live.
 * 18px/1 + 16px = 34px centred in the 64px box ⇒ 15px in. COMPONENT_MAP C-06's "day over month"
 * describes THIS chip, not the home one above. */
.hba-eventlist__row > .hba-eventchip__day,
.hba-eventlist__row > .hba-eventchip__month {
  position: absolute;
  left: 20px;
  width: 64px;
  margin: 0;
  text-align: center;
  font-family: var(--hba-font-display);
}
.hba-eventlist__row > .hba-eventchip__day {
  top: 35px;
  font-size: 18px;
  line-height: 18px; /* H leading-none */
  font-weight: 700;
  color: var(--hba-white, #ffffff);
}
.hba-eventlist__row > .hba-eventchip__month {
  top: 53px;
  font-size: 12px;
  line-height: 16px;
  font-weight: 400;
  text-transform: uppercase; /* H uppercase */
  color: var(--hba-amberink, #ffb900);
}
/* H puts the title and its category chip in a `flex items-center gap-3 mb-1 flex-wrap` line.
 * compose-pages.php emits them as siblings, so they are made inline with the same 12px gap. */
.hba-eventlist__row > .hba-heading {
  float: left;            /* see the copy-block note below */
  margin: 0 12px 4px 0;   /* H gap-3 beside the chip, H mb-1 under the row */
  font-size: 18px;
  line-height: 28px;
  font-weight: 600;
}
/* ⛔ 2026-08-21 RHYTHM ROUND — THE REST OF THIS ROW'S INTERIOR, MEASURED OFF LIVE
 * RATHER THAN READ OFF THE MARKUP, BECAUSE THE MARKUP IS WHAT MISLED ME.
 * Live's copy column (spacing-probe, /events "All Upcoming Events", 2543px) is:
 *     div.flex.items-center.gap-3        h=28   mb 4    <- h3 + category chip
 *     div.flex.flex-wrap.gap-4           h=20   mb 4    <- time AND location, ONE row
 *     p.text-gray-500.text-sm            h=20           <- description, 14/20
 *   column 76 + 20/20 padding + 2 border = 106 (no description) / 118 (with)
 * The title row was already right. The other two were not:
 *   - compose-pages.php emits time and location as two <p class="hba-body hba-meta">
 *     SIBLINGS, and a <p> is a block, so they stacked where live wraps them in one
 *     `flex flex-wrap gap-4` row. That is a whole 20px line per row, x6 rows.
 *   - the description kept .hba-body's 18/29.25 section-lead register where live
 *     runs `text-gray-500 text-sm` = 14/20. This is the "oversized body copy" half
 *     of /events [2] being +101: the row was both jammed AND too tall, from two
 *     different causes, at the same time.
 * ⛔ FLOATS, AND THEY ARE THE ONLY MECHANISM THAT WORKS HERE — MEASURED, NOT
 * PREFERRED. Live builds this column from THREE nested flex rows; the composition
 * emits all six elements as FLAT siblings of the row, with no wrapper to make a
 * row out of. The obvious fix — `display: inline-block` on the metas — was tried
 * and measured first, and it is wrong: with the h3 and the chip already inline,
 * everything flows onto ONE line and the row collapses to its min-height (/events
 * [2] went from +101 to −76). An inline formatting context has no way to say
 * "break here", `clear` does not apply to inline-level boxes, and the row's
 * `::before` is already spent on the navy date chip so the flex line-breaker
 * pseudo-element trick is unavailable too.
 * Floats do have a break — `clear` — so the three lines are built as float rows:
 *   line 1  h3 + chip      (float left, chip nudged 4px to match H items-center)
 *   line 2  meta + meta    (clear: left on the first, gap-4 as margin-left on the
 *                           second so no trailing margin widens the wrap point)
 *   line 3  description    (clear: left, in flow, and therefore what gives the row
 *                           its height)
 * `display: flow-root` on the row (above) contains them. Retire all of this the
 * day compose-pages.php emits `.hba-eventlist__chip` / `__copy` wrappers the way
 * `.hba-newsrow` already emits `__copy` — that is live's own shape, it would also
 * clear the R-9 flush rows this component cannot answer in CSS, and it is raised
 * with the TL. Measured after: 118 with a description, 106 without; live 118/106.
 *
 * `:not(…)` IS LOAD-BEARING, same trap as everywhere else in this file: the day,
 * the month, the chip and both metas all ride on .hba-body, so a bare
 * `> .hba-body` would repaint the 18px day, the 12px chip and the meta lines at
 * 14/20 description ink. */
.hba-eventlist__row > .hba-chip { float: left; margin-top: 4px; } /* H items-center: (28-20)/2 */
.hba-eventlist__row > .hba-meta {
  float: left;
  clear: left;          /* starts live's second line */
  margin-bottom: 4px;   /* H mb-1 on the meta row */
}
.hba-eventlist__row > .hba-meta + .hba-meta { clear: none; margin-left: 16px; } /* H gap-4 */
.hba-eventlist__row > .hba-body:not(.hba-meta, .hba-chip,
                                    .hba-eventchip__day, .hba-eventchip__month) {
  clear: left;       /* live's third line */
  font-size: 14px;   /* H text-sm */
  line-height: 20px;
  color: var(--hba-inkmuted, #6a7282); /* H text-gray-500 */
}

/* =========================================================================
 * STATS — C-07 / C-83
 * =====================================================================  */

/* H, verbatim:
 *   <div class="grid grid-cols-2 gap-5">
 *     <div class="bg-[#f5f7fa] rounded-xl p-6 border border-gray-100">
 *       <div class="font-['Oswald'] font-bold text-[#0d1b2a] text-2xl leading-tight mb-1">1,100+</div>
 *       <div class="font-['Source_Sans_3'] font-semibold text-[#374151] text-sm">Facebook Followers</div>
 *       <div class="font-['Source_Sans_3'] text-gray-400 text-xs mt-0.5">&amp; growing</div>
 * C confirms 2-up at BOTH 1440 and 390, so the grid is not collapsed on mobile.
 *
 * ✅ FIELD COLLISION — RESOLVED IN THE COMPOSITION, 2026-08-21. The note that stood here said
 * these #f5f7fa cards sit inside the WHITE story section on live (About.tsx:137, the second
 * child of the `lg:grid-cols-2 gap-14 items-center` split) while compose-pages.php had put them
 * in their own `hba-field-offWhite` section, offWhite-on-offWhite. The interior round moves them
 * into the story split's right column, which is where live has them. THE VALUES BELOW WERE
 * ALREADY CORRECT FOR THAT POSITION and are unchanged — re-verified against about.html this
 * round, class for class. Nothing here had to move; the fix was upstream, exactly as recorded.
 *
 * TWO VARIANTS, ONE PAIR OF CLASSES, AND BOTH STILL WORK. This block is the /about CARD form on
 * a light field. Home's navy band is the card-less centred form and lives in the
 * `.hba-field-navy .hba-stats` block near the foot of this file at (0,2,0) — strictly more
 * specific, and field-scoped, so it cannot reach /about's white ground and /about cannot reach
 * it. Verified by inspection of both selectors, not assumed.
 *
 * `width: 100%` is the .brxe-container trap in its third form (site.css row B-4, body.css's
 * align-items, site.css's flex-direction). Inside a split column a shrink-wrapped grid collapses
 * to its content width, and a container that kept Bricks' `width: 1100px` would instead blow
 * straight out of a 580px column. Stated explicitly so neither can happen. */
.hba-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;    /* H gap-5 */
  width: 100%;  /* see the .brxe-container note above */
}
.hba-stat {
  background: var(--hba-offwhite, #f5f7fa);
  border: 1px solid var(--hba-hairline, #f3f4f6);
  border-radius: var(--hba-radius-card, 12px);
  padding: 24px; /* H p-6 */
}
.hba-stat__value {
  font-family: var(--hba-font-display);
  font-size: 24px;
  line-height: 30px; /* H leading-tight */
  font-weight: 700;
  color: var(--hba-charcoal, #0d1b2a);
  margin: 0 0 4px; /* H mb-1 */
}
.hba-stat__label {
  font-family: var(--hba-font-text);
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  color: var(--hba-inkstrong, #374151);
  margin: 0;
}
.hba-stat__sub {
  font-family: var(--hba-font-text);
  font-size: 12px;
  line-height: 16px;
  color: var(--hba-inkfaint, #99a1af); /* H text-gray-400 */
  margin: 2px 0 0; /* H mt-0.5 */
}

/* =========================================================================
 * TIMELINE — C-90 (/about; single-use and named as such in COMPONENT_MAP §5)
 * =====================================================================  */

/* H, verbatim:
 *   <div class="max-w-2xl mx-auto">
 *     <div class="relative pl-8">
 *       <div class="absolute left-3 top-2 bottom-2 w-0.5 bg-[#e5e7eb]"></div>
 *       <div class="space-y-10">
 *         <div class="relative flex gap-6 items-start">
 *           <div class="absolute -left-5 top-1.5 w-3.5 h-3.5 rounded-full bg-amber-500
 *                       border-2 border-white shadow"></div>
 *           <span class="inline-block bg-[#1e3a5f] text-amber-400 font-['Oswald'] font-bold
 *                        text-xs tracking-wider px-3 py-1 rounded mb-2">Founded</span>
 * ✅ GROUND — RESOLVED IN THE COMPOSITION, 2026-08-21, AND THE RULES BELOW NEEDED NO CHANGE.
 * The note that stood here flagged compose-pages.php putting this section on `charcoal` while H
 * and C both show the live ground as #ffffff (About.tsx:197, `py-16 bg-white`). The interior
 * round moves it to white. RE-VERIFIED against about.html this round rather than assumed:
 *   rail   `absolute left-3 top-2 bottom-2 w-0.5 bg-[#e5e7eb]`      -> #e5e7eb, correct on white
 *   dot    `w-3.5 h-3.5 rounded-full bg-amber-500 border-2 border-white shadow`
 *                                                                   -> white ring, correct on white
 * Both were authored FROM the live white-ground markup in the first place, so the charcoal
 * placement was the thing that was wrong, not these values. Nothing is re-coloured. What WAS
 * missing is the step's own type register — three sizes that the field defaults get wrong on a
 * white ground — and that is added at the foot of this block. */
.hba-timeline {
  position: relative;
  max-width: 672px; /* H max-w-2xl */
  margin-inline: auto;
  padding-left: 32px; /* H pl-8 */
}
/* RHYTHM ROUND: the timeline's LEAD-IN, which was 16px instead of 48.
 * body.css gives a content block 40px after the section head, but only for the
 * seven classes named in its `.hba-section__inner > * + :where(…)` list, and
 * `.hba-timeline` is not one of them — so this section fell through to the generic
 * `heading + * { margin-top: 16px }` and the rail started 32px too high. Measured:
 * the timeline block itself is 612px on both sides, byte for byte; the whole
 * /about [4] delta is this gap plus two things this lane does not own (the section
 * is composed 56/56 where live is `py-16`, and the h2 ramp).
 * H (About.tsx:197-ish): live wraps the eyebrow and h2 in `text-center mb-12`, so
 * the distance from the heading to the rail is 48. Stated on this component rather
 * than by adding a class to body.css's list, which is the other lane's. (0,2,0)
 * over that rule's `:where()`-flattened (0,1,0); if body.css later adopts
 * `.hba-timeline` the two agree on the property and nothing doubles. */
/* ⛔ THE DECLARATION NOW LIVES IN body.css, in the block-gap register beside
 * `.hba-grid` 40 and `.hba-actions` 32. Both lanes reached the same 48 from the
 * same measurement; two homes for one fact is how the next person changes only
 * one of them. The reasoning stays here because this is the component it
 * describes — the rule does not. */
.hba-timeline::before {
  content: "";
  position: absolute;
  left: 12px; /* H left-3 */
  top: 8px;
  bottom: 8px; /* H top-2 bottom-2 */
  width: 2px; /* H w-0.5 */
  background: var(--hba-border, #e5e7eb);
}
/* ⛔ THE STEP IS AN <a> NOW (R-43, ruling SS-13) AND THESE THREE DECLARATIONS ARE
 * WHAT THAT COSTS. An anchor is an INLINE box: `position: relative` still applies,
 * but the ::before dot below is positioned against a box that has collapsed around
 * its text, the block children re-wrap it, and the amber dot lands in the middle of
 * the paragraph instead of beside the marker. `display: block` restores exactly the
 * geometry the <div> had, so nothing else in this block needed touching. The colour
 * and underline resets keep the step reading as body copy rather than as a link —
 * the marker, heading and text keep their own registers, and the affordance is the
 * cursor and the hover below, the same treatment `.hba-tile` and the federation
 * cards already use for a whole-block link. */
.hba-timeline__step {
  position: relative;
  display: block;
  margin-bottom: 40px; /* H space-y-10 */
  color: inherit;
  text-decoration: none;
}
.hba-timeline__step:last-child { margin-bottom: 0; }
/* An affordance, but a quiet one: live has no hover state here because live had no
 * link here. The heading takes navy on hover, which is the same signal
 * `.hba-card--topbar` gives on /news. */
a.hba-timeline__step:hover .hba-heading {
  color: var(--hba-navy, #1e3a5f);
}
.hba-timeline__step::before {
  content: "";
  position: absolute;
  left: -20px; /* H -left-5, i.e. 12px from the container edge */
  top: 6px; /* H top-1.5 */
  width: 14px;  /* H w-3.5 */
  height: 14px; /* H h-3.5 */
  box-sizing: border-box;
  border-radius: var(--hba-radius-pill, 9999px);
  background: var(--hba-amberfill, #fe9a00);
  border: 2px solid var(--hba-white, #ffffff);
  box-shadow: var(--hba-shadow-cardFlat, rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.1) 0px 1px 2px -1px);
}
.hba-timeline__marker {
  display: inline-block;
  font-family: var(--hba-font-display);
  font-size: 12px;
  line-height: 16px;
  font-weight: 700;
  letter-spacing: 0.6px; /* H tracking-wider 0.05em at 12px */
  padding: 4px 12px; /* H py-1 px-3 */
  border-radius: var(--hba-radius-hairline, 4px); /* H rounded */
  background: var(--hba-navy, #1e3a5f);
  color: var(--hba-amberink, #ffb900);
  margin: 0 0 8px; /* H mb-2 */
}
/* 2026-08-21: the step's own type register, which was never authored — the steps
 * were taking body.css's section defaults (h3 20/28, body 18/29.25 inkBody) where
 * live runs a tighter, darker pair. H (About.tsx, per step), verbatim:
 *   h3  `font-['Oswald'] font-bold text-[#0d1b2a] text-lg mb-1.5`
 *   p   `font-['Source_Sans_3'] text-[#374151] text-sm leading-relaxed`
 * text-lg with NO leading class = 18/28; mb-1.5 = 6px; text-sm leading-relaxed =
 * 14 x 1.625 = 22.75. The paragraph ink is inkStrong #374151, NOT the light-field
 * inkBody #4a5565 — the same one-channel distinction STYLE_GUIDE trap 3 forbids
 * collapsing on list items. (0,2,0) over body.css's (0,1,0) field rules. */
.hba-timeline__step .hba-heading {
  font-size: 18px;    /* H text-lg */
  line-height: 28px;
  font-weight: 700;
  margin: 0 0 6px;    /* H mb-1.5 */
}
/* ⛔ `:not(.hba-timeline__marker)` IS LOAD-BEARING. The marker is emitted as
 * `<p class="hba-body hba-timeline__marker">` — it rides .hba-body like every other
 * paragraph on the site — so a bare `.hba-timeline__step .hba-body` at (0,2,0) beats
 * `.hba-timeline__marker` at (0,1,0) and repaints the amber-on-navy pill in 14px
 * inkStrong. Caught by measuring the rendered step, not by reading the rule: it
 * computed rgb(55,65,81)/14px where the pill is #ffb900/12px. Same trap body.css
 * documents for .hba-meta and .hba-kicker riding on .hba-body — the ink modifier is
 * on the SAME element, so a descendant rule aimed at its siblings hits it too. */
.hba-timeline__step .hba-body:not(.hba-timeline__marker) {
  font-size: 14px;         /* H text-sm */
  line-height: 22.75px;    /* H leading-relaxed */
  color: var(--hba-inkstrong, #374151);
}

/* =========================================================================
 * OFFICE HOURS — part of C-91 (/contact)
 * =====================================================================  */

/* `hba-hours` is emitted by compose-pages.php but was not on my class list. It is the direct
 * parent of the rows below and belongs to this component, so it is styled here and reported.
 * H, verbatim — live uses a real table, so the two columns align across every row:
 *   <table class="text-xs font-['Source_Sans_3'] w-full">
 *     <tr><td class="text-white/60 pr-4 py-0.5">Monday</td>
 *         <td class="text-white/90">9 AM – 4:30 PM</td></tr>
 *     …<td class="text-white/30">Closed</td>
 * `display: contents` on the row gives the div markup the same shared column behaviour a table
 * has, which a per-row flexbox cannot do. C's brightest-ink samples over the #0d1b2a panel land
 * on exactly these three alpha rungs (0.60 / 0.90 / 0.30).
 *
 * ⚠ CARRIED DIFFERENCE: live paints the "Closed" values at white/30, but compose-pages.php gives
 * every day's value the same class and CSS cannot select on text content. All seven values are
 * white/90 here. Reported. */
.hba-hours {
  display: grid;
  grid-template-columns: max-content 1fr;
  width: 100%;
}
.hba-hours__row { display: contents; }
.hba-hours__day {
  font-family: var(--hba-font-text);
  font-size: 12px;
  line-height: 16px;
  padding: 2px 16px 2px 0; /* H py-0.5 pr-4 */
  color: var(--hba-white-white60, rgba(255, 255, 255, 0.600));
  margin: 0;
}
.hba-hours__val {
  font-family: var(--hba-font-text);
  font-size: 12px;
  line-height: 16px;
  padding: 2px 0;
  color: var(--hba-white-white90, rgba(255, 255, 255, 0.902));
  margin: 0;
}

/* =========================================================================
 * ICONS — C-30 / D HBA-D-10
 *
 * ⚠ THE ARTWORK IS AUTHORED, NOT MEASURED — AND THAT IS THE RECORDED DECISION.
 * H confirms live uses bare emoji: `<div class="text-3xl mb-3">🏛️</div>` on the six group cards
 * and `<span class="text-2xl">🏠</span>` inside the disc on the two affiliated cards. HBA-D-10
 * makes emoji-as-iconography a re-authoring category — "pixel parity on an emoji is only ever
 * true on one machine" — and records each glyph's MEANING in
 * content-source/content/pages/benefits.md. Those meanings are used verbatim below. No icon
 * asset exists anywhere in the repo, so the eight marks are authored here as SVG masks; swap
 * them for a real icon set when one lands.
 *
 * GEOMETRY IS MEASURED. H: group glyph `text-3xl mb-3` ⇒ a 30px slot with a 12px bottom margin;
 * affiliated disc `w-16 h-16 bg-amber-500/20 rounded-full … mb-4` ⇒ 64px, amber-500/20, 16px
 * bottom margin, holding a `text-2xl` (24px) glyph.
 *
 * ⚠ INK IS UNSOURCED. Emoji carry no transferable colour. The six group marks take T navy
 * #1e3a5f — the site's own icon-tile fill on light grounds (C-30, n=50). The two marks inside
 * the amber disc on the charcoal card take T amberInk #ffb900 — the documented accent ink on
 * dark, and the colour H gives every other icon on those two cards. Both are existing site
 * tokens used for their documented role; neither is a measured value.
 * =====================================================================  */

.hba-icon {
  display: block;
  width: 30px;  /* H text-3xl */
  height: 30px;
  margin: 0 0 12px; /* H mb-3 */
  background-color: var(--hba-navy, #1e3a5f);
  -webkit-mask: var(--hba-glyph, none) center / contain no-repeat;
  mask: var(--hba-glyph, none) center / contain no-repeat;
}

/* 🏛️ institution / government — Advocacy */
.hba-icon--institution {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2 2 7v2h20V7L12 2zM4 11h2.5v7H4v-7zm5.25 0h2.5v7h-2.5v-7zm5.25 0H17v7h-2.5v-7zM2 20h20v2H2v-2z'/%3E%3C/svg%3E");
}
/* 🎓 education / credential — Education & Training */
.hba-icon--education {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3 1 8l11 5 9-4.1V15h2V8L12 3zM5 13.2V17l7 3.5 7-3.5v-3.8l-7 3.2-7-3.2z'/%3E%3C/svg%3E");
}
/* 🤝 partnership / connection — Networking */
.hba-icon--partnership {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9.5 7H7a5 5 0 0 0 0 10h2.5v-2H7a3 3 0 0 1 0-6h2.5V7zm5 0H17a5 5 0 0 1 0 10h-2.5v-2H17a3 3 0 0 0 0-6h-2.5V7zM8 11h8v2H8v-2z'/%3E%3C/svg%3E");
}
/* 💰 savings / money — Business Savings */
.hba-icon--savings {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3c-4.4 0-8 1.6-8 3.5S7.6 10 12 10s8-1.6 8-3.5S16.4 3 12 3zM4 9.4V12c0 1.9 3.6 3.5 8 3.5s8-1.6 8-3.5V9.4c-1.9 1.4-4.8 2.1-8 2.1s-6.1-.7-8-2.1zm0 5.5v2.6C4 19.4 7.6 21 12 21s8-1.6 8-3.5v-2.6c-1.9 1.4-4.8 2.1-8 2.1s-6.1-.7-8-2.1z'/%3E%3C/svg%3E");
}
/* 📰 news / publication — Information & Resources */
.hba-icon--news {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 4h18v16H3V4zm2 2v5h8V6H5zm10 0v5h4V6h-4zM5 13v2h14v-2H5zm0 4v2h14v-2H5z'/%3E%3C/svg%3E");
}
/* 🏘️ community / housing — Community */
.hba-icon--community {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 2 1 6.2V21h10V6.2L6 2zm3 17H3V7.2L6 4.6l3 2.6V19zm9-12-5 4.2V21h10v-9.8L18 7zm3 12h-6v-6.8l3-2.6 3 2.6V19z'/%3E%3C/svg%3E");
}
/* 🏠 house / home — HBAA Member Benefits */
.hba-icon--house {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffb900'%3E%3Cpath d='M12 3 2 11.2h3V21h5.5v-6h3v6H19v-9.8h3L12 3z'/%3E%3C/svg%3E");
}
/* 🇺🇸 national / United States — NAHB Member Savings */
.hba-icon--national {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffb900'%3E%3Cpath d='M4 2h2v20H4V2zm3 1h13l-3.2 4.5L20 12H7V3z'/%3E%3C/svg%3E");
}

/* The two affiliated marks are a filled disc, not a masked block: the disc's amber/20 fill has
 * to survive, so the glyph rides on top as a background image instead of a mask. */
.hba-icon--house,
.hba-icon--national {
  width: 64px;  /* H w-16 */
  height: 64px; /* H h-16 */
  margin: 0 auto 16px; /* H mx-auto mb-4 */
  border-radius: var(--hba-radius-pill, 9999px);
  background-color: var(--hba-ambertint-20, rgba(254, 154, 0, 0.200)); /* H bg-amber-500/20 */
  background-image: var(--hba-glyph);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 24px 24px; /* H text-2xl */
  -webkit-mask: none;
  mask: none;
}

/* =========================================================================
 * FEDERATION-PARTNER LOCKUP — C-85 (home)
 * =====================================================================  */

/* H, verbatim:
 *   <div class="flex flex-col sm:flex-row items-center justify-center gap-8 sm:gap-14">
 *     <a class="flex items-center gap-3 …"><img class="h-12 w-auto object-contain"> …
 *     <div class="hidden sm:block w-px h-10 bg-gray-200"></div>
 *     <a class="flex items-center gap-3 …"> …
 * compose-pages.php emits two <img class="hba-partners__mark"> then one
 * <div class="hba-partners__text">, so the rule below puts the divider immediately before the
 * text block — the same position live gives it, between the HBAA and NAHB lockups. */
.hba-partners {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 56px; /* H sm:gap-14 */
}
.hba-partners__mark {
  height: 48px; /* H h-12 */
  width: auto;
  object-fit: contain;
}
/* 2026-08-21 DELTA ROUND: the composition now emits the full live lockup
 * internals (logo/disc + two classed text lines per anchor), retiring the old
 * two-imgs-plus-one-<p> markup and its ::first-line hack. H (Home.tsx:317–346),
 * verbatim:
 *   row      `flex flex-col sm:flex-row items-center justify-center gap-8 sm:gap-14`
 *   anchor   `flex items-center gap-3 group hover:opacity-75 transition-opacity
 *             duration-200`
 *   HBAA     `<img class="h-12 w-auto object-contain">`
 *   NAHB     `w-12 h-12 bg-[#1e3a5f] rounded-full flex items-center
 *             justify-center flex-shrink-0` holding a 22px white building-2
 *   line 1   `font-['Oswald'] font-bold text-[#0d1b2a] text-sm leading-tight`
 *   line 2   `font-['Oswald'] text-xs tracking-wide` — #8b1a1a on the HBAA
 *            lockup, #1e3a5f on the NAHB lockup (the old note claiming the red
 *            line lives inside the logo image was WRONG — it is DOM text)
 *   divider  standalone `hidden sm:block w-px h-10 bg-gray-200` BETWEEN the
 *            anchors. The composition emits no divider element, so it rides as
 *            a border on the second anchor: parent gap 56 + padding 56
 *            reproduces live's 56/56 spacing around the rule. Full-height
 *            rather than h-10 — the same carried compromise as before. */
.hba-partners > a,
.hba-partners__lockup {
  display: flex;
  align-items: center;
  gap: 12px; /* H gap-3 */
  text-decoration: none;
  transition: opacity var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-partners > a:hover,
.hba-partners__lockup:hover { opacity: 0.75; } /* H hover:opacity-75 */
.hba-partners > a + a,
.hba-partners__lockup + .hba-partners__lockup {
  border-left: 1px solid var(--hba-border, #e5e7eb); /* H w-px bg-gray-200 */
  padding-left: 56px;
}
.hba-partners__logo {
  height: 48px; /* H h-12 */
  width: auto;
  object-fit: contain;
}
.hba-partners__disc {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;  /* H w-12 */
  height: 48px; /* H h-12 */
  flex: none;
  border-radius: var(--hba-radius-pill, 9999px);
  background: var(--hba-navy, #1e3a5f);
  color: var(--hba-white, #ffffff); /* H text-white — glyph rides currentColor */
}
.hba-partners__disc [class*="hba-icon--"] { width: 22px; height: 22px; }
.hba-partners__text { text-align: left; }
.hba-partners__l1 {
  font-family: var(--hba-font-display);
  font-size: 14px;      /* H text-sm */
  line-height: 17.5px;  /* H leading-tight */
  font-weight: 700;
  color: var(--hba-charcoal, #0d1b2a);
  margin: 0;
}
.hba-partners__l2 {
  font-family: var(--hba-font-display);
  font-size: 12px;      /* H text-xs */
  line-height: 16px;
  font-weight: 400;
  letter-spacing: 0.3px; /* H tracking-wide, 0.025em at 12px */
  color: var(--hba-navy, #1e3a5f); /* NAHB ink — the majority-of-two default */
  margin: 0;
}
/* The HBAA lockup's second line is the partner-brand red (H Home.tsx:331).
 * Reached structurally: it is the lockup whose mark is the LOGO IMG. */
.hba-partners > a:has(.hba-partners__logo) .hba-partners__l2,
.hba-partners__lockup:has(.hba-partners__logo) .hba-partners__l2 {
  color: #8b1a1a; /* T partner-brand literal, now genuinely authored */
}

/* =========================================================================
 * APPLICATION OPTION BLOCKS — part of C-92 (/become-a-member)
 * =====================================================================  */

/* ✅ THE POSITIONAL DEPENDENCY IS GONE. The note that stood here said one class carried two live
 * treatments and was reachable only through `~`, and asked for `--dark` / `--light` modifiers in
 * compose-pages.php. The 2026-08-21 interior round emits them, so the sibling combinator is
 * retired and each register is addressed by name. H, re-read from become-a-member.html:
 *   dark   `bg-[#0d1b2a] rounded-xl p-6 mb-6`
 *   light  `bg-[#f5f7fa] rounded-xl p-6 border border-gray-200`   <- gray-200 #e5e7eb, NOT
 *          gray-100. The `~` rule carried #f3f4f6; corrected here against the source.
 * The base holds only what both share. */
/* THE COLUMN HEAD ABOVE THE BLOCKS. `.hba-optioncols` is body.css's LAYOUT class,
 * but this <h2> is the option stack's own head — it introduces the two blocks
 * below and nothing else in the aside — so its register is authored here with
 * them. ⚠ Boundary noted for the TL rather than assumed away.
 * H (BecomeMember.tsx:197), verbatim: `font-['Oswald'] font-bold text-[#0d1b2a]
 * text-2xl mb-6`. That is 24/32 against body.css's h2 register of 30/36, and the
 * heading had NO bottom margin at all: it is not a direct child of
 * `.hba-section__inner`, so body.css's `> .hba-heading + *` rule never reached it
 * and "Application Options" sat flush on the charcoal block beneath it.
 * The same 24/32 column-head register is already carried for "Apply Online" by
 * `.hba-formwrap__head` further down; this is its pair, and RHYTHM_TRUTH's type
 * table lists the two together. */
.hba-optioncols__aside > .hba-heading {
  font-size: 24px;     /* H text-2xl */
  line-height: 32px;
  margin-bottom: 24px; /* H mb-6 */
}

.hba-optionblock {
  border-radius: var(--hba-radius-card, 12px);
  padding: 24px;       /* H p-6 */
  margin-bottom: 24px; /* H mb-6 */
}
/* Live's light panel is the LAST block in the column and carries no bottom margin; without this
 * the aside runs 24px longer than the panel it ends with. */
.hba-optionblock:last-child { margin-bottom: 0; }

.hba-optionblock--dark {
  background: var(--hba-charcoal, #0d1b2a);
  border: 0;
}
.hba-optionblock--dark .hba-heading { color: var(--hba-white, #ffffff); }
/* H `text-white/70 font-['Source_Sans_3'] text-sm mb-5`.
 * `:not(.hba-placeholder)` — see the note on the light panel below; carried on both
 * so a placeholder can move between the two panels without silently losing its
 * inert register. */
.hba-optionblock--dark .hba-body:not(.hba-placeholder) {
  color: var(--hba-white-white70, rgba(255, 255, 255, 0.698));
  font-size: 14px;
  line-height: 20px;
  /* RHYTHM ROUND: the `mb-5` in the H string quoted above was transcribed as ink
   * and size and then dropped. Nothing else supplies it — the paragraph is inside
   * a block, so body.css's section-flow rules do not reach — and the copy sat hard
   * against the two application buttons. */
  margin-bottom: 20px; /* H mb-5 */
}

.hba-optionblock--light {
  background: var(--hba-offwhite, #f5f7fa);
  border: 1px solid var(--hba-border, #e5e7eb); /* H border-gray-200 */
}
.hba-optionblock--light .hba-heading { color: var(--hba-charcoal, #0d1b2a); }
/* H `text-gray-600 font-['Source_Sans_3'] text-sm leading-relaxed mb-4`.
 * ⛔ `:not(.hba-placeholder)` IS LOAD-BEARING, and the bug it fixes predates this
 * round — the `~ .hba-optionblock .hba-body` rule this replaced had it too. The
 * withheld PAY ONLINE control ships as `<p class="hba-body hba-placeholder">` INSIDE
 * this panel, so a bare descendant rule at (0,2,0) beats `.hba-placeholder` at
 * (0,1,0) and repaints the marker in ordinary body ink. COMPONENT_MAP M12 requires
 * that marker to be "visibly inert, never live-looking"; a placeholder that reads
 * like copy is exactly the failure S-1 exists to catch. */
.hba-optionblock--light .hba-body:not(.hba-placeholder) {
  color: var(--hba-inkbody, #4a5565);
  font-size: 14px;
  line-height: 22.75px; /* H leading-relaxed */
  /* RHYTHM ROUND, same omission as the dark panel above: the `mb-4` in this rule's
   * own H string was never transcribed. 16 here, 20 there — live measures the two
   * panels differently and they are read twice rather than unified, the same way
   * their head rows already are (mb-4 dark / mb-3 light). */
  margin-bottom: 16px; /* H mb-4 */
}

/* The heading row: a glyph beside the h3. H, and THE TWO PANELS DIFFER — read twice rather than
 * unified, because the difference is 4px of margin and one icon size and it would have been
 * invisible either way:
 *   dark   `flex items-center gap-3 mb-4` + 24px lucide file-text in text-amber-400
 *   light  `flex items-center gap-3 mb-3` + 20px lucide mail      in text-[#1e3a5f]
 * Both h3s are `font-['Oswald'] font-semibold text-lg` = 18/28 weight 600, where body.css's h3
 * register is 20/28 weight 700 — so the size is restated here too. */
.hba-optionblock__head {
  display: flex;
  flex-direction: row;   /* .brxe-container trap: direction, alignment AND width, all three */
  align-items: center;
  width: 100%;
  gap: 12px;             /* H gap-3 */
  margin-bottom: 16px;   /* H mb-4 (dark) */
}
.hba-optionblock--light .hba-optionblock__head { margin-bottom: 12px; } /* H mb-3 */
.hba-optionblock__head .hba-heading {
  font-size: 18px;   /* H text-lg */
  line-height: 28px;
  font-weight: 600;  /* H font-semibold, not the h3 default 700 */
  margin: 0;
}
.hba-optionblock__icon {
  flex: none;
  width: 24px;   /* H width="24" on the dark panel's file-text */
  height: 24px;
}
.hba-optionblock--dark  .hba-optionblock__icon { background-color: var(--hba-amberink, #ffb900); } /* H text-amber-400 */
.hba-optionblock--light .hba-optionblock__icon {
  width: 20px;   /* H width="20" on the light panel's mail glyph */
  height: 20px;
  background-color: var(--hba-navy, #1e3a5f); /* H text-[#1e3a5f] */
}

/* ── SS-18: the membership-dues payment QR, inside the light Payment panel ──
 *
 * NO LIVE COUNTERPART EXISTS. Live's payment slot is a dead `href="#"` button;
 * this is the client's own QR artwork, delivered 2026-09-08, and nothing in the
 * capture measures it. Both rules below are therefore chosen, not read — which
 * is why the reasoning is here rather than an "H ..." transcription.
 *
 * `.hba-payqr__h` — THE ONLY h4 ON THE SITE. body.css's `.hba-heading` sizes
 * h1/h2/h3 and deliberately stops, so an h4 would paint at whatever the UA and
 * Bricks between them decide. 15/22 semibold sits one clear step under the
 * panel's own 18/28 semibold h3 and above the 14/22.75 body the panel runs, so
 * the three levels read as three levels. Ink comes from
 * `.hba-optionblock--light .hba-heading` at (0,2,0) and is not restated.
 *
 * `.hba-qr` — the QR file is OURS to shape since 2026-09-09: the owner directed
 * the crop ("cut out the blue text… make it just be the QR code. make it a
 * little bigger"), which amends SS-18's byte-fidelity rule for these two files
 * (the transform + the client-original sha are recorded in media-map.json
 * `_provenance`). The asset is now the code + quiet zone only, 124px native
 * scaled 3x NEAREST-NEIGHBOR to 372px — integer scaling of a QR is
 * pixel-perfect, so the served file is crisp at 1:1 and any downscale.
 * Display 340px: bigger than the old 300px title-and-margins render (the code
 * itself more than doubles). ⚠ MEASURED, NOT ASSUMED: the light panel's content
 * box is 339.33px at a 1440 viewport — NOT the ~362px an earlier draft of this
 * comment claimed — so `max-width: 100%` clamps the 340 to 339.33 and the code
 * renders as a full-panel fill. That is the intended outcome and the pair is
 * kept deliberately: 340 states the ceiling we would take if the panel ever got
 * wider, `max-width` keeps it inside whatever the panel actually is at every
 * narrower width. Anything from 340 up would paint identically today, so do not
 * read the 340 as a measured fit.
 * `image-rendering: pixelated` keeps module edges square if any context ever
 * resamples it — for a machine-readable code, smooth interpolation is the
 * wrong kind of pretty. `margin-inline:auto` centres it (a code is an object
 * to aim a camera at, not a line to read); `margin-bottom` restates the
 * panel's mb-4 register, which the panel's body rule cannot reach. */
.hba-payqr__h {
  font-size: 15px;
  line-height: 22px;
  font-weight: 600;
  margin-bottom: 6px;
}
.hba-qr {
  display: block;
  width: 340px;
  max-width: 100%;
  height: auto;
  margin-inline: auto;
  margin-bottom: 16px; /* the light panel's mb-4 */
  image-rendering: pixelated;
}

/* =========================================================================
 * FOOTER MODIFIERS
 *
 * ⚠ OWNERSHIP NOTE: both of these are CHROME. Their bases (`.hba-footer__col` and `.hba-cta`)
 * are authored in site.css, which this file loads after. Only the delta live shows over those
 * bases is set here. Raised with the TL as belonging with the rest of the footer.
 * =====================================================================  */

/* H: `<div class="lg:col-span-1"><div class="mb-5"><img class="h-20 w-auto object-contain">…
 *     <p class="text-white/60 text-sm font-['Source_Sans_3'] leading-relaxed">`
 * inside a `grid lg:grid-cols-4 gap-10`, i.e. an equal quarter column — 274px at 1440, which C
 * confirms (the tagline wraps at x=382 from a column edge of x=112). site.css's shared
 * `.hba-footer__col` gives the column a 10px gap and `.hba-footer__tagline` white/70; live is
 * 20px and white/60 here, and the logo is sized by HEIGHT, not width. */
.hba-footer__brand {
  max-width: 274px;
  gap: 20px; /* H mb-5 */
}
.hba-footer__brand .hba-footer__logo {
  height: 80px; /* H h-20 */
  width: auto;
}
.hba-footer__brand .hba-footer__tagline {
  color: var(--hba-white-white60, rgba(255, 255, 255, 0.600)); /* H text-white/60 */
}
/* H `inline-block bg-amber-500 hover:bg-amber-400 text-white font-['Oswald'] font-semibold
 *    tracking-wider text-sm px-5 py-2.5 rounded transition-all duration-200`
 * ⇒ padding 10px 20px and radius 4px, which C confirms as a 184×40 painted box. site.css's
 * shared `.hba-cta` uses 8px 18px and radius 6px; the radius delta is site-wide and is reported
 * rather than fixed here for one button. */
.hba-footer__cta {
  padding: 10px 20px;
  border-radius: var(--hba-radius-hairline, 4px);
}

/* =========================================================================
 * RESPONSIVE
 *
 * T layout: this site's section vertical rhythm is WIDTH-INVARIANT (byte-identical at 390, 768
 * and 1440 across all 39 sampled sections), so nothing below touches vertical padding.
 * C at 390 confirms the event rows keep their desktop shape (the 64px chip stays 64px and stays
 * beside the copy) and the stats stay 2-up. Neither is reflowed here.
 * =====================================================================  */

@media (min-width: 1024px) {
  /* H `lg:p-7 lg:min-h-[175px]` and `lg:text-lg` on the tile. */
  .hba-tile { padding: 28px; min-height: 175px; }
  .hba-tile__title { font-size: 18px; line-height: 22.5px; letter-spacing: 0.45px; }
}

@media (max-width: 767px) {
  /* The tile rail is the one component with no measured counterpart in this position — live's
   * tiles are a 2×2 hero overlay and O-1 is open. One column at the 768 container step. */
  .hba-tiles { grid-template-columns: 1fr; }
  /* H `flex-col … gap-8` below sm, with the divider `hidden sm:block`. */
  .hba-partners { flex-direction: column; gap: 32px; }
  .hba-partners__text { border-left: 0; padding-left: 0; }
  /* Delta round: the divider now rides on the second lockup anchor. */
  .hba-partners > a + a,
  .hba-partners__lockup + .hba-partners__lockup { border-left: 0; padding-left: 0; }
}

/* D INTERACTIONS I-21 / HBA-D-12: 24 controls measure under 44px at 375 on the live site. That
 * is a defect in the source and it is FIXED here, not reproduced. Every interactive component
 * this file authors clears 44px at mobile widths — the tiles and both event rows already do so
 * by their measured min-heights (160px / 96px / 104px); only the footer CTA needs a floor. */
@media (max-width: 1023px) {
  .hba-footer__cta {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

/* =========================================================================
 * REDUCED MOTION — D HBA-D-8 / I-16: added, not reproduced. Live has none at all.
 * Hover transitions collapse to 0s; nothing in this file animates on entrance.
 * =====================================================================  */

@media (prefers-reduced-motion: reduce) {
  .hba-card--dark,
  .hba-card--icon,
  .hba-tile,
  .hba-eventchip,
  .hba-eventlist__row { transition-duration: 0s; }
  /* ⛔ Zero DURATION is not zero MOTION. The tile now lifts and scales on hover, and
   * `transition-duration: 0s` would make that an instant jump — which is worse for a
   * motion-sensitive reader than the animation, not better. Drop the movement and
   * keep the shadow, so the affordance survives without the gesture. */
  .hba-tile:hover,
  .hba-tile:active { transform: none; }
}

/* ================================================================ contact ===
 * ⛔ THESE FIVE CLASSES WERE ORPHANED BY MY OWN FAN-OUT, NOT BY ANY AGENT.
 *
 * I split the page body three ways — foundation / components / hero — and wrote a
 * disjoint class list for each. `hba-contact*` and `hba-formwrap` appear in none
 * of the three. Both agents that touched /contact correctly refused to style
 * classes outside their assignment and reported them instead, exactly as briefed.
 * The gap was in the ASSIGNMENT, and the only thing that caught it was paint row
 * P-1 counting rendered classes against styled ones. A disjoint split is
 * collision-proof; it is not automatically COMPLETE, and completeness is the
 * splitter's job, not the agents'.
 *
 * Values read from the captured live DOM (hba-capture/content/html/contact.html),
 * not inferred:
 *   layout  grid grid-cols-1 lg:grid-cols-3 gap-12   (form is lg:col-span-2)
 *   details bg-white rounded-xl p-7 border border-gray-200 shadow-sm
 *   side    bg-[#1e3a5f] rounded-xl p-6
 *   form    bg-white rounded-xl p-8 shadow-md border border-gray-100
 * Shadows are the VERBATIM measured strings from shape.shadow — note the spaces
 * inside rgba(), which the browser emits and a normalised hand-written form does
 * not (the Stage C adversary caught all six written space-stripped).
 */
/* ⛔ THE THREE PANELS ARE TWO COLUMNS, NOT THREE, AND THIS RULE MADE THEM WRAP.
 * Corrected 2026-08-21 (rhythm round) after measuring both sides; it is the single
 * largest remaining delta on the site, ~+250px on /contact.
 * Live (Contact.tsx:73-75, re-read plus spacing-probe at 2543):
 *   grid grid-cols-1 lg:grid-cols-3 gap-12         -> 3 tracks, 48px gutters
 *     div.lg:col-span-1.space-y-6   h=984          <- details AND side, STACKED,
 *                                                     24px apart, in ONE column
 *     div.lg:col-span-2             h=984          <- the form, BESIDE them
 * compose-pages.php emits the three panels as flat siblings with no column
 * wrapper, and the old rule read `lg:col-span-2` off the form alone: details took
 * track 1, side took track 2, and the form — needing two tracks — wrapped to a
 * second ROW. Measured 497 + 48 + 689 = 1234 against live's 984.
 * With no wrapper to nest, the column is rebuilt by placing all three explicitly.
 * Three equal tracks are kept rather than `1fr 2fr` so the panel widths stay
 * live's: 1fr of three = 373.33, and the form spanning tracks 2-3 picks up the
 * gutter between them = 794.67, which `1fr 2fr` would round to 389/779 instead.
 * row-gap is live's `space-y-6`, NOT its `gap-12` — the only gap between rows here
 * is the one inside that left column. */
/* ⛔ `minmax(0, 1fr)`, NOT BARE `1fr`, AND THE TURNSTILE WIDGET IS WHY (B-12,
 * measured 2026-09-14 on the live clean seed — the first build that ever HAD
 * Turnstile keys, so no earlier gate run could see this). A bare `1fr` track is
 * `minmax(auto, 1fr)`: its floor is the content's min-content, and Cloudflare's
 * widget is a FIXED-300px iframe the form cannot shrink. At 360–414w that floor
 * blew the track past the viewport (+3..56px of page-level horizontal scroll on
 * both form routes). `minmax(0, 1fr)` caps the track at its share of the grid,
 * and `min-width: 0` on the panels lets them honour it — the same pairing every
 * other grid in this lane already uses (.hba-grid--2/3, .hba-membergrid). The
 * turnstile-less staging reference showed zero overflow, which is the
 * elimination proof. Desktop geometry is unchanged: three equal minmax(0,1fr)
 * tracks resolve to the same 373.33px the comment above this rule derives. */
.hba-contact {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  column-gap: 48px; /* H gap-12 */
  row-gap: 24px;    /* H space-y-6, the left column's internal stack */
}
.hba-contact__aside,
.hba-contact__form { min-width: 0; }
/* ⚠ THE LAST 6 PIXELS LIVE INSIDE CLOUDFLARE'S CLOSED SHADOW ROOT, AND THIS CLIP
 * IS THE ONLY REACHABLE ANSWER. With the tracks fixed, the widget HOST squeezes
 * (228px at 360w) but Turnstile's inner iframe stays a fixed 300px inside a
 * closed shadow root no page CSS can style — measured: host left 66 + 300 = 366
 * against a 360 viewport, +6px of page scroll, on BOTH form routes (and on
 * /become-a-member/ it predates the grid fix — same iframe, never the track).
 * The plugin's size options don't help: "flexible" still floors at 300px and
 * "compact" would shrink the widget on every viewport to serve phones under
 * 366px. So: clip at the host, below 375px ONLY. What crops is the widget's
 * right-edge branding links; the checkbox and its label sit in the left ~150px
 * and stay fully usable. Every gate baseline measures at 390+ and desktop, so
 * this query is invisible to all of them — it exists purely so the smallest
 * phones don't get a horizontal wiggle. */
@media (max-width: 374px) {
  .hba-contact__form .cf-turnstile,
  .hba-optioncols__main .cf-turnstile {
    max-width: 100%;
    overflow: hidden;
  }
}
/* Stacked, the form is separated from the column above it by live's gap-12, not by
 * the column's own space-y-6: 24 row-gap + 24 margin = 48. */
@media (max-width: 1023px) {
  .hba-contact__form { margin-top: 24px; }
}
@media (min-width: 1024px) {
  .hba-contact { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .hba-contact__aside { grid-column: 1; }
  .hba-contact__form  { grid-column: 2 / span 2; } /* H lg:col-span-2 */
}
/* Live's `lg:col-span-1 space-y-6` — the three panels are a stack inside ONE grid
 * cell, not three grid rows. Modelling them as rows is what forced the merged
 * panel the composition used to emit. */
.hba-contact__aside {
  display: flex;
  flex-direction: column;
  gap: 24px;                                   /* H space-y-6 */
}

/* ⛔ THE GROUNDS WERE WRONG AND THAT IS WHY CONTENT LOOKED MISSING. The owner
 * reported the office hours, the partner rows and the quick links as absent from
 * /contact. Every one of them was in the DOM with a real box and real text:
 *
 *     .hba-hours__day  "Monday"   74x20   color rgba(255,255,255,0.6)  on a WHITE card
 *     .hba-cta         "HBAA"     31x20   color rgb(30,58,95)          on a rgb(30,58,95) card
 *
 * The INK was right — it is live's, for live's grounds. The GROUNDS were wrong.
 * White on white, navy on navy. Acceptance 15/15 and paint 7/7 both passed the
 * page: P-2 asks whether a section paints a background and P-7 whether a card
 * does; neither asks whether the text on it can be SEEN. Hence the new contrast
 * row in the paint battery.
 *
 * Live, measured 2026-08-21 at 2543: h=482 / 258 / 196, pad 28 / 28 / 24, all r12. */
.hba-contact__details {
  background: #0d1b2a;                         /* H bg-[#0d1b2a] — charcoal, NOT white */
  border-radius: 12px;                         /* rounded-xl */
  padding: 28px;                               /* p-7 */
}

.hba-contact__partners {
  background: #fff;                            /* H bg-white */
  border: 1px solid #e5e7eb;                   /* border-gray-200 */
  border-radius: 12px;
  padding: 28px;                               /* p-7 */
}

.hba-contact__quick {
  background: #1e3a5f;                         /* H bg-[#1e3a5f] */
  border-radius: 12px;
  padding: 24px;                               /* p-6 */
}

/* ⛔ THE TWO FORM PANELS ARE NOT THE SAME ELEMENT, AND THIS RULE USED TO TREAT
 * THEM AS ONE. Re-read from the capture 2026-08-21 (interior round):
 *   /contact  `<div class="bg-white rounded-xl p-8 shadow-md border border-gray-100">`
 *             wrapping BOTH the "Send Us a Message" h2 AND the <form>
 *   /join     `<h2>Apply Online</h2>` OUTSIDE, then
 *             `<form class="bg-[#f5f7fa] rounded-xl p-8 border border-gray-200">`
 * So on /contact the panel is the WRAPPER and on /become-a-member it is the FORM.
 * Painting `.hba-formwrap` like `.hba-contact__form` put the join page's heading
 * inside a panel live keeps outside it, and painted a white panel where live has an
 * offWhite one with a darker hairline and no shadow. Split accordingly. */
.hba-contact__form {
  background: #fff;
  border: 1px solid #f3f4f6;                   /* border-gray-100 */
  border-radius: 12px;
  padding: 32px;                               /* p-8 */
  box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.1) 0px 2px 4px -2px;
}
/* The join wrapper carries NO panel — it is just the column that holds the head and
 * the form. Stated rather than left undeclared so the class is not zero-ruled. */
.hba-formwrap {
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0;
  width: 100%;
}
/* The panel is the CF7 <form> itself. Selected by element rather than by
 * `.wpcf7-form` so it does not depend on a plugin's internal class name. */
.hba-formwrap form {
  background: var(--hba-offwhite, #f5f7fa);    /* H bg-[#f5f7fa] */
  border: 1px solid var(--hba-border, #e5e7eb); /* H border-gray-200 */
  border-radius: var(--hba-radius-card, 12px);
  padding: 32px;                               /* H p-8 */
  box-shadow: none;                            /* H: this one has no shadow */
}

/* The side card sits on navy, so its copy inverts. Scoped to the card so it
 * cannot leak into the two white cards beside it. */
/* Ink per panel, now that each has its own ground. */
.hba-contact__details .hba-heading { color: #fff; }
/* H: the detail rows read at white/90 (Contact.tsx:84/100/109), the hours note
 * at white/30 (:138) — not one blanket white/70. */
.hba-contact__details .hba-body,
.hba-contact__details .hba-cta.hba-cta--link { color: rgba(255, 255, 255, 0.902); }
.hba-contact__details .hba-meta { color: rgba(255, 255, 255, 0.302); }
.hba-contact__quick .hba-heading { color: #fff; }
.hba-contact__quick .hba-body,
.hba-contact__quick .hba-cta.hba-cta--link { color: rgba(255, 255, 255, 0.698); }
/* The white panel keeps the dark ink it was already authored with — it is the one
 * panel whose ground now matches what its ink assumed. */
.hba-contact__partners .hba-heading { color: #0d1b2a; }

/* ------------------------------------------- contact panels: interior rhythm ---
 * RHYTHM ROUND. Both panels stacked at ZERO: a heading, then its links, then the
 * next heading, with nothing between any of them. Same one-level-deep miss as the
 * cards — these are component wrappers, so body.css's `.hba-section__inner > *`
 * flow does not reach inside them. The R-9 gate names the details panel's
 * `H2"Home Builders Associ…" -> P"2123 Denton Rd #1…"` pair explicitly.
 *
 * H (Contact.tsx:76-133 and :181-195), verbatim:
 *   details head  h3 `font-['Oswald'] font-bold text-white text-xl mb-5`
 *   details rows  the icon rows are a `space-y-4` stack = 16 apart
 *   "Get Directions" `text-amber-400 text-xs hover:underline mt-1 inline-block`
 *   hours label   `text-white/90 text-sm font-semibold mb-2`
 *   side head     h3 `font-['Oswald'] font-semibold text-white text-lg mb-4`
 *   side links    `space-y-2` = 8 apart
 * The two heads are told apart by TAG, not by a new class: the composition emits
 * the panel head as the h2 and the in-panel labels ("Office Hours", "Quick Links")
 * as h3s, which is the same split live makes between its `text-xl mb-5` panel head
 * and its `text-sm mb-2` inner label. */
/* ⛔ AND EVERY MARGIN BELOW DID NOTHING UNTIL THIS RULE EXISTED. Measured
 * 2026-08-21: all three details-panel links reported `top629` — THE SAME LINE.
 * `.hba-cta` is `inline-flex` (site.css), an INLINE-LEVEL box, and vertical
 * margins on an inline-level box push nothing: the seven link rows across the two
 * panels were laid out side by side and the left column collapsed to 746 where
 * live's is 984. THAT is /contact's −238 — not the grid, not the card padding —
 * and it is the same defect class as the submit control's 81px line box further
 * down this file: an inline box standing where live has a block one. A spacing
 * rule cannot be seen to be wrong by reading it, only by measuring what it moved.
 * On live every one of these rows is block-level — each anchor is a flex row in a
 * `space-y-*` stack (phone, email, Quick Links) or `mt-1 inline-block` inside one
 * (Get Directions). `display: flex` is what makes a row a row here;
 * `width: fit-content` keeps the hit target on the words, which is what live's
 * content-width rows give.
 * SPECIFICITY COUNTED, NOT ASSUMED — AND THE FIRST FORM OF THIS RULE LOST.
 * hero.css loads AFTER this file and sets `.hba-cta.hba-cta--link { display:
 * inline-flex }` (hero.css:443) at (0,2,0), so `.hba-contact__details > .hba-cta`
 * at (0,2,0) ties it and loses on source order. Measured, not reasoned: the links
 * still computed inline-flex and still shared one line. Carrying `.hba-cta--link`
 * makes this (0,3,0), which clears it — the same count this file already does for
 * `.hba-card__body .hba-cta.hba-cta--link` and the dark-card link rules at the
 * foot. */
.hba-contact__details .hba-cta.hba-cta--link,
.hba-contact__quick > .hba-cta.hba-cta--link { display: flex; width: fit-content; }

/* Owner round-2: the details panel is now composed as ICON ROWS, matching live
 * (Contact.tsx:81-133) — `flex items-start gap-3`, a 16px amber lucide in its own
 * column, rows a `space-y-4` stack. The old flat-stack spacing selectors above
 * were rewritten for the row wrappers. */
.hba-contact__row { display: flex; align-items: flex-start; gap: 12px; } /* H gap-3 */
.hba-contact__row + .hba-contact__row { margin-top: 16px; }              /* H space-y-4 */
.hba-contact__row > [class*="hba-icon--"] {
  width: 16px;
  height: 16px;
  flex: none;
  margin: 2px 0 0;                                /* H mt-0.5 */
  background-color: var(--hba-amberink, #ffb900); /* H text-amber-400 */
  -webkit-mask: var(--hba-glyph, none) center / contain no-repeat;
  mask: var(--hba-glyph, none) center / contain no-repeat;
}
.hba-contact__rowtext { min-width: 0; }

/* H text-xl font-bold — the panel head is 20/28 700, NOT body.css's 30px h2. */
.hba-contact__details > .hba-heading:where(h2) {
  font-size: 20px;
  line-height: 28px;
  margin-bottom: 20px; /* H mb-5 */
}
.hba-contact__rowtext > .hba-heading:where(h3) { margin-bottom: 8px; }  /* H mb-2 */
.hba-contact__rowtext > .hba-body + .hba-cta   { margin-top: 4px; }     /* H mt-1, "Get Directions" */
/* "Get Directions" is the one amber row link — H `text-amber-400 text-xs`. */
.hba-contact__details .hba-contact__rowtext > .hba-body + .hba-cta.hba-cta--link {
  color: var(--hba-amberink, #ffb900);
  font-size: 12px;
  line-height: 16px;
}
/* The in-row hours label is live's `text-sm font-semibold`, not an h3 register. */
.hba-contact__rowtext > .hba-heading:where(h3) {
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.902); /* H text-white/90 */
}

.hba-contact__partners > .hba-heading,
.hba-contact__quick > .hba-heading { margin-bottom: 16px; }          /* H mb-4, both panel heads */
/* Quick Links' head is a size DOWN from the other two — H `text-lg font-semibold`
 * against their `text-xl font-bold`. Measured: 18/28 600 vs 20/28 700. */
.hba-contact__quick > .hba-heading { font-size: 18px; line-height: 28px; font-weight: 600; }
/* ✅ THE SPLIT THIS RULE WAS WAITING FOR HAS HAPPENED. The note here used to say
 * the two groups "differ only by POSITION inside the merged panel", that reaching
 * them via `:has(~ .hba-heading)` would mis-fire the moment the composition split
 * the panel, and that splitting it in compose-pages.php was the actual fix. It was,
 * and it is done — so each group now states its own live value directly.
 *   Partner Organizations  H `space-y-3` -> 12, rows are filled 44px chips
 *   Quick Links            H `space-y-2` -> 8,  rows are 20px text links */
.hba-contact__partners > .hba-cta + .hba-cta { margin-top: 12px; }  /* H space-y-3 */
.hba-contact__quick > .hba-cta + .hba-cta { margin-top: 8px; }      /* H space-y-2 */
/* Owner round-2: partner rows are live's filled CHIPS (Contact.tsx:150-157) —
 * `flex items-center justify-between p-3 bg-[#f5f7fa] rounded-lg
 * hover:bg-[#1e3a5f]/10`, Oswald semibold 14 navy label, trailing 14px gray
 * external glyph that turns amber on hover. Composed as `hba-cta--chip`. */
.hba-contact__partners > .hba-cta.hba-cta--chip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: auto;
  padding: 12px;                                  /* H p-3 */
  background: var(--hba-offwhite, #f5f7fa);
  border-radius: 8px;                             /* H rounded-lg */
  font-family: var(--hba-font-display);
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  color: #0d1b2a;
  text-decoration: none;
  transition: background-color var(--hba-duration-slow, 300ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-contact__partners > .hba-cta.hba-cta--chip:hover { background: rgba(30, 58, 95, 0.1); } /* H hover:bg-[#1e3a5f]/10 */
.hba-contact__partners > .hba-cta.hba-cta--chip .hba-icon--external {
  width: 14px;
  height: 14px;
  margin: 0;
  background-color: #99a1af;                      /* H text-gray-400 */
  transition: background-color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-contact__partners > .hba-cta.hba-cta--chip:hover .hba-icon--external { background-color: var(--hba-amberfill, #fe9a00); } /* H group-hover:text-amber-500 */
/* Quick links lead with the arrow at live's gap-2. */
.hba-contact__quick > .hba-cta.hba-cta--link { gap: 8px; align-items: center; }
/* ✅ RETIRED. This rule reconstructed the 24px between the two groups because the
 * composition merged them into one panel and there was no inter-panel gap to
 * measure. They are two panels again, and the 24 is now where live puts it — the
 * aside's own `space-y-6` stack gap — so the reconstruction is gone rather than
 * left behind as a second, quieter home for the same fact. */


/* --------------------------------------------- card hover: the border half ---
 * REAL GAP found by browser row B-11 / I-05, 2026-08-20. The card lifted
 * (boxShadow + transform) but its BORDER never moved, which is half the register.
 *
 * Live, from /benefits' own markup, on all six cards:
 *   border border-gray-100 hover:border-[#1e3a5f]/30 hover:shadow-xl
 *   transition-all duration-300
 * and observed-tokens hoverRegisters[4] ("benefit card") agrees exactly:
 *   borderTopColor #f3f4f6 -> #1e3c60 a=0.302
 *
 * Standard easing at 300ms — NOT the expressive curve. Trap 4 reserves that for
 * exactly two consumers, and the live DOM does not make this one of them.
 */
.hba-card--icon,
.hba-card {
  transition: border-color 300ms cubic-bezier(0.4, 0, 0.2, 1),
              box-shadow   300ms cubic-bezier(0.4, 0, 0.2, 1),
              transform    300ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* !important, deliberately and narrowly. Bricks emits the card's border as a
 * PER-ELEMENT ID RULE — `#brxe-bb780d { border: 1px solid #f3f4f6 }` at (1,0,0) —
 * which no class selector can outrank. Measured, not assumed: the (0,2,0) form of
 * this rule lost and the hover border never moved. Scoped to the hover state and
 * to border-color alone, so the resting border stays exactly as Bricks set it.
 *
 * 2026-08-21 INTERIOR ROUND — THE TWO EXCLUSIONS BELOW ARE LOAD-BEARING. An
 * `!important` outranks specificity, so before they were added this rule repainted
 * EVERY card family's hover border, including the two whose live hover border is
 * something else entirely: a dark card is `hover:border-amber-400/40` and a
 * federation card keeps its static `border-white/10`. Both would have gone navy/30
 * — invisible on a charcoal ground and on a navy one. The families this rule is
 * actually for (benefit groups, news cards, membership types, event cards, HBAA
 * rows) all measure `hover:border-[#1e3a5f]/30` on live. */
.hba-card--icon:hover,
.hba-card:not(.hba-card--dark, .hba-card--navy):hover {
  border-color: rgba(30, 58, 95, 0.3) !important;
}

/* ############################################################################
 * 2026-08-21 FIX ROUND — owner side-by-side review, home route.
 * Composition is changing concurrently (compose-pages.php / compose-chrome.php);
 * class names below are the AGREED set from the TL brief. Anything assumed
 * beyond that list is marked. All artwork is traced from the live lucide SVGs
 * in H (paths verbatim); mask-image + currentColor per the existing --hba-glyph
 * technique above.
 * ######################################################################## */

/* ---------------------------------------------------- CTA + UI glyph masks ---
 * H sources, exact:
 *   arrow-right   16px in the hero/sectionhead CTAs (Home.tsx:179/435-adjacent),
 *                 14px inside card links (Home.tsx:384/532), 18px event rows
 *   calendar-days 16px in VIEW CALENDAR (Home.tsx:435); 26px in the hero tile
 *   newspaper     16px in ALL NEWS (Home.tsx:486)
 *   users         18px in FIND A MEMBER (Home.tsx:561) — the brief's
 *                 "user-search" name maps to THIS artwork; live is lucide-users
 *   external-link 14px card links (Home.tsx:384), 12px footer partner links,
 *                 10px utility bar
 *   map-pin/phone/mail/clock  14px, amber-400, footer contact block
 *   facebook      14px, fill-based, footer bottom bar
 * All stroke-2, round caps/joins, currentColor. Mask alpha only needs opaque
 * strokes, so the data URIs stroke in #000. */
.hba-cta__arrow,
.hba-cta__icon,
.hba-icon--arrow,
.hba-icon--calendar,
.hba-icon--news,
.hba-icon--person-search,
.hba-icon--external,
.hba-icon--map-pin,
.hba-icon--phone,
.hba-icon--mail,
.hba-icon--clock,
.hba-icon--facebook,
.hba-icon--join,
.hba-icon--hardhat,
.hba-icon--login,
.hba-icon--award,
.hba-icon--building {
  display: inline-block;
  width: 16px;
  height: 16px;
  flex: none;
  margin: 0;
  background-color: currentColor;
  -webkit-mask: var(--hba-glyph, none) center / contain no-repeat;
  mask: var(--hba-glyph, none) center / contain no-repeat;
}
/* lucide arrow-right (H Home.tsx:179): M5 12h14 / m12 5 7 7-7 7 */
.hba-cta__arrow,
.hba-icon--arrow {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E");
}
/* lucide calendar-days (H Home.tsx:435) */
.hba-icon--calendar {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3Cpath d='M8 14h.01'/%3E%3Cpath d='M12 14h.01'/%3E%3Cpath d='M16 14h.01'/%3E%3Cpath d='M8 18h.01'/%3E%3Cpath d='M12 18h.01'/%3E%3Cpath d='M16 18h.01'/%3E%3C/svg%3E");
}
/* lucide newspaper (H Home.tsx:486) */
.hba-icon--news {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-2 2Zm0 0a2 2 0 0 1-2-2v-9c0-1.1.9-2 2-2h2'/%3E%3Cpath d='M18 14h-8'/%3E%3Cpath d='M15 18h-5'/%3E%3Cpath d='M10 6h8v4h-8V6Z'/%3E%3C/svg%3E");
}
/* lucide users (H Home.tsx:561 — see the naming note above) */
.hba-icon--person-search {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cpath d='M22 21v-2a4 4 0 0 0-3-3.87'/%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75'/%3E%3C/svg%3E");
}
/* lucide external-link (H Home.tsx:384) */
.hba-icon--external {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 3h6v6'/%3E%3Cpath d='M10 14 21 3'/%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3C/svg%3E");
}
/* lucide map-pin (H Footer.tsx:104) */
.hba-icon--map-pin {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0'/%3E%3Ccircle cx='12' cy='10' r='3'/%3E%3C/svg%3E");
}
/* lucide phone (H Footer.tsx:112) */
.hba-icon--phone {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z'/%3E%3C/svg%3E");
}
/* lucide mail (H Footer.tsx:121) */
.hba-icon--mail {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
}
/* lucide clock (H Footer.tsx:126) — same artwork the C-60 stub traces above */
.hba-icon--clock {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
}
/* 2026-08-21 DELTA ROUND — remaining glyphs, paths verbatim from H: */
/* lucide user-plus (H Home.tsx:208, "Join" hero tile) */
.hba-icon--join {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cline x1='19' x2='19' y1='8' y2='14'/%3E%3Cline x1='22' x2='16' y1='11' y2='11'/%3E%3C/svg%3E");
}
/* lucide hard-hat (H Home.tsx:208, "Hire a Member" hero tile) */
.hba-icon--hardhat {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 18a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v2z'/%3E%3Cpath d='M10 10V5a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v5'/%3E%3Cpath d='M4 15v-3a6 6 0 0 1 6-6'/%3E%3Cpath d='M14 6a6 6 0 0 1 6 6v3'/%3E%3C/svg%3E");
}
/* lucide log-in (H Home.tsx:208, "Member Portal" — the FOURTH hero tile).
 * ⚠ NOT in the delta contract's class list; authored under the obvious name so
 * the fourth tile is not a blank disc if the composition used it. Reported. */
.hba-icon--login {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4'/%3E%3Cpolyline points='10 17 15 12 10 7'/%3E%3Cline x1='15' x2='3' y1='12' y2='12'/%3E%3C/svg%3E");
}
/* lucide award (H Home.tsx:375, HBAA savings-card disc, 36px navy) */
.hba-icon--award {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m15.477 12.89 1.515 8.526a.5.5 0 0 1-.81.47l-3.58-2.687a1 1 0 0 0-1.197 0l-3.586 2.686a.5.5 0 0 1-.81-.469l1.514-8.526'/%3E%3Ccircle cx='12' cy='8' r='6'/%3E%3C/svg%3E");
}
/* lucide building-2 (H Home.tsx:395 NAHB savings-card disc 36px navy;
 * Home.tsx:342 NAHB partner disc 22px white) */
.hba-icon--building {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z'/%3E%3Cpath d='M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2'/%3E%3Cpath d='M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2'/%3E%3Cpath d='M10 6h4'/%3E%3Cpath d='M10 10h4'/%3E%3Cpath d='M10 14h4'/%3E%3Cpath d='M10 18h4'/%3E%3C/svg%3E");
}
/* Facebook glyph, fill-based (H Footer.tsx:158–159, path verbatim) */
.hba-icon--facebook {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Cpath d='M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z'/%3E%3C/svg%3E");
}
/* Guard: if the composition pairs a glyph modifier with the bare .hba-icon base
 * (30px navy block, mb-12) INSIDE a CTA, the CTA context wins. */
.hba-cta .hba-icon,
.hba-cta [class*="hba-icon--"] {
  width: 16px;
  height: 16px;
  margin: 0;
  background-color: currentColor;
}
/* Context sizes, all read from H width/height attributes: */
.hba-card .hba-cta__arrow,
.hba-card .hba-cta__icon,
.hba-card--dark .hba-cta__arrow,
.hba-card--dark .hba-cta__icon,
.hba-card--icon .hba-cta__arrow,
.hba-card--icon .hba-cta__icon { width: 14px; height: 14px; } /* card links */
.hba-cta--primary .hba-icon--person-search { width: 18px; height: 18px; } /* FIND A MEMBER */

/* -------------------------------------------------------- section head row ---
 * H, both home instances (Home.tsx:422 and :473), verbatim:
 *   `flex flex-col lg:flex-row items-start lg:items-center justify-between
 *    mb-10 gap-4`
 * Left block (eyebrow + h2) is left-aligned; the action button rides right at
 * lg. body.css's centred default targets DIRECT children of .hba-section__inner,
 * which these no longer are once wrapped — text-align is still pinned left here
 * so the row cannot inherit a centred context.
 * .brxe-container trap: direction, alignment AND width restated (3 priors). */
.hba-sectionhead {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;       /* H gap-4 */
  width: 100%;
  margin-bottom: 40px; /* H mb-10 */
  text-align: left;
}
/* ⛔ THE HEAD → GRID GAP WAS BEING PAID TWICE, AND IT IS 40px OF THE OWNER'S
 * "bunched up" ON FIVE SECTIONS. Found by measuring, 2026-08-21 rhythm round:
 *     .hba-sectionhead   mar 0/40   (this rule, H mb-10)
 *     .hba-grid          mar 40/0   (body.css `.hba-section__inner > * +
 *                                    :where(.hba-grid, …) { margin-top: 40px }`)
 *   = 80px where live measures 40 — spacing-probe on `/` [7] Industry News gives
 *   live `head mar 0/40` + `grid mar 0/0`. That single 40 is /events [1] being
 *   +48 and `/` [7] being +41 against live; it is not visible in a card audit
 *   because neither rule is wrong on its own.
 * The duplicate is MINE: body.css's content-block rule spaced grids from whatever
 * precedes them site-wide long before this wrapper existed, so where it fires this
 * class must not fire too. Dropped here rather than neutralised on `.hba-grid`,
 * which is body.css's element and not this lane's to touch. Coupling reported.
 * ⚠ ONLY `.hba-grid` collides. The other things a sectionhead introduces in this
 * composition — `.hba-eventrow`, `.hba-eventlist`, `.hba-newsstack` — are NOT in
 * body.css's content-block list, so for those this class is the only source of the
 * gap and keeps its 40. Verified against every `.hba-sectionhead` call site. */
.hba-sectionhead:has(+ .hba-grid) { margin-bottom: 0; }
.hba-sectionhead > * { text-align: left; }
.hba-sectionhead .hba-eyebrow,
.hba-sectionhead .hba-heading { margin-left: 0; margin-right: 0; }
@media (min-width: 1024px) {
  .hba-sectionhead {
    flex-direction: row;
    align-items: center; /* H lg:items-center — live aligns CENTER, not end */
  }
  .hba-sectionhead > .hba-cta { flex: none; } /* H flex-shrink-0 */
}
/* The sectionhead action register: H px-6 py-2.5 on BOTH the navy VIEW CALENDAR
 * and the outline ALL NEWS. Scoped here so the CF7 submit (which shares
 * --navy) keeps its own padding. */
.hba-sectionhead .hba-cta--navy,
.hba-sectionhead .hba-cta--outline {
  padding: 10px 24px; /* H px-6 py-2.5 */
  gap: 8px;           /* H gap-2 */
}
/* ⚠ TWO OUTLINE REGISTERS ON DARK. The hero CONTACT US is border-white/40 →
 * white/80 (hero.css --outline). The sectionhead ALL NEWS is measurably
 * different (H Home.tsx:482): `border-white/30 hover:border-amber-400
 * text-white hover:text-amber-400`, and NO active:scale. Authored as the
 * sectionhead-scoped delta over --outline. */
.hba-sectionhead .hba-cta--outline {
  border-color: rgba(255, 255, 255, 0.3);
}
.hba-sectionhead .hba-cta--outline:hover {
  border-color: #ffb900; /* amber-400 */
  color: #ffb900;
}
.hba-sectionhead .hba-cta--outline:active { transform: none; }

/* Delta round: the left block. Alignment is already pinned by the
 * `.hba-sectionhead > *` rule above; what it adds is the tighter live eyebrow
 * register (H Home.tsx:424: `mb-2` = 8px, vs body.css's 12px sibling gap). */
.hba-sectionhead__copy { text-align: left; }
.hba-sectionhead__copy .hba-eyebrow { margin-bottom: 8px; } /* H mb-2 */
/* ⛔ THESE TWO GO TOGETHER, AND EITHER ONE ALONE MAKES THE BAND WORSE.
 * Home's "Find a Member" band, `/` [7]. Live 256, ours was 261 — and that +5 was
 * two errors cancelling:
 *   - the paragraph ran ONE line where live takes TWO (live caps it at max-w-lg
 *     and sets it at the default 16/24; ours inherited body.css's 18/29.25, which
 *     is live's `text-lg` hero size and correct for section leads, not for this),
 *   - against a phantom 40px below the head, because line ~1555 gives every
 *     .hba-sectionhead `margin-bottom: 40` and this band's head has NO following
 *     sibling at all to need a gap from.
 * Landing the cap by itself took the band to +76. Measured, both directions. */
.hba-sectionhead__copy > .hba-body {
  font-size: 16px;      /* H: live's default paragraph, not text-lg */
  line-height: 24px;
  max-width: 512px;     /* H max-w-lg (Home.tsx:544) */
}
.hba-sectionhead:last-child { margin-bottom: 0; }
/* RHYTHM ROUND: the head's h2 → paragraph gap, which nothing supplied. Wrapping
 * the head took these out of `.hba-section__inner`'s direct children, so body.css's
 * `> .hba-heading + *` rule stopped reaching them — the same one-level-deep miss
 * the card interiors had, in the one head that carries copy.
 * `:has(+ .hba-body)` is not decoration: exactly ONE of the nine
 * `.hba-sectionhead__copy` blocks the composition emits has a paragraph under its
 * heading (home's "Find a Member"), and live gives only that one an `mb-3` —
 * H Home.tsx:548 `text-3xl lg:text-4xl mb-3`. The other eight are `text-3xl` with
 * no margin at all (H Home.tsx:478, News.tsx:202, …), and a blanket rule would
 * have opened 12px under every one of them. */
.hba-sectionhead__copy .hba-heading:has(+ .hba-body) { margin-bottom: 12px; } /* H mb-3 */

/* Delta round: the centered row under the benefits grid holding the
 * VIEW ALL MEMBER BENEFITS textlink. H (Home.tsx:408): `text-center mt-8`. */
.hba-sectionfoot {
  width: 100%;
  margin-top: 32px; /* H mt-8 */
  text-align: center;
}

/* --------------------------------------------------- hero tile icon discs ---
 * H (Home.tsx:207–208), verbatim:
 *   disc  `w-14 h-14 rounded-full bg-white/10 group-hover:bg-amber-500/20
 *          flex items-center justify-center transition-all duration-200`
 *   icon  26×26 lucide, `text-white group-hover:text-amber-400
 *          transition-colors duration-200` */
.hba-tile__disc {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;  /* H w-14 */
  height: 56px; /* H h-14 */
  flex: none;
  border-radius: var(--hba-radius-pill, 9999px);
  background: var(--hba-white-white10, rgba(255, 255, 255, 0.102));
  color: var(--hba-white, #ffffff);
  transition: background-color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1)),
              color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-tile__disc [class*="hba-icon--"] { width: 26px; height: 26px; }
.hba-tile:hover .hba-tile__disc {
  background: var(--hba-ambertint-20, rgba(254, 154, 0, 0.200)); /* H amber-500/20 */
  color: var(--hba-amberink, #ffb900);                           /* H text-amber-400 */
}
/* The tile's H `gap-3` was deliberately withheld while no disc existed (see the
 * C-82 note above). It returns only when the disc is present. */
.hba-tile:has(.hba-tile__disc) { gap: 12px; }

/* ------------------------------------------------------ stats band on navy ---
 * Home strip, H (Home.tsx:228–240), verbatim:
 *   section `bg-[#1e3a5f] py-8`
 *   grid    `grid grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-0 lg:divide-x
 *            lg:divide-white/20`
 *   cell    `text-center px-6`
 *   value   `font-['Oswald'] font-bold text-amber-400 text-3xl lg:text-4xl`
 *   label   `text-white/70 text-sm font-['Source_Sans_3'] mt-1`
 * The existing .hba-stats/.hba-stat rules are the /about offWhite-card usage.
 * On a navy field the live strip is card-less, centred, amber/white — authored
 * as the field-scoped variant so /about is untouched. */
.hba-field-navy .hba-stats {
  grid-template-columns: repeat(2, 1fr);
  gap: 24px; /* H gap-6 */
}
.hba-field-navy .hba-stat {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0 24px; /* H px-6 */
  text-align: center;
}
.hba-field-navy .hba-stat__value {
  font-size: 30px;        /* H text-3xl */
  line-height: 36px;
  color: var(--hba-amberink, #ffb900); /* H text-amber-400 */
  margin: 0;
}
.hba-field-navy .hba-stat__label {
  font-weight: 400;
  color: var(--hba-white-white70, rgba(255, 255, 255, 0.698)); /* H text-white/70 */
  margin: 4px 0 0; /* H mt-1 */
}
.hba-field-navy .hba-stat__sub { color: var(--hba-white-white55, rgba(255, 255, 255, 0.549)); }

/* ⛔ THE HOME BAND HOLDS THREE STATS NOW, NOT FOUR (client 2026-09-02, ruling
 * SS-13 — "1,000+ Homes Built Annually" was removed at her request), AND THE
 * COLUMN COUNT HAD TO STOP BEING A LITERAL.
 *
 * `repeat(4, 1fr)` with three children does not re-balance: it fills three
 * columns, leaves the fourth empty, and the whole strip sits visibly left of centre
 * under a centred hero. That is a direct consequence of the content change, not
 * something the live capture could have shown.
 *
 * ⚠ AUTO-FLOW RATHER THAN `repeat(3, 1fr)`, DELIBERATELY. Hard-coding 3 replaces
 * one count-dependent rule with another, and this count has now changed once
 * already. Column auto-flow gives N equal columns for whatever N the composer
 * emits: correct at three, correct if a fourth ever returns, and correct without
 * anyone remembering this rule exists. `grid-template-columns: none` is REQUIRED to
 * hand the axis over — leave the template in place and the explicit tracks win and
 * the auto-flow does nothing at all.
 *
 * Below 1024px the band stays the 2-up stack live measures. An odd last child would
 * be stranded in a half-width cell under a centred pair, so it spans instead —
 * count-agnostic for the same reason as above. */
.hba-field-navy .hba-stat:last-child:nth-child(odd) {
  grid-column: 1 / -1;
}
@media (min-width: 1024px) {
  .hba-field-navy .hba-stats {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: 0;
  }
  /* The span above is a 2-up rule only; at 1024+ every stat is its own column. */
  .hba-field-navy .hba-stat:last-child:nth-child(odd) {
    grid-column: auto;
  }
  .hba-field-navy .hba-stat + .hba-stat {
    border-left: 1px solid rgba(255, 255, 255, 0.2); /* H lg:divide-white/20 */
  }
  .hba-field-navy .hba-stat__value { font-size: 36px; line-height: 40px; } /* H lg:text-4xl */
}

/* -------------------------------------------------------- about extras (home) ---
 * Badge, H (Home.tsx:302–304), verbatim:
 *   `absolute -bottom-6 -left-6 bg-amber-500 text-white p-5 rounded-xl shadow-xl`
 *   value `font-['Oswald'] font-bold text-2xl`; label `text-sm text-white/90`
 * shadow-xl is Tailwind's 0 20px 25px -5px / 0 8px 10px -6px at black 10%.
 * The badge's parent (the image wrapper) must be a containing block; live gives
 * it `relative` and :has() supplies that here without knowing its class. */
:where(div, figure):has(> .hba-about__badge) { position: relative; }
.hba-about__badge {
  position: absolute;
  bottom: -24px; /* H -bottom-6 */
  left: -24px;   /* H -left-6 */
  z-index: 1;
  padding: 20px; /* H p-5 */
  background: var(--hba-amberfill, #fe9a00); /* H bg-amber-500 */
  color: var(--hba-white, #ffffff);
  border-radius: var(--hba-radius-card, 12px); /* H rounded-xl */
  box-shadow: rgba(0, 0, 0, 0.1) 0px 20px 25px -5px, rgba(0, 0, 0, 0.1) 0px 8px 10px -6px;
  text-align: left;
}
/* Delta round: the children landed as classed spans, still first/last — the
 * positional selectors keep working; the classes are added as explicit
 * synonyms so the rules survive any future third child. */
.hba-about__badge-value,
.hba-about__badge > :first-child {
  font-family: var(--hba-font-display);
  font-size: 24px;   /* H text-2xl */
  line-height: 32px;
  font-weight: 700;
  color: var(--hba-white, #ffffff);
  margin: 0;
}
.hba-about__badge-label,
.hba-about__badge > :last-child {
  font-family: var(--hba-font-text);
  font-size: 14px;   /* H text-sm */
  line-height: 20px;
  font-weight: 400;
  color: var(--hba-white-white90, rgba(255, 255, 255, 0.902));
  margin: 0;
}
/* The small logo above the About eyebrow: H `h-14 w-auto object-contain`,
 * wrapper `mb-5`. Size rule only, per the brief. */
.hba-about__logo {
  height: 56px; /* H h-14 */
  width: auto;
  object-fit: contain;
  margin-bottom: 20px; /* H mb-5 */
}

/* -------------------------------------- home benefit cards (light --icon) ---
 * H, the two home "savings" cards (Home.tsx:369/387), verbatim:
 *   card `bg-white rounded-xl p-8 flex flex-col items-center text-center
 *         shadow-md hover:shadow-xl … border border-gray-100
 *         hover:border-[#1e3a5f]/30` (duration-300)
 *   disc `w-20 h-20 bg-[#1e3a5f]/10 rounded-full flex items-center
 *         justify-center mb-4 group-hover:bg-[#1e3a5f]/20 transition-colors`
 *   icon 36×36 lucide, `text-[#1e3a5f]`
 * NOTE the disc is NAVY/10, not grey — measured, not the brief's "#f5f7fa-ish".
 * The disc class is the structural hook that distinguishes these from the p-7
 * /benefits group cards sharing --icon (same technique as the :has() dark pair
 * above). ⚠ `.hba-card__disc` IS AN ASSUMED NAME — not in the agreed list. */
.hba-card__disc {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 80px;  /* H w-20 */
  height: 80px; /* H h-20 */
  flex: none;
  border-radius: var(--hba-radius-pill, 9999px);
  background: rgba(30, 58, 95, 0.1); /* H bg-[#1e3a5f]/10 */
  color: var(--hba-navy, #1e3a5f);
  margin: 0 auto 16px; /* H mb-4 */
  transition: background-color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-card__disc [class*="hba-icon--"],
.hba-card__disc .hba-icon { width: 36px; height: 36px; margin: 0; }
/* ⛔ `:not(.hba-card--dark)` IS LOAD-BEARING, ADDED 2026-08-21 AND MEASURED, NOT
 * DECORATIVE. The interior round gives /benefits' two AFFILIATED cards the class
 * set `hba-card hba-card--dark hba-card--icon hba-card--center` with a
 * `hba-card__disc hba-card__disc--amber` inside — so they now match
 * `.hba-card--icon:has(> .hba-card__disc)` too. Both that rule and the charcoal
 * `:has(.hba-icon--house)` rule near the top of this file are (0,2,0), and THIS
 * ONE IS LATER IN THE FILE, so without the exclusion the two dark affiliate cards
 * would have flipped to a WHITE background — a regression introduced by a
 * composition change, in a rule neither agent was editing. The guard is the whole
 * reason the pair still reads dark. */
.hba-card--icon:not(.hba-card--dark):has(> .hba-card__disc) {
  background: var(--hba-white, #ffffff);
  padding: 32px; /* H p-8 */
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  box-shadow: var(--hba-shadow-card, rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.1) 0px 2px 4px -2px); /* H shadow-md */
}
.hba-card--icon:not(.hba-card--dark):has(> .hba-card__disc):hover {
  box-shadow: rgba(0, 0, 0, 0.1) 0px 20px 25px -5px, rgba(0, 0, 0, 0.1) 0px 8px 10px -6px; /* H shadow-xl */
}
/* RHYTHM ROUND: this family's title is TIGHTER than the base card's mb-3.
 * H (Home.tsx:377), verbatim: `font-['Oswald'] font-semibold text-[#0d1b2a]
 * text-xl mb-2`, then `text-gray-600 text-sm leading-relaxed mb-4`, then the
 * "Explore …" span. Live's 16px between the paragraph and the link is already
 * delivered by the base register's `.hba-card > .hba-cta { margin-top: 16px }` —
 * the link is the last child here — so the paragraph gets NO bottom margin and
 * the gap is stated once, not twice. (In a Bricks flex card the two would add.) */
.hba-card--icon:not(.hba-card--dark):has(> .hba-card__disc) > .hba-heading {
  margin-bottom: 8px; /* H mb-2 */
}
/* H `group-hover:bg-[#1e3a5f]/20` — but ONLY on home's benefit cards. /about's Core
 * Values card has no hover at all on live and its disc is a SOLID navy, so a
 * translucent-navy hover on it would both lighten the disc and invent a gesture.
 * `:not(.hba-card--center)` is the discriminator the composition gives us: home's
 * cards are the only `--icon` cards that are not `--center`. */
.hba-card--icon:not(.hba-card--center):hover > .hba-card__disc {
  background: rgba(30, 58, 95, 0.2); /* H group-hover:bg-[#1e3a5f]/20 */
}
/* The card's amber link ("Explore Benefits"): ink is amber-500 at rest on these
 * LIGHT cards (H `text-amber-500`), where hero.css's --link would leave navy. */
.hba-card--icon:not(.hba-card--dark):has(> .hba-card__disc) .hba-cta--link { color: var(--hba-amberfill, #fe9a00); }

/* ----------------------------------------------------- event row hover arrow ---
 * H (Home.tsx:463): every home event row carries an 18×18 arrow-right at the
 * row's right edge — `text-gray-300 group-hover:text-amber-500
 * transition-colors flex-shrink-0`. It is PRESENT at rest (grey), turning amber
 * on row hover; it does not translate. The title also shifts ink on row hover
 * (H `group-hover:text-[#1e3a5f]`). Both were missing.
 * ⚠ `.hba-eventchip__arrow` IS AN ASSUMED NAME — not in the agreed list. */
.hba-eventchip { padding-right: 58px; } /* 20 + 18 arrow + 20 gap-5 */
/* Interior round: the /calendar rows now carry the arrow as a NAMED pair —
 * `hba-eventlist__row--arrow` on the row and `hba-eventlist__arrow hba-icon--arrow`
 * on the span — replacing the `:has(.hba-cta__arrow)` probe this rule used to run.
 * Clearance is still opt-in, so /events' arrowless rows keep their measured 20px
 * right padding. Both spellings are kept: the `:has()` form still covers any row
 * that carries a CTA arrow instead. */
.hba-eventlist__row--arrow,
.hba-eventlist__row:has(.hba-cta__arrow) { padding-right: 58px; }
.hba-eventchip .hba-cta__arrow,
.hba-eventlist__row .hba-cta__arrow,
.hba-eventlist__arrow,
.hba-eventchip__arrow {
  position: absolute;
  right: 20px;
  top: 50%;
  width: 18px;
  height: 18px;
  margin-top: -9px;
  display: inline-block;
  flex: none;
  background-color: #d1d5db; /* H text-gray-300 — literal: no seeded token carries gray-300 (P-5: no unresolvable vars) */
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: background-color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-eventchip:hover .hba-cta__arrow,
.hba-eventlist__row:hover .hba-cta__arrow,
.hba-eventlist__row:hover .hba-eventlist__arrow,
.hba-eventchip:hover .hba-eventchip__arrow {
  background-color: var(--hba-amberfill, #fe9a00); /* H group-hover:text-amber-500 */
}
.hba-eventchip__title { transition: color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1)); }
.hba-eventchip:hover .hba-eventchip__title { color: var(--hba-navy, #1e3a5f); } /* H group-hover */

/* ------------------------------------------------------------ footer icons ---
 * Contact block (H Footer.tsx:104–126): 14×14 lucide, `text-amber-400`, rows
 * `flex items-center/items-start gap-2.5`. Partner links carry a 12×12
 * external-link at currentColor (H Footer.tsx:68–90). Bottom bar: 14×14
 * Facebook glyph at white/40 → amber-400 hover — .hba-footer__social already
 * carries the ink+hover; the glyph inherits it via currentColor. */
.hba-footer__top .hba-icon--map-pin,
.hba-footer__top .hba-icon--phone,
.hba-footer__top .hba-icon--mail,
.hba-footer__top .hba-icon--clock {
  width: 14px;
  height: 14px;
  background-color: var(--hba-amberink, #ffb900); /* H text-amber-400 */
  margin-right: 10px; /* H gap-2.5 */
}
.hba-footer__link .hba-icon--external,
.hba-footer__barlink .hba-icon--external {
  width: 12px;
  height: 12px;
  /* margin-RIGHT: the glyph LEADS on live ([svg, TEXT], measured in the rendered
   * DOM 2026-08-21). It shipped trailing here on the reasonable-but-wrong
   * assumption that an external-link marker follows its label. Flipping the
   * composition without flipping this side leaves the icon leading with a left
   * margin, which reads as a new defect — the two are one change. */
  margin-right: 4px; /* H gap-1 */
}
.hba-footer__social .hba-icon--facebook { width: 14px; height: 14px; }
/* Inside a flex contact row (site.css .hba-footer__row) the 10px separation is
 * the row's gap, not the icon's margin — zeroed here so it doesn't double; the
 * 3px top nudge is H mt-0.5, optically centering on the first text line. */
.hba-footer__row > [class*="hba-icon--"] { margin-right: 0; margin-top: 3px; }

/* Reduced motion for everything this round added (motion.css conventions;
 * transitions only, so they collapse cleanly). */
@media (prefers-reduced-motion: reduce) {
  .hba-cta,
  .hba-tile__disc,
  .hba-card__disc,
  .hba-sectionhead .hba-cta--outline,
  .hba-eventchip .hba-cta__arrow,
  .hba-eventchip__arrow,
  .hba-eventchip__title { transition-duration: 0s; }
}

/* ############################################################################
 * 2026-08-21 INTERIOR ROUND — owner side-by-side review, seven routes.
 *
 * The home round left the interior pages standing on a base card that HAD NO
 * RULE (see the CARDS block at the top of this file). Everything below either
 * completes a component the composition now emits or corrects a register the
 * owner's Live-vs-Generated pairs showed wrong.
 *
 * PROVENANCE for this whole block is H — the live DOM as served, re-read this
 * round from hba-capture/content/html/{events,news,benefits,about,
 * become-a-member}.html. Class strings are quoted verbatim beside every value.
 * Tailwind is decoded at the SOURCE's 16px root, as everywhere else in this file:
 *   text-xs 12 · text-sm 14 · text-base 16 · text-lg 18 · text-xl 20 · text-2xl 24
 *   leading-none 1 · leading-tight 1.25 · leading-snug 1.375 · leading-relaxed 1.625
 *   p-5 20 · p-6 24 · p-7 28 · p-8 32 · gap-1 4 · gap-1.5 6 · gap-2 8 · gap-3 12
 *   gap-4 16 · gap-5 20 · h-2 8 · w-8 32 · w-10 40 · w-12 48 · w-14 56 · w-16 64
 *
 * CLASS NAMES are the ones compose-pages.php and bin/import-forms.php actually
 * emit, read out of both files rather than agreed in prose — the contract in the
 * brief named `hba-applyrow`, the composition emits `hba-optioncols`, and three
 * other names moved the same way. Every selector below was checked against the
 * emitting call site. Coverage was then verified mechanically: every `hba-*`
 * class either file emits now matches at least one rule in this lane.
 * ######################################################################## */

/* ------------------------------------------------------- new glyph masks ---
 * Same --hba-glyph technique as the library above; paths traced VERBATIM from the
 * lucide SVGs in H. Mask alpha only needs opaque strokes, so the data URIs stroke
 * in #000 and the ink comes from `background-color`.
 *   circle-check  15px, /benefits list markers      (Benefits.tsx:110)
 *   star          24px, /events "Featured Events"   (Events.tsx:124)
 *   download      16px PDF buttons, 14px flyer link (BecomeMember.tsx:217, News.tsx:135)
 *   file-text     24px, /become-a-member PDF panel  (BecomeMember.tsx:204)
 *   user-plus     24px, /become-a-member form head  (BecomeMember.tsx:258)
 * `--user-plus` is the SAME artwork as the existing `--join`; the composition uses
 * both names, so both are declared rather than one silently aliased. */
.hba-icon--check-circle,
.hba-icon--star,
.hba-icon--download,
.hba-icon--file,
.hba-icon--user-plus,
.hba-list__marker,
.hba-meta__icon,
.hba-newsrow__ext,
.hba-card__ext,
.hba-optionblock__icon,
.hba-formwrap__icon,
.hba-heading__icon {
  display: inline-block;
  flex: none;
  background-color: currentColor;
  -webkit-mask: var(--hba-glyph, none) center / contain no-repeat;
  mask: var(--hba-glyph, none) center / contain no-repeat;
}
/* lucide circle-check (H Benefits.tsx:110): circle r=10 + "m9 12 2 2 4-4" */
.hba-icon--check-circle {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='m9 12 2 2 4-4'/%3E%3C/svg%3E");
}
/* lucide star (H Events.tsx:124) — a single polygon, points verbatim */
.hba-icon--star {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/%3E%3C/svg%3E");
}
/* lucide download (H BecomeMember.tsx:217) */
.hba-icon--download {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'/%3E%3Cpolyline points='7 10 12 15 17 10'/%3E%3Cline x1='12' x2='12' y1='15' y2='3'/%3E%3C/svg%3E");
}
/* lucide file-text (H BecomeMember.tsx:204) */
.hba-icon--file {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z'/%3E%3Cpath d='M14 2v4a2 2 0 0 0 2 2h4'/%3E%3Cpath d='M10 9H8'/%3E%3Cpath d='M16 13H8'/%3E%3Cpath d='M16 17H8'/%3E%3C/svg%3E");
}
/* lucide user-plus — identical artwork to .hba-icon--join above */
.hba-icon--user-plus {
  --hba-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cline x1='19' x2='19' y1='8' y2='14'/%3E%3Cline x1='22' x2='16' y1='11' y2='11'/%3E%3C/svg%3E");
}

/* ============================================== 4. BENEFIT LIST MARKERS ===
 * body.css reserved the marker slot and now fills its BOX; the artwork and the
 * two guards are here.
 *
 * GUARD 1 — the composition emits `<span class="hba-list__marker
 * hba-icon--check-circle">`, i.e. one element carrying both the box and the
 * glyph. It is registered in the mask-carrier group above so the mask actually
 * paints; this restates the 15x15 afterwards so it beats that group's 16x16 on
 * source order (both are (0,1,0)).
 * GUARD 2 — if the marker is ever wrapped around a separate `.hba-icon` child,
 * the base `.hba-icon` (30px NAVY block with a 12px bottom margin) would paint a
 * huge navy square. Same class of trap the `.hba-cta .hba-icon` guard above
 * catches, same fix. (0,2,0) over (0,1,0). */
.hba-list__marker { width: 15px; height: 15px; }
.hba-list__marker .hba-icon,
.hba-list__marker [class*="hba-icon--"] {
  width: 15px;
  height: 15px;
  margin: 0;
  background-color: currentColor;
}

/* Live's group card is `h3 … mb-4` above the <ul> (H Benefits.tsx:104 — `font-bold
 * text-[#0d1b2a] text-xl mb-4`). Nothing in this build gave the two any separation
 * at all: inside a card, body.css's section-flow rules do not reach, so the list
 * sat hard against the heading.
 * 2026-08-21 RHYTHM ROUND — RESTATED AS A margin-bottom, AND THE CHANGE IS NOT
 * COSMETIC. This used to be `> .hba-heading + .hba-list { margin-top: 16px }`. The
 * base card register now gives every card h3 a 12px margin-bottom, and a Bricks
 * card is a FLEX column, where the two do not collapse — the pair would have
 * painted 28px. Same value, same source, one mechanism; `:has(+ .hba-list)` keeps
 * it aimed at the heading that actually introduces a list, and its (0,3,0) clears
 * the base register's (0,2,0). */
.hba-card--icon > .hba-heading:has(+ .hba-list) { margin-bottom: 16px; } /* H mb-4 */

/* ==================================================== SQUARE ICON TILES ===
 * `hba-card__iconsq` — the ROUNDED-SQUARE tile, which is a different component
 * from the round `hba-card__disc` and appears in three sizes. H, all three:
 *   /become-a-member types  `w-12 h-12 bg-[#1e3a5f]/10 rounded-lg … mb-4` + 24px navy glyph
 *   /news HBAA rows         `w-10 h-10 bg-[#1e3a5f]/10 rounded-lg … flex-shrink-0` + 18px navy
 *   /news NAHB cards        `w-8  h-8  bg-amber-500/20 rounded-lg … mt-0.5`      + 14px amber-400
 * The 48px form is the base because it is the only one that stacks (the other two
 * sit beside copy in a row and take their margin from the row's gap instead).
 * `--hba-navytint-10` is the seeded token for `#1e3a5f`/10 — one fact, one home. */
.hba-card__iconsq {
  display: flex;
  flex-direction: row;    /* .brxe-container trap: never leave direction to Bricks */
  align-items: center;
  justify-content: center;
  flex: none;             /* H flex-shrink-0 */
  width: 48px;            /* H w-12 */
  height: 48px;
  border-radius: var(--hba-radius-input, 8px); /* H rounded-lg */
  background: var(--hba-navytint-10, rgba(29, 59, 98, 0.102));
  color: var(--hba-navy, #1e3a5f);
}
.hba-card__iconsq .hba-icon,
.hba-card__iconsq [class*="hba-icon--"] {
  width: 24px;   /* H width="24" on the membership-type glyphs */
  height: 24px;
  margin: 0;
  background-color: currentColor;
}
/* Only the stacked form carries live's mb-4; the two row forms are spaced by their
 * parent's gap and must not add to it. */
.hba-card--icon > .hba-card__iconsq { margin: 0 0 16px; } /* H mb-4 */

.hba-newsrow > .hba-card__iconsq { width: 40px; height: 40px; } /* H w-10 h-10 */
.hba-newsrow > .hba-card__iconsq .hba-icon,
.hba-newsrow > .hba-card__iconsq [class*="hba-icon--"] { width: 18px; height: 18px; } /* H width="18" */

.hba-card__iconsq--amber {
  width: 32px;   /* H w-8 */
  height: 32px;
  margin-top: 2px; /* H mt-0.5 */
  background: var(--hba-ambertint-20, rgba(254, 154, 0, 0.200)); /* H bg-amber-500/20 */
  color: var(--hba-amberink, #ffb900);                           /* H text-amber-400 */
}
.hba-card__iconsq--amber .hba-icon,
.hba-card__iconsq--amber [class*="hba-icon--"] { width: 14px; height: 14px; } /* H width="14" */

/* ========================================================= DISC REGISTERS ===
 * `hba-card__disc` now has THREE live registers and the composition reuses one
 * class for all of them, so each is reached through the modifier or the card
 * variant that distinguishes it. Written in ascending specificity so the order in
 * this file is also the order of precedence — the amber one last because it is
 * the most specific case, not because of where it happens to sit.
 *   home benefit cards  `w-20 h-20 bg-[#1e3a5f]/10 … mb-4` + 36px navy   (already above)
 *   /about Core Values  `w-14 h-14 bg-[#1e3a5f]  … mx-auto mb-5` + 26px AMBER-400
 *   /benefits affiliate `w-16 h-16 bg-amber-500/20 … mb-4` + 24px glyph
 * NOTE the Core Values disc is a SOLID navy fill with an AMBER icon — the inverse
 * of home's translucent-navy disc with a navy icon. They look like the same
 * component and they are not. */
.hba-card--center > .hba-card__disc {
  width: 56px;   /* H w-14 */
  height: 56px;
  margin: 0 auto 20px; /* H mx-auto mb-5 */
  background: var(--hba-navy, #1e3a5f);
  color: var(--hba-amberink, #ffb900); /* H text-amber-400 on the glyph */
}
.hba-card--center > .hba-card__disc .hba-icon,
.hba-card--center > .hba-card__disc [class*="hba-icon--"] { width: 26px; height: 26px; } /* H width="26" */
/* `--community` is the one Core Values glyph from the navy-masked library (base
 * .hba-icon paints background-color navy); `--building`/`--award` sit in the
 * currentColor group and inherit the disc's amber. Navy-on-solid-navy made the
 * middle disc render empty — owner caught it on /about. Take the disc's ink. */
.hba-card--center > .hba-card__disc .hba-icon--community { background-color: currentColor; }

.hba-card__disc.hba-card__disc--amber {
  width: 64px;   /* H w-16 */
  height: 64px;
  margin: 0 auto 16px; /* H mb-4 */
  background: var(--hba-ambertint-20, rgba(254, 154, 0, 0.200)); /* H bg-amber-500/20 */
  color: var(--hba-amberink, #ffb900);
}
.hba-card__disc.hba-card__disc--amber .hba-icon,
.hba-card__disc.hba-card__disc--amber [class*="hba-icon--"] { width: 24px; height: 24px; } /* H text-2xl */

/* ⛔ DISC INSIDE A DISC. `.hba-icon--house` / `--national` were authored as
 * STANDALONE 64px amber discs back when the composition gave the affiliate cards
 * a bare glyph and no container. The interior round wraps them in a real
 * `.hba-card__disc--amber`, so the old rule would paint a 64px amber circle inside
 * a 64px amber circle. Reduced to what they are now: a 24px mark. They keep their
 * background-image form (the two are the only glyphs in the library with a baked
 * fill rather than a mask), so only the disc chrome is stripped. */
.hba-card__disc .hba-icon--house,
.hba-card__disc .hba-icon--national {
  width: 24px;
  height: 24px;
  margin: 0;
  border-radius: 0;
  background-color: transparent;
  background-size: 24px 24px;
}

/* =========================================================== CENTRED CARD ===
 * H: /about's Core Values card is `bg-white rounded-xl p-8 shadow-sm border
 * border-gray-100 text-center`; /benefits' affiliate card is `… p-8 flex flex-col
 * items-center text-center`. One modifier covers both; the fills differ and are
 * set by their own variants.
 * ⚠ shadow-sm, NOT shadow-md — the Core Values card is the only p-8 white card on
 * the site at the lower elevation, and it is (0,4,0) here so it beats the
 * shadow-md the `:has(> .hba-card__disc)` rule sets for home's benefit cards. */
.hba-card--center {
  display: flex;
  flex-direction: column;  /* .brxe-container trap: direction restated */
  align-items: center;
  text-align: center;
  width: 100%;
  /* RHYTHM ROUND: PADDING, which this modifier never claimed. Both families that
   * take it are p-8 on live and both were falling through to `.hba-card--icon`'s
   * p-7, so /about's Core Values cards ran 4px tight in every direction. H, read
   * from the two capture files this round:
   *   about.html      `bg-white rounded-xl p-8 shadow-sm border border-gray-100
   *                    text-center`
   *   benefits.html   `bg-[#0d1b2a] rounded-xl p-8 flex flex-col items-center
   *                    text-center`
   * (0,1,0) and later in this file than `.hba-card--icon`, so it wins on source
   * order; the affiliate pair's own `:has(.hba-icon--house)` rule at (0,2,0) says
   * 32 too, so the two agree rather than fight. */
  padding: 32px; /* H p-8 */
}
.hba-card.hba-card--icon.hba-card--center:not(.hba-card--dark) {
  box-shadow: var(--hba-shadow-field, rgba(0, 0, 0, 0.05) 0px 1px 2px 0px); /* H shadow-sm */
}
/* H `text-xl mb-3` and `text-[#374151] text-sm leading-relaxed`. The paragraph ink
 * is inkStrong, not the light-field inkBody — the same one-channel distinction the
 * timeline block above calls out. Scoped to the light card so the /benefits dark
 * pair keeps its white/70 (set at the top of this file). */
.hba-card--center:not(.hba-card--dark) > .hba-heading { margin-bottom: 12px; }
.hba-card--center:not(.hba-card--dark) > .hba-body {
  font-size: 14px;
  line-height: 22.75px;
  color: var(--hba-inkstrong, #374151);
}
/* H `text-xl mb-3` then `text-sm leading-relaxed mb-4` on the dark affiliate pair.
 * RHYTHM ROUND: the paragraph's `mb-4` is now carried by the base register's
 * `.hba-card > .hba-cta { margin-top: 16px }` instead — the "Explore …" span is
 * always the last child of this card, so the measured 16px lands in exactly the
 * same place. Stating it in both would paint 32: a Bricks card is a flex column
 * and adjoining margins there do not collapse. */
.hba-card--center.hba-card--dark > .hba-heading { margin-bottom: 12px; }
.hba-card--center.hba-card--dark > .hba-body {
  font-size: 14px;
  line-height: 22.75px;
}

/* ================================================ 1. EVENT CARDS (/events) ===
 * H (Events.tsx:129-162), verbatim:
 *   card  `bg-white rounded-xl overflow-hidden shadow-md border border-gray-100
 *          hover:shadow-xl transition-all duration-300 group`
 *   band  `bg-[#1e3a5f] p-5`
 *   row   `flex items-center justify-between mb-2`
 *   chip  the standard .hba-chip register
 *   date  `text-white/60 text-xs font-['Source_Sans_3']`
 *   title `font-['Oswald'] font-bold text-white text-xl leading-tight`
 *   body  `p-5`
 *   desc  `text-gray-600 font-['Source_Sans_3'] text-sm leading-relaxed mb-4`
 *   metas `space-y-1.5 mb-4`, each `flex items-center gap-2 text-gray-500 text-sm`
 *         with a 13px lucide clock / map-pin in `text-amber-500`
 *   link  `flex items-center gap-1.5 text-[#1e3a5f] hover:text-amber-500
 *          font-['Oswald'] font-semibold text-sm group-hover:gap-2`
 * The link is exactly hero.css's --link register already (navy -> amber-500, 14px
 * Oswald 600, gap 6 -> 8 on card hover), so nothing is restated for it.
 *
 * The card's padding is ZERO: the band and the body each carry their own p-5 and
 * the card only clips them. That is why `overflow: hidden` is not decoration —
 * without it the navy band's square corners sit outside the 12px radius. */
.hba-eventcard {
  padding: 0;
  overflow: hidden;
}
.hba-eventcard__band {
  display: flex;
  flex-direction: column;  /* .brxe-container trap */
  align-items: stretch;
  width: 100%;
  padding: 20px;           /* H p-5 */
  background: var(--hba-navy, #1e3a5f);
}
.hba-eventcard__bandrow {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 12px;
  margin-bottom: 8px;      /* H mb-2 */
}
/* H `text-white/60 text-xs font-['Source_Sans_3']`. This rides on .hba-body, so the
 * declaration order matters: body.css's field rules are (0,1,0) and so is this, but
 * this file is later. */
.hba-eventcard__date {
  font-family: var(--hba-font-text);
  font-size: 12px;
  line-height: 16px;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--hba-white-white60, rgba(255, 255, 255, 0.600));
  margin: 0;
}
/* H `font-bold text-white text-xl leading-tight` = 20 x 1.25. Not the h3 default. */
.hba-eventcard__title {
  font-size: 20px;
  line-height: 25px;   /* H leading-tight */
  font-weight: 700;
  color: var(--hba-white, #ffffff);
  margin: 0;
}
.hba-eventcard__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  padding: 20px;       /* H p-5 */
  text-align: left;
}
/* H `mb-4` between the blocks; the two meta rows are `space-y-1.5` inside their own
 * container, so the tighter rule has to win — (0,2,0) over (0,1,0), and it is
 * second. */
.hba-eventcard__body > * + * { margin-top: 16px; }
.hba-eventcard__body > .hba-body { font-size: 14px; line-height: 22.75px; }
.hba-eventcard__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
}
.hba-eventcard__meta > .hba-meta + .hba-meta { margin-top: 6px; } /* H space-y-1.5 */

/* The leading glyph on a meta line. TWO SIZES, both measured, and they differ by
 * one pixel — read twice rather than unified:
 *   /events + /calendar list rows   12px, `gap-1.5`  (Events.tsx:  the flex-wrap row)
 *   /events featured card metas     13px, `gap-2`    (Events.tsx:150/154)
 * Ink is `text-amber-500` = amberFILL on both, against a #6a7282 line — so the
 * glyph does NOT ride currentColor here and the colour is stated. */
.hba-meta__icon {
  width: 12px;
  height: 12px;
  margin-right: 6px;      /* H gap-1.5 */
  vertical-align: -1px;
  background-color: var(--hba-amberfill, #fe9a00);
}
.hba-eventcard__meta .hba-meta__icon {
  width: 13px;
  height: 13px;
  margin-right: 8px;      /* H gap-2 */
}

/* ================================================ 2. NEWS CARDS (/news) ===
 * H (News.tsx:110-135), verbatim:
 *   card  `bg-[#f5f7fa] rounded-xl overflow-hidden border border-gray-100
 *          hover:border-[#1e3a5f]/30 hover:shadow-lg transition-all duration-300`
 *   bar   `bg-[#1e3a5f] h-2`                       <- 8px, flush, full width
 *   body  `p-6`
 *   row   `flex items-center justify-between mb-3`
 *   date  `text-gray-400 text-xs font-['Source_Sans_3']`
 *   h3    `font-bold text-[#0d1b2a] text-xl leading-snug mb-3
 *          group-hover:text-[#1e3a5f]`
 *   p     `text-gray-600 text-sm leading-relaxed`
 *   link  `mt-4 inline-flex items-center gap-2 text-amber-600 hover:text-amber-500
 *          font-['Source_Sans_3'] font-semibold text-sm` + 14px download glyph
 * NO shadow at rest. The hover pair (navy/30 border + shadow-lg) is already
 * carried: the border by the `!important` hover rule above, the elevation by
 * motion.css's normalised lift, which IS shadow-lg. Nothing to add for either. */
.hba-card--topbar {
  background: var(--hba-offwhite, #f5f7fa);
  padding: 0;          /* the body carries p-6; the card only clips */
  overflow: hidden;
  box-shadow: none;    /* H: no rest shadow on this family */
}
.hba-card__topbar {
  display: block;
  width: 100%;
  height: 8px;         /* H h-2 */
  background: var(--hba-navy, #1e3a5f);
  overflow: hidden;    /* it carries a visually-hidden label so Bricks renders it */
}
.hba-card__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  padding: 24px;       /* H p-6 */
  text-align: left;
}
.hba-card__metarow {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 12px;
  margin-bottom: 12px; /* H mb-3 */
}
/* ⚠ THE THIRD KICKER REGISTER, now reachable. body.css's .hba-kicker note records
 * that one class covers three live registers and authors the /home one (Oswald 600,
 * 12/16, 0.6px tracking, amber). This is register (c): a grey Source Sans caption.
 * It is not a swap — it is the same class in a different component, and the
 * component is now nameable, which is exactly what that note said was missing. */
.hba-card__metarow .hba-kicker {
  font-family: var(--hba-font-text);
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--hba-inkfaint, #99a1af); /* H text-gray-400 */
}
.hba-card__body > .hba-heading {
  font-size: 20px;       /* H text-xl */
  line-height: 27.5px;   /* H leading-snug */
  font-weight: 700;
  margin-bottom: 12px;   /* H mb-3 */
  transition: color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-card--topbar:hover .hba-card__body > .hba-heading { color: var(--hba-navy, #1e3a5f); } /* H group-hover */
.hba-card__body > .hba-body { font-size: 14px; line-height: 22.75px; }
/* H `text-amber-600 hover:text-amber-500 font-['Source_Sans_3'] font-semibold`.
 * amber-600 is a real seeded token — `flyerLinkInk` #e17100 — and this link is
 * literally what tokens.json named it after. (0,3,0) so it beats hero.css's
 * `.hba-cta.hba-cta--link` (0,2,0), which would otherwise leave it Oswald + navy. */
.hba-card__body .hba-cta.hba-cta--link {
  font-family: var(--hba-font-text);
  gap: 8px;                                       /* H gap-2 */
  margin-top: 16px;                               /* H mt-4 */
  color: var(--hba-flyerlinkink, #e17100);
}
.hba-card__body .hba-cta.hba-cta--link:hover { color: var(--hba-amberfill, #fe9a00); }
.hba-card__body .hba-cta.hba-cta--link .hba-cta__icon { width: 14px; height: 14px; }

/* ========================== 3. HBAA NEWS STACK + NAHB GRID (/news) ===
 * ⛔ LIVE'S HBAA SECTION IS NOT A GRID. H (News.tsx:167) is `space-y-4` holding
 * FULL-WIDTH white row cards; this build shipped it as a 3-column text grid with
 * no cards, no icon tiles and no external-link affordance.
 *   row   `flex items-start gap-4 p-5 bg-white rounded-xl border border-gray-100
 *          hover:border-[#1e3a5f]/30 hover:shadow-md transition-all duration-200`
 *   tile  the 40px `hba-card__iconsq` above
 *   copy  `flex-1 min-w-0`
 *   h3    `font-semibold text-[#0d1b2a] text-lg leading-snug group-hover:text-[#1e3a5f]`
 *   p     `text-gray-500 text-sm mt-1 leading-relaxed`
 *   ext   16px external-link, `text-gray-300 group-hover:text-amber-500
 *          flex-shrink-0 mt-1` */
.hba-newsstack {
  display: flex;
  flex-direction: column;
  gap: 16px;   /* H space-y-4 */
  width: 100%;
}
.hba-newsrow {
  display: flex;
  flex-direction: row;   /* .brxe-container trap */
  align-items: flex-start;
  width: 100%;
  gap: 16px;             /* H gap-4 */
  padding: 20px;         /* H p-5 */
  background: var(--hba-white, #ffffff);
  border: 1px solid var(--hba-hairline, #f3f4f6); /* H border-gray-100 — stated because
                          * the LINKED rows are not $card()s and carry no Bricks border */
  border-radius: var(--hba-radius-card, 12px);
  box-shadow: none;
  text-align: left;
  text-decoration: none;
}
.hba-newsrow__copy {
  flex: 1 1 auto;
  min-width: 0;   /* H min-w-0 — without it a long title stops the row shrinking */
}
.hba-newsrow__copy > .hba-heading {
  font-size: 18px;       /* H text-lg */
  line-height: 24.75px;  /* H leading-snug */
  font-weight: 600;      /* H font-semibold, not the h3 default 700 */
  transition: color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-newsrow:hover .hba-newsrow__copy > .hba-heading { color: var(--hba-navy, #1e3a5f); }
.hba-newsrow__copy > .hba-body {
  font-size: 14px;
  line-height: 22.75px;  /* H leading-relaxed */
  color: var(--hba-inkmuted, #6a7282); /* H text-gray-500, not the field's inkBody */
  margin-top: 4px;       /* H mt-1 */
}
.hba-newsrow__ext {
  width: 16px;
  height: 16px;
  margin-top: 4px;       /* H mt-1 */
  overflow: hidden;      /* it carries a visually-hidden label */
  /* H text-gray-300. No seeded token carries gray-300 — same literal, same reason,
   * as the event-row arrow above (P-5: no unresolvable vars). */
  background-color: #d1d5db;
  transition: background-color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-newsrow:hover .hba-newsrow__ext { background-color: var(--hba-amberfill, #fe9a00); } /* H group-hover:text-amber-500 */

/* NAHB grid. H (News.tsx:217-232): the card is the `hba-card--dark` register plus
 * `flex items-start gap-3`, an amber icon square, and a "Read More" affordance
 * that is a SPAN (the whole card is the anchor).
 *   h3         `font-semibold text-white text-base leading-snug group-hover:text-amber-400`
 *   read-more  `mt-2 text-amber-400 text-xs font-['Oswald'] flex items-center gap-1
 *               group-hover:gap-2` + 12px arrow   <- weight 400: NO font-semibold class */
.hba-newscard {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  width: 100%;
  gap: 12px;          /* H gap-3 */
  /* RHYTHM ROUND: the /news NAHB grid is the p-5 half of the `--dark` pair the
   * base note used to carry as an unsplittable ⚠. H (News.tsx:217): `bg-white/5 …
   * rounded-xl p-5 … flex items-start gap-3`. `.hba-card--dark` now holds home's
   * p-6, so this restates its own 20 — (0,1,0), later in the file, source order. */
  padding: 20px;      /* H p-5 */
  text-align: left;
  text-decoration: none;
}
.hba-newscard__copy { flex: 1 1 auto; min-width: 0; }
.hba-newscard__copy > .hba-heading {
  font-size: 16px;      /* H text-base */
  line-height: 22px;    /* H leading-snug */
  font-weight: 600;
  transition: color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-newscard:hover .hba-newscard__copy > .hba-heading { color: var(--hba-amberink, #ffb900); }
/* (0,3,0) — hero.css's `.hba-cta.hba-cta--link` is (0,2,0) and would otherwise
 * leave this 14px semibold with a 6px gap. */
.hba-newscard .hba-cta.hba-cta--link {
  font-size: 12px;      /* H text-xs */
  line-height: 16px;
  font-weight: 400;     /* H: no weight class on this one */
  gap: 4px;             /* H gap-1 */
  margin-top: 8px;      /* H mt-2 */
  color: var(--hba-amberink, #ffb900);
}
.hba-newscard:hover .hba-cta.hba-cta--link { gap: 8px; } /* H group-hover:gap-2 */
.hba-newscard .hba-cta.hba-cta--link .hba-cta__arrow { width: 12px; height: 12px; } /* H width="12" */

/* ⛔ THE BRICKS HAIRLINE IS PAINTING A LIGHT BORDER ON EVERY DARK CARD.
 * `$card()` sets a per-element `border: 1px solid #f3f4f6` at (1,0,0), and
 * `.hba-card--dark`'s white/10 border-colour is (0,1,0) — so it never applied, and
 * every dark card on the site draws a near-white hairline on charcoal. VISIBLE IN
 * THE EVIDENCE, not inferred: the NAHB cards in the owner's Generated /news
 * capture are outlined boxes where the Live capture shows barely-there edges.
 * Same (1,0,0) fact this file already proved and used twice (the affiliate pair's
 * `border: 0` and the card hover's border-colour); this is the third use, scoped
 * to one property on one variant. Live is `border border-white/10
 * hover:border-amber-400/40`, and both halves need it because the hover rule below
 * carries `!important` too. */
.hba-card--dark { border-color: var(--hba-white-white10, rgba(255, 255, 255, 0.102)) !important; }
.hba-card--dark:hover { border-color: rgba(255, 185, 0, 0.4) !important; } /* H amber-400/40 */

/* ======================================================== 5. ABOUT PAGE ===
 * STAT CARDS. H (About.tsx:137-154) — the four cards live in the STORY split's
 * right column, `grid grid-cols-2 gap-5`, two-up at every width:
 *   card   `bg-[#f5f7fa] rounded-xl p-6 border border-gray-100`   <- no shadow
 *   value  `font-['Oswald'] font-bold text-[#0d1b2a] text-2xl leading-tight mb-1`
 *   label  `font-['Source_Sans_3'] font-semibold text-[#374151] text-sm`
 *   sub    `font-['Source_Sans_3'] text-gray-400 text-xs mt-0.5`
 * These are the same values the older `.hba-stats`/`.hba-stat` block above carries;
 * the composition renamed the pair to `hba-statgrid`/`hba-statcard` so that
 * `.hba-stats` can keep home's navy band without the two fighting over one class.
 * They are restated rather than aliased — an alias would tie the /about card and
 * the home band back together, which is the collision the rename removed. */
.hba-statgrid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;    /* H gap-5 */
  width: 100%;  /* .brxe-container trap, inside a 580px split column */
}
.hba-statcard {
  background: var(--hba-offwhite, #f5f7fa);
  border-radius: var(--hba-radius-card, 12px);
  padding: 24px;      /* H p-6 */
  box-shadow: none;   /* H: no shadow on these */
  text-align: left;
}
.hba-statcard__value {
  font-family: var(--hba-font-display);
  font-size: 24px;
  line-height: 30px;  /* H leading-tight */
  font-weight: 700;
  color: var(--hba-charcoal, #0d1b2a);
  margin: 0 0 4px;    /* H mb-1 */
}
.hba-statcard__label {
  font-family: var(--hba-font-text);
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  color: var(--hba-inkstrong, #374151);
  margin: 0;
}
.hba-statcard__sub {
  font-family: var(--hba-font-text);
  font-size: 12px;
  line-height: 16px;
  font-weight: 400;
  color: var(--hba-inkfaint, #99a1af); /* H text-gray-400 */
  margin: 2px 0 0;    /* H mt-0.5 */
}

/* The white HBA mark above the federation heading. H (About.tsx:242): wrapper
 * `flex justify-center mb-5`, image `h-16 w-auto object-contain`.
 *
 * ⚠ THIS IS A MODIFIER, NOT A STANDALONE. The composition carries it alongside
 * `hba-about__logo` deliberately: styling `hba-fed__logo` on its own left the image
 * with no height rule at all and a 300x144 source blew up to 1024x490 and swallowed
 * the section. The base gives it 56px and the 20px bottom margin (H mb-5, the same
 * value); this modifier carries ONLY the delta — 64px — plus the centring the live
 * `flex justify-center` wrapper provides and the composition does not emit. Both
 * rules are (0,1,0) and this file is where both live, so source order decides and
 * this one is later. */
.hba-fed__logo {
  height: 64px;        /* H h-16, over the base's 56px */
  margin-inline: auto; /* H wrapper `flex justify-center` */
}

/* FEDERATION PARTNER CARDS. H (About.tsx:272-288), verbatim:
 *   card   `group bg-[#1e3a5f] hover:bg-[#264d7a] rounded-xl p-7 transition-colors
 *           border border-white/10`
 *   row    `flex items-center justify-between mb-3`
 *   label  `font-['Oswald'] font-bold text-amber-400 text-2xl`
 *   ext    16px external-link `text-white/30 group-hover:text-amber-400`
 *   name   `font-['Oswald'] font-semibold text-white text-base mb-2`
 *   blurb  `font-['Source_Sans_3'] text-white/60 text-sm leading-relaxed`
 * ⚠ UNRECORDED LITERAL: `#264d7a`, the hover fill, is in neither tokens.json's
 * palette nor its component ledger. Reported to the TL for entry at source, the
 * same way `#1a3356`/`#0f2240` were.
 * These cards sit ON the charcoal field and are one step LIGHTER than it — that
 * navy fill is the entire reason they read as cards, and it is why the previous
 * `hba-card--dark` (a 5%-white wash) made them invisible. */
.hba-card--navy {
  display: block;
  width: 100%;
  background: var(--hba-navy, #1e3a5f);
  border: 1px solid var(--hba-white-white10, rgba(255, 255, 255, 0.102));
  border-radius: var(--hba-radius-card, 12px);
  padding: 28px;      /* H p-7 */
  box-shadow: none;
  text-align: left;
  text-decoration: none;
  transition: background-color var(--hba-duration-slow, 300ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-card--navy:hover { background: #264d7a; } /* H hover:bg-[#264d7a] — see the literal note above */
.hba-card__labelrow {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 12px;
  margin-bottom: 12px; /* H mb-3 */
}
.hba-card__label {
  font-family: var(--hba-font-display);
  font-size: 24px;     /* H text-2xl */
  line-height: 32px;
  font-weight: 700;
  letter-spacing: normal;
  color: var(--hba-amberink, #ffb900); /* H text-amber-400 */
  margin: 0;
}
.hba-card__ext {
  width: 16px;
  height: 16px;
  overflow: hidden;    /* carries a visually-hidden label */
  background-color: var(--hba-white-white30, rgba(255, 255, 255, 0.298)); /* H text-white/30 */
  transition: background-color var(--hba-duration-base, 200ms) var(--hba-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
}
.hba-card--navy:hover .hba-card__ext { background-color: var(--hba-amberink, #ffb900); } /* H group-hover:text-amber-400 */
.hba-card--navy > .hba-heading {
  font-size: 16px;     /* H text-base */
  line-height: 24px;
  font-weight: 600;    /* H font-semibold */
  color: var(--hba-white, #ffffff);
  margin: 0 0 8px;     /* H mb-2 */
}
.hba-card--navy > .hba-body {
  font-size: 14px;
  line-height: 22.75px;  /* H leading-relaxed */
  color: var(--hba-white-white60, rgba(255, 255, 255, 0.600)); /* H text-white/60 */
}

/* ==================================================== 6. JOIN PAGE ===
 * MEMBERSHIP TYPE CARDS. H (BecomeMember.tsx, the types grid), verbatim:
 *   card  `bg-white rounded-xl p-7 shadow-md border border-gray-100
 *          hover:border-[#1e3a5f]/30 hover:shadow-xl transition-all duration-300
 *          flex flex-col`
 *   tile  the 48px `hba-card__iconsq` above
 *   h3    `font-bold text-[#0d1b2a] text-xl mb-3`
 *   p     `text-gray-600 text-sm mb-5 leading-relaxed`
 *   link  wrapped in `mt-auto`, `flex items-center gap-2 text-[#1e3a5f]
 *          hover:text-amber-500 font-['Source_Sans_3'] font-semibold text-sm`
 * The fill, radius, padding and shadow all come from the base card now. What is
 * left is the COLUMN and live's `mt-auto`, which is what keeps the download links
 * on one line across three cards of unequal copy — the composition emits the link
 * as a bare sibling, so the auto margin rides the first <a> instead of a wrapper.
 * Note the link face is SOURCE SANS here, not the Oswald every other CTA uses. */
.hba-card--icon:has(> .hba-card__iconsq) {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
}
.hba-card--icon:has(> .hba-card__iconsq) > .hba-heading { margin-bottom: 12px; } /* H mb-3 */
.hba-card--icon:has(> .hba-card__iconsq) > .hba-body {
  font-size: 14px;
  line-height: 22.75px;
  margin-bottom: 20px;  /* H mb-5 */
}
.hba-card--icon:has(> .hba-card__iconsq) > .hba-cta:first-of-type { margin-top: auto; } /* H mt-auto */
.hba-card--icon:has(> .hba-card__iconsq) > .hba-cta + .hba-cta { margin-top: 12px; }    /* H space-y-3 */
.hba-card--icon:has(> .hba-card__iconsq) .hba-cta.hba-cta--link {
  font-family: var(--hba-font-text);
  gap: 8px;   /* H gap-2 */
}
.hba-card--icon:has(> .hba-card__iconsq) .hba-cta.hba-cta--link .hba-cta__icon { width: 15px; height: 15px; } /* H width="15" */

/* ⛔ CF7 FORM PLUMBING — wpautop. body.css handles a wrapped CELL; this handles a
 * wrapped ROW. `wpcf7_autop` runs over the whole form body, so any of the
 * top-level blocks the importer emits can arrive inside a <p> that nobody wrote,
 * and the stray <p> both adds a margin and (for a row) becomes the flex item in
 * its cell's place. `display: contents` removes the box without removing the
 * content — and it is scoped by :has() to the wrappers only, because two real <p>
 * elements in this form MUST keep their boxes: the placeholder copy and
 * .form__confirmation. A blanket `form p { display: contents }` would erase both.
 * The <br> rule is the same defect's other half: wpautop turns the newlines
 * between the importer's blocks into line breaks, which open gaps the measured
 * rhythm does not have. Both are inert if wpautop leaves the markup alone. */
.hba-formwrap form > p:has(> .hba-formrow),
.hba-formwrap form > p:has(> .hba-formsubmit),
.hba-formwrap form > p:has(> .field),
.hba-contact__form form > p:has(> .field) { display: contents; }
/* ⛔ AND THE SAME DEFECT ONE LEVEL DOWN, WHICH THE RULE ABOVE CANNOT SEE. Measured
 * 2026-08-21: wpautop also wraps the submit control INSIDE `.hba-formsubmit`, so
 * the shape is `.hba-formsubmit > p > input`, not `p > .hba-formsubmit`. That <p>
 * measured h=81 with an 18px bottom margin around a 48px control — the whole block
 * 115 where live is 76 (a 48px button + 12 + a 16px confirmation line). The height
 * was never the button: it was a paragraph box nobody wrote, and its line-box
 * strut, sitting between the two.
 * ⛔ `:not(.form__confirmation)` IS LOAD-BEARING, exactly as on the rule above:
 * the confirmation line is a REAL <p> inside this block and must keep its box, or
 * its 12px margin and 12/16 register go with it. Removing the wpautop box also
 * puts the ::after arrow back on the control's own 48px band — it had been
 * centring against the 81px paragraph. */
.hba-formsubmit > p:not(.form__confirmation) { display: contents; }
/* ⛔ EVERY <br> IN THESE FORMS, not just the top-level ones. Proven on a harness
 * that reproduces the emitted DOM: wpautop's breaks land INSIDE the cell, between
 * the label and the control, where a `> br` rule cannot reach them — and each one
 * opens a ~20px empty line the measured rhythm does not have. Live's form markup
 * contains no <br> at all, so any that appears here came from wpautop and is
 * unwanted by definition. Scoped to the two form panels; nothing else on the site
 * is touched. */
.hba-formwrap form br,
.hba-contact__form form br { display: none; }

/* A SAFETY NET, NOT A REGISTER — and deliberately written to lose. The paired-row
 * layout only reads as pairs if the label sits above a control that fills its cell;
 * a UA-default inline label beside a ~177px input turns a 346px half into a
 * one-line row and the whole pairing is defeated. The live-facing build already
 * gets this from the form stack's own stylesheet (visible in the owner's Generated
 * /become-a-member capture: labels on their own line, inputs full width), so these
 * three declarations should be no-ops there.
 * They are carried anyway because the failure mode is silent and total, and they
 * are wrapped in `:where()` — zero added specificity — so ANY rule the form stack
 * ships wins outright wherever the two disagree. Scoped to row cells only, so the
 * unrowed fields and /contact keep whatever they have today. */
.hba-formrow__half :where(label),
.hba-formrow__half :where(.wpcf7-form-control-wrap) { display: block; }
.hba-formrow__half :where(input, select, textarea) { width: 100%; }

/* The turnstile slot. NOT an hba-* class, but it renders and the composition asked
 * for it by name. (2026-09-15 live-placeholder hotfix: the parent no longer
 * carries `.hba-placeholder` and there is no placeholder sentence above the slot
 * — the wrapper holds the slot alone, and the margin-top separates the widget
 * from the field above it.) NO live counterpart exists — live has no bot
 * protection at all — so nothing here is measured, and it is deliberately the
 * smallest rule that keeps the slot from collapsing to zero height when the
 * shortcode is unregistered and renders nothing. */
.form__turnstile-slot { display: block; margin-top: 8px; min-height: 0; }

/* THE FORM HEAD. H (BecomeMember.tsx:257): `flex items-center gap-3 mb-6` holding a
 * 24px lucide user-plus in `text-[#1e3a5f]` and an h2 `font-bold text-[#0d1b2a]
 * text-2xl` — 24/32, where body.css's h2 register is 30/36. It sits OUTSIDE the
 * form panel; see the .hba-formwrap split above for why that matters. */
.hba-formwrap__head {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 100%;
  gap: 12px;           /* H gap-3 */
  margin-bottom: 24px; /* H mb-6 */
}
.hba-formwrap__head .hba-heading {
  font-size: 24px;     /* H text-2xl */
  line-height: 32px;
  margin: 0;
}
.hba-formwrap__icon {
  width: 24px;
  height: 24px;
  background-color: var(--hba-navy, #1e3a5f); /* H text-[#1e3a5f] */
}

/* ⛔ SUBMIT: FULL-WIDTH NAVY, AND THE HEIGHT IS MEASURED BECAUSE THE CLASSES
 * CONTRADICT EACH OTHER. H is `h-9 px-4 w-full bg-[#1e3a5f] hover:bg-[#162d4a]
 * text-white font-['Oswald'] font-semibold tracking-wider text-base py-6 rounded
 * active:scale-[0.98]` — `h-9` (36px) and `py-6` (24px top AND bottom) cannot both
 * hold, so the painted box is whatever the browser resolves. Pixel-probed off the
 * owner's Live /become-a-member capture rather than reasoned about: the navy run at
 * x=1100 spans y 1594..1641 = 48px tall and 899px wide. Scale is 1:1, proven on the
 * same capture by the amber PDF button measuring exactly its 44px `px-5 py-3` box.
 * So: 24px of vertical padding around a 16/24 label, full width.
 * The fill pair (#1e3a5f -> #162d4a) is hero.css's --navy and is already correct. */
.hba-formsubmit {
  position: relative;   /* the arrow's containing block — see the ::after below */
  width: 100%;
  margin-top: 24px;     /* H mt-6 */
}
/* ⛔ THE ARROW CANNOT SIT WHERE LIVE PUTS IT, AND THE REASON IS STRUCTURAL.
 * CF7's [submit] renders `<input type="submit">`, a REPLACED element: it hosts no
 * ::before/::after and has no child box to flex against. Live uses a real <button>
 * with an inner `<span class="flex items-center gap-2">SUBMIT APPLICATION →</span>`,
 * so the glyph rides immediately after the label and the pair is centred together.
 *
 * Reproducing that from CSS would need the label's rendered WIDTH, which is a
 * content fact CSS cannot read — the only way to place it inline would be to
 * hard-code a pixel offset measured off the string "SUBMIT APPLICATION", which
 * would be a fabricated value AND would be wrong for /contact's "SEND MESSAGE" on
 * the same class. So the glyph is drawn on the WRAPPER (per the TL's ruling) and
 * pinned to the button's right edge instead of trailing the label.
 * ⚠ CARRIED DIFFERENCE, deliberate and reported: position only — size, ink and
 * artwork are live's. Closing it needs CF7's control swapped for a <button>, which
 * the composition agent has already raised as a TL ruling rather than a CSS
 * workaround.
 *
 * `pointer-events: none` is not cosmetic: without it the overlay eats clicks on the
 * one control that submits the form. The 48px height is the button's own measured
 * height, so `mask-position: center` self-centres the 16px glyph rather than
 * needing an offset that a wrapped label would falsify. */
.hba-formsubmit::after {
  content: "";
  position: absolute;
  top: 0;
  right: 20px;
  width: 16px;    /* H: the submit glyph is [&_svg]:size-4 = 16px */
  height: 48px;   /* the measured button height; centres the glyph vertically */
  pointer-events: none;
  background-color: var(--hba-white, #ffffff); /* H text-white, same ink as the label */
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
}
.hba-formsubmit .hba-cta {
  width: 100%;
  /* ⛔ `display: flex`, NOT THE BASE'S inline-flex, AND THE 33px IT SAVES WAS
   * INVISIBLE IN EVERY RULE. Measured 2026-08-21: the control's own box is exactly
   * 48px — min-height, padding and border all resolve correctly — but as an
   * INLINE-level box it sits in a line box, and the wrapper's 15px/25.5px strut
   * plus baseline descent stretched that line to 81. The button was never wrong;
   * the line around it was. Block-level here, so no line box forms at all. */
  display: flex;
  /* ⛔ `border: 0` IS NOT TIDYING. [submit] renders an <input>, and a UA submit
   * button carries a 2px border that .hba-cta never clears — so the control
   * measured 52px against live's 48 even with min-height set correctly. Found by
   * measuring the rendered button, not by reading the rule. The focus ring is
   * unaffected: body.css draws it with outline + box-shadow, not the border. */
  border: 0;
  min-height: 48px;       /* measured, see above */
  padding: 12px 16px;     /* H px-4; the block padding is carried by min-height */
  font-size: 16px;        /* H text-base */
  line-height: 24px;
  letter-spacing: 0.8px;  /* H tracking-wider at 16px, not the base's 0.7 at 14px */
  text-align: center;
}
/* CF7's AJAX spinner. Not an hba-* class and it has NO live counterpart — live's
 * form is a plain POST with no loading affordance — but CF7 emits it as a sibling
 * of the submit control and its own stylesheet gives it `display: inline-block`
 * with `margin: 0 24px`, so beside a full-width button it wraps to a line of its
 * own and adds ~24px to a block live measures at 76. Taken out of flow rather than
 * hidden: `visibility` is CF7's to toggle during a submit and it still works from
 * an absolutely-positioned box, where `display: none` would kill the affordance
 * outright. Scoped to this component only. Reported — if body.css takes CF7's
 * chrome wholesale (as it is doing for `.wpcf7-response-output`), this belongs
 * with it. */
.hba-formsubmit .wpcf7-spinner {
  position: absolute;
  right: 0;
  top: 12px;
  margin: 0;
}
/* H: `text-gray-400 text-xs font-['Source_Sans_3'] text-center mt-3`, INSIDE the
 * form directly under the button. Not an hba-* class, so it is not counted by paint
 * row P-1 — carried anyway because it is live-facing copy that would otherwise
 * inherit the form's default ink at full size. */
.hba-formsubmit .form__confirmation {
  font-family: var(--hba-font-text);
  font-size: 12px;
  line-height: 16px;
  color: var(--hba-inkfaint, #99a1af);
  text-align: center;
  margin: 12px 0 0;  /* H mt-3 */
}

/* `--block`: the full-width CTA. Used by both PDF buttons and the submit, so it
 * carries WIDTH ONLY — the two have different type registers and the submit's is
 * set above. site.css's `.hba-cta { width: fit-content }` is (0,1,0) in an earlier
 * file, so (0,2,0) here is more than enough and leaves room for hero.css to take
 * the variant over later if the CTA family is consolidated there. */
.hba-cta.hba-cta--block {
  width: 100%;
  justify-content: center;
}
/* ⛔ THE TWO PDF BUTTONS MUST MATCH EACH OTHER, AND THEY DID NOT. Live gives both
 * `px-5 py-3` — a 44px box — but only three CTA variants carry hero.css's
 * `padding: 12px 28px`, and `--navy` is not one of them. So BUILDER (--primary)
 * painted 44px and ASSOCIATE (--navy) fell back to site.css's base 8px/18px and
 * painted 36px: two stacked full-width buttons, 8px different in height, on the
 * same panel. Measured on the rendered pair, not inferred. Scoped to the option
 * panel's action row so it cannot reach the CF7 submit (48px) or any other --navy.
 * (0,3,0) clears hero.css's (0,2,0) variant padding. */
.hba-optionblock .hba-actions .hba-cta {
  padding: 12px 20px; /* H px-5 py-3 = a 44px box on a 14/20 label */
}
/* `--static`: a CTA-shaped <span> inside a card that is itself the anchor (nesting
 * <a> in <a> is invalid, so live uses a span and so does the composition). It is
 * not interactive on its own; the cursor must come from the card, not from the
 * span, or the affordance reads as a separate target. */
.hba-cta.hba-cta--static { cursor: inherit; }

/* ================================== 7. SECTION HEADS ON INTERIOR GROUNDS ===
 * VERIFIED, NOT REWRITTEN. The composition now puts `.hba-sectionhead` on /events,
 * /news x3, /calendar and /benefits as well as home's three. Checked selector by
 * selector against what those grounds need:
 *   - eyebrow ink   body.css's field rules are (0,1,0) and the sectionhead rules
 *                   above set only margins, so amberInk-on-dark / amberFill-on-light
 *                   still resolves per field. Correct on /news' charcoal NATIONAL
 *                   NEWS and its offWhite STATE NEWS in the same document.
 *   - heading ink   `:where(.hba-field-charcoal, .hba-field-navy) .hba-heading`
 *                   is a descendant selector, so wrapping the h2 in the head does
 *                   not break it.
 *   - centring      body.css centres DIRECT children of a section inner; a wrapped
 *                   head is not one, so the left alignment holds without an
 *                   exception. `.hba-sectionhead > *` pins it anyway.
 *   - action ink    hero.css gives `--link` navy on light and amberInk on dark,
 *                   which is exactly live's "Visit HBAA" / "Visit NAHB" pair.
 * Nothing needed changing. TWO CARRIED DIFFERENCES, both reported rather than
 * guessed at: live's /news heads are `mb-8` (32px) where this class carries live's
 * home register `mb-10` (40px), and they are `flex … justify-between` at EVERY
 * width where this class stacks below 1024. One class, two live registers, and no
 * structural difference between the two to select on.
 *
 * What IS new is the inline heading glyph. H (Events.tsx:123): the "Featured
 * Events" h2 is `flex items-center gap-3` with a 24px lucide star in
 * `text-amber-500` before the words. (/news' NAHB h2 carries the same flex classes
 * and NO icon — the composition's own note flags that as vestigial; nothing here
 * fabricates one.) */
.hba-heading__icon {
  width: 24px;   /* H width="24" */
  height: 24px;
  margin-right: 12px; /* H gap-3 */
  vertical-align: -3px;
  background-color: var(--hba-amberfill, #fe9a00); /* H text-amber-500 */
}

/* ================================ 8. LINK INK ON DARK CARD GROUNDS ===
 * ⛔ THE DEFECT, AND IT IS A FIELD-vs-GROUND MISMATCH, NOT A MISSING RULE.
 * hero.css gives `.hba-cta--link` navy #1e3a5f by default and switches it to
 * amberInk only via `.hba-field-charcoal`/`.hba-field-navy`. /benefits' "State &
 * National Benefits" section is on a WHITE field with DARK CARDS inside it, so the
 * field rule never fired and "Explore HBAA Benefits" painted navy on charcoal —
 * #1e3a5f on #0d1b2a, which is the dim grey-blue the owner flagged. Live is
 * `text-amber-400` (H Benefits.tsx:149), and it does NOT change on hover: the live
 * gesture there is `group-hover:gap-2.5`, the gap, not the ink.
 *
 * The ink is a property of the CARD's ground, so it is scoped to the card and not
 * to the field. Specificity, counted rather than assumed — hero.css loads AFTER
 * this file, so these have to out-rank it, not merely match it:
 *   hero  .hba-cta.hba-cta--link                            (0,2,0)
 *   hero  .hba-cta.hba-cta--link:hover                      (0,3,0)
 *   hero  .hba-field-charcoal .hba-cta.hba-cta--link        (0,3,0)
 *   hero  .hba-field-charcoal .hba-cta.hba-cta--link:hover  (0,4,0)
 *   here  .hba-card--dark .hba-cta.hba-cta--link            (0,3,0)  ties the field
 *         rule, and both say amberInk, so the tie is harmless
 *   here  .hba-card--center.hba-card--dark …                (0,4,0)  clears it
 *   here  …:hover                                           (0,5,0)  clears it */
.hba-card--dark .hba-cta.hba-cta--link,
.hba-card--center.hba-card--dark .hba-cta.hba-cta--link,
.hba-card--icon:has(.hba-icon--house) .hba-cta.hba-cta--link,
.hba-card--icon:has(.hba-icon--national) .hba-cta.hba-cta--link {
  color: var(--hba-amberink, #ffb900); /* H text-amber-400 */
}
.hba-card--dark .hba-cta.hba-cta--link:hover,
.hba-card--center.hba-card--dark .hba-cta.hba-cta--link:hover,
.hba-card--icon:has(.hba-icon--house) .hba-cta.hba-cta--link:hover,
.hba-card--icon:has(.hba-icon--national) .hba-cta.hba-cta--link:hover {
  color: var(--hba-amberink, #ffb900); /* H: ink HOLDS on hover; the gesture is the gap */
}
/* H `gap-1.5 group-hover:gap-2.5` on the affiliate pair — 6px to 10px, a step wider
 * than the 8px every other card link grows to. (0,5,0) over hero.css's
 * `.hba-card--icon:hover .hba-cta--link` (0,3,0). */
.hba-card--center.hba-card--dark:hover .hba-cta.hba-cta--link { gap: 10px; }

/* ============================================== REDUCED MOTION (interior) ===
 * Same convention as the blocks above: transitions only, so they collapse cleanly.
 * Live has no reduced-motion handling at all; this is ADDED, per HBA-D-8 / I-16. */
@media (prefers-reduced-motion: reduce) {
  .hba-card--navy,
  .hba-card__ext,
  .hba-card__body > .hba-heading,
  .hba-newsrow__ext,
  .hba-newsrow__copy > .hba-heading,
  .hba-newscard__copy > .hba-heading,
  .hba-eventlist__arrow { transition-duration: 0s; }
}
