/* Astra surfaces that do not match the design system out of the box.
 * Handover doc section 5. Every value is a token — no literals except the
 * ones the doc itself specifies (44px control height, 921px breakpoint). */

/* 1 — Buttons. Astra prints its own button rules inline; re-assert ours.
      .bk-btn classes are used in patterns, but editor-inserted core
      buttons and Astra's own CTA must inherit the same pill. */
.ast-button,
.ast-custom-button,
input[type="submit"],
.button {
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  border-radius: var(--radius-button);
  background: var(--accent-primary);
  border: var(--border-width-strong) solid var(--accent-primary);
  color: var(--accent-contrast);
  min-height: 44px;
  padding: 0 var(--space-6);
  transition: var(--transition-control);
}
.ast-button:hover {
  background: var(--accent-primary-hover);
  border-color: var(--accent-primary-hover);
  color: var(--bk-white);
}

/* W-2: .wp-block-button__link and its is-style-outline variant used to be
   styled here too, at (0,1,0). Sections 6c and 6d style the same anchor at
   (0,3,0)/(0,4,0), so these could never win and were dead weight. Removed. */

/* 2 — Container. Keep Astra's grid, take our max width and gutter. */
.ast-container, .ast-container-fluid {
  max-width: var(--container-max);
  padding-inline: var(--gutter-inline);
}
.ast-page-builder-template .entry-content > .alignfull { margin-inline: 0; }

/* 3 — Focus. Astra's outline is thin and grey; compliance software
      needs an obvious ring.

   The design system readme specifies two distinct treatments, not one:
   a 3px rgba(138,195,64,.42) ring via --shadow-focus on CONTROLS, and a
   2px green outline with 2px offset ELSEWHERE. Applying the ring to
   everything, as this file previously did, dropped the second treatment
   entirely — and because tokens/base.css is deliberately not copied
   (section 3), nothing else supplied it. Focus must always be visible and
   is never removed. */
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[role="button"]:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
}

/* 4 — Headings. Astra sets these from the Customizer, but tracking
      is not exposed there. */
h1 { font-size: var(--type-h1-size); line-height: var(--type-h1-lh);
     letter-spacing: var(--type-h1-ls); }
h2 { font-size: var(--type-h2-size); line-height: var(--type-h2-lh);
     letter-spacing: var(--type-h2-ls); }
h3 { font-size: var(--type-h3-size); line-height: var(--type-h3-lh);
     letter-spacing: var(--type-h3-ls); }
h1, h2, h3, h4 { text-wrap: balance; }
p, li { text-wrap: pretty; }

/* 5 — Section rhythm: now UPSTREAMED into components.css
   (.bk-section, --tight, --sunken, --dark). Removed here to keep one
   definition. The (0,3,0) rules in 6a stay — they beat Astra's
   (0,2,0) block padding, which the upstream (0,1,0) rule cannot. */

/* ============================================================
 * 6 — Beating Astra's real specificity.
 *
 * Astra's own rules are (0,2,0), not zero-specificity :where()
 * defaults, so the (0,1,0) rules above lose to them outright. Measured
 * from the live page:
 *
 *   .wp-block-button__link:not(.has-text-color){color:var(--ast-global-color-0)}
 *       -> :not() contributes its argument, so (0,2,0). Beat our (0,1,0)
 *          button colour, which is why button text rendered Astra blue.
 *
 *   .entry-content > .wp-block-group{padding-top:var(--wp--custom--ast-...)}
 *       -> (0,2,0). Beat .bk-section's padding-block, collapsing the
 *          96px section rhythm to Astra's default block padding.
 *
 * Per section 5 these are fixed by out-specificity, never !important.
 * Everything below is (0,2,0) or higher and uses only tokens.
 * ============================================================ */

/* 6a — Section rhythm, re-asserted over Astra's default block padding. */
.entry-content > .wp-block-group.bk-section {
  padding-block: var(--section-y);
  padding-inline: var(--gutter-inline);
}
.entry-content > .wp-block-group.bk-section--tight {
  padding-block: var(--section-y-tight);
}
@media (max-width: 921px) {
  .entry-content > .wp-block-group.bk-section {
    padding-block: var(--section-y-tight);
  }
}

/* 6b — Eyebrow as a direct section child.
 *
 * components.css makes .bk-eyebrow display:inline-flex so the rule hugs the
 * text. That is inline-level, and WordPress's constrained layout centres
 * children with margin-inline:auto, which has no effect on an inline-level
 * box — so a section-level eyebrow escaped to the full-bleed left edge while
 * the block-level headings beside it were constrained correctly.
 *
 * Making it block-level flex only where it is a direct section child fixes
 * the constraint and keeps the ::before rule line. Eyebrows nested inside
 * columns are untouched and stay inline-flex.
 */
.bk-section > p.bk-eyebrow {
  display: flex;
}

/* 6c — Editor buttons with NO bk-btn variant get the primary pill.
 *
 * Correction to an earlier note here: a custom className on core/button does
 * survive a save. The live page carries bk-btn, bk-btn--primary, bk-btn--lg
 * and friends on all five button wrappers. An earlier reading of a stale
 * capture concluded otherwise and this file was written for that wrong
 * premise, which left two rule sets styling the same anchor at tied (0,3,0)
 * specificity — decided only by source order, and doubling up wherever both
 * matched.
 *
 * Scoped with :not([class*="bk-btn--"]) so the two can no longer overlap:
 * a variant-classed button is styled solely by 6d below, and a plain
 * editor-inserted button gets the primary pill. Section 5 wants the latter —
 * "editor-inserted core buttons and Astra's own CTA must inherit the same
 * pill" — so both paths are needed, just not on the same element.
 *
 * The anchor always carries .wp-block-button__link and .wp-element-button,
 * giving (0,3,0) against Astra's (0,2,0) inline rules without !important.
 * Core's own is-style-outline provides the secondary look for plain buttons.
 */
.wp-block-button:not([class*="bk-btn--"]) > .wp-block-button__link.wp-element-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  letter-spacing: .01em;
  min-height: 44px;
  padding: 0 var(--space-6);
  font-size: 15px;
  border: var(--border-width-strong) solid var(--accent-primary);
  border-radius: var(--radius-button);
  background: var(--accent-primary);
  color: var(--accent-contrast);
  text-decoration: none;
  transition: var(--transition-control);
  white-space: nowrap;
}
.wp-block-button:not([class*="bk-btn--"]) > .wp-block-button__link.wp-element-button:hover {
  background: var(--accent-primary-hover);
  border-color: var(--accent-primary-hover);
  color: var(--bk-white);
}
.wp-block-button:not([class*="bk-btn--"]) > .wp-block-button__link.wp-element-button:active {
  background: var(--accent-primary-press);
  border-color: var(--accent-primary-press);
}
.wp-block-button:not([class*="bk-btn--"]) > .wp-block-button__link.wp-element-button:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
}

/* Secondary, via core's built-in outline style. */
.wp-block-button.is-style-outline > .wp-block-button__link.wp-element-button {
  background: transparent;
  border-color: var(--accent-primary);
  color: var(--bk-leaf-800);
}
.wp-block-button.is-style-outline > .wp-block-button__link.wp-element-button:hover {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: var(--accent-contrast);
}

/* On dark backgrounds (hero, CTA band) the second button reads white.
 * Scoped by context rather than by a class the editor would strip. */
.wp-block-cover .wp-block-button.is-style-outline > .wp-block-button__link.wp-element-button,
.bk-section--dark .wp-block-button.is-style-outline > .wp-block-button__link.wp-element-button {
  background: var(--bk-white);
  border-color: var(--bk-white);
  color: var(--bk-graphite-900);
}
.wp-block-cover .wp-block-button.is-style-outline > .wp-block-button__link.wp-element-button:hover,
.bk-section--dark .wp-block-button.is-style-outline > .wp-block-button__link.wp-element-button:hover {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: var(--accent-contrast);
}

/* 6d — bk-btn bridge, kept for markup where the classes DO survive
 * (a pattern inserted and not re-saved, or hand-written wp:html).
 * Sizes and variants copied from components.css.
 */
/* 6d — bk-btn wrapper bridge.
 *
 * components.css styles .bk-btn as the button itself, but the block editor
 * only lets a className reach the WRAPPER (div.wp-block-button); the real
 * control is the inner <a class="wp-block-button__link">. Left alone, the
 * wrapper got our pill and the anchor kept Astra's styling — a green pill
 * with blue text.
 *
 * So: neutralise the wrapper, and map each variant onto the anchor at
 * (0,3,0). Values are copied from components.css, not re-invented.
 */
.wp-block-button.bk-btn {
  display: inline-block;
  height: auto;
  min-height: 0;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  transition: none;
}

.wp-block-button.bk-btn > .wp-block-button__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  letter-spacing: .01em;
  border: var(--border-width-strong) solid transparent;
  border-radius: var(--radius-button);
  text-decoration: none;
  transition: var(--transition-control);
  white-space: nowrap;
}
.wp-block-button.bk-btn > .wp-block-button__link:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
}

.wp-block-button.bk-btn--sm > .wp-block-button__link { height: 34px; padding: 0 var(--space-4); font-size: 13px; }
.wp-block-button.bk-btn--md > .wp-block-button__link { height: 44px; padding: 0 var(--space-6); font-size: 15px; }
.wp-block-button.bk-btn--lg > .wp-block-button__link { height: 54px; padding: 0 var(--space-7); font-size: 17px; }

.wp-block-button.bk-btn--primary > .wp-block-button__link {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: var(--accent-contrast);
}
.wp-block-button.bk-btn--primary > .wp-block-button__link:hover {
  background: var(--accent-primary-hover);
  border-color: var(--accent-primary-hover);
  color: var(--bk-white);
}
.wp-block-button.bk-btn--primary > .wp-block-button__link:active {
  background: var(--accent-primary-press);
  border-color: var(--accent-primary-press);
}

.wp-block-button.bk-btn--secondary > .wp-block-button__link {
  background: transparent;
  border-color: var(--accent-primary);
  color: var(--bk-leaf-800);
}
.wp-block-button.bk-btn--secondary > .wp-block-button__link:hover {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: var(--accent-contrast);
}

.wp-block-button.bk-btn--outlineDark > .wp-block-button__link {
  background: transparent;
  border-color: var(--bk-graphite-700);
  color: var(--bk-graphite-900);
}
.wp-block-button.bk-btn--outlineDark > .wp-block-button__link:hover {
  background: var(--bk-graphite-900);
  border-color: var(--bk-graphite-900);
  color: var(--bk-white);
}

.wp-block-button.bk-btn--onDark > .wp-block-button__link {
  background: var(--bk-white);
  border-color: var(--bk-white);
  color: var(--bk-graphite-900);
}
.wp-block-button.bk-btn--onDark > .wp-block-button__link:hover {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
}

.wp-block-button.bk-btn--dark > .wp-block-button__link {
  background: var(--bk-graphite-900);
  border-color: var(--bk-graphite-900);
  color: var(--bk-white);
}
.wp-block-button.bk-btn--ghost > .wp-block-button__link {
  background: transparent;
  border-color: transparent;
  color: var(--bk-graphite-700);
}

/* ============================================================
 * 7 — Material Symbols rendered as masks.
 *
 * The brand's real icons were delivered from the media library as 96x96 WebP
 * with an alpha channel, not as SVG. Rendering them in an <img> would paint
 * them at their exported #1F1F1F, which breaks the design system's rule that
 * a glyph inherits currentColor — white inside a leaf IconBadge, leaf-700
 * inside a soft tile, graphite in body text. A raster cannot recolour.
 *
 * Using the file as a CSS mask over a currentColor background solves that:
 * the alpha channel supplies the glyph shape and the colour comes from
 * context, exactly as an inline SVG would. bk_icon() sets --bk-icon per
 * instance and the size inline.
 *
 * Masking is the reason the alpha channel mattered; without it this would
 * paint a solid square.
 * ============================================================ */
.bk-icon--material {
  display: inline-block;
  flex: none;
  background-color: currentColor;
  -webkit-mask-image: var(--bk-icon);
  mask-image: var(--bk-icon);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* 8 — Hero scrim: cover-block workaround REMOVED (W-14, Rev 1.6).
   components.css now stacks photo 0 · scrim 1 · copy 2 and lifts only
   .wp-block-cover__inner-container. Core's cover CSS keeps the image at
   z-index 0; the dim span is z-index 1 but the hero pattern sets
   dimRatio 0, so it is transparent. Core loads before bk-components, so
   the equal-(0,2,0) inner-container rule resolves in components.css's favour. */

/* ============================================================
 * 9 — Header navigation and footer.
 *
 * Both are Astra Header/Footer Builder output, so the markup is Astra's and
 * the selectors below are taken from the rendered page, not guessed:
 * .main-header-menu .menu-link, .sub-menu, span.site-title, .site-footer,
 * .wp-block-heading (the footer columns are a block widget), .ast-footer-copyright.
 *
 * Root cause of both looking wrong: Astra's global palette was at its
 * defaults, with --ast-global-color-0 set to #0170B9. (Fixed in the
 * Customizer on 27 Sep 2026, W-5: slot 0 is now leaf-700 #5f7d31 and no
 * #0170B9 remains on the home page. The history below explains the rules.) That one blue drives
 * every nav link, every footer link, and the footer headings that happen to
 * wrap an anchor — which is why "Quick Links" renders dark while "Solutions"
 * and "Services" render blue. Astra sets it through a bare `a` selector at
 * (0,0,1), so scoped rules here win comfortably without !important.
 *
 * The durable fix is the Customizer, per section 5 of the handover doc:
 * Text #3a3a3c, Link #5f7d31, Link hover #495726, Theme colour #8ac340. Set
 * there it applies everywhere at once and survives independently of this file.
 * These rules bring the two areas to the design system in the meantime, and
 * remain correct afterwards because they reference tokens rather than
 * Astra's palette.
 * ============================================================ */

/* 9a — Header.
 *
 * The nav wrapping onto two rows was not a font-choice problem. Astra prints,
 * from the Customizer:
 *
 *   .ast-builder-menu-1 .menu-item > .menu-link{font-size:28px;padding:15px 15px;}
 *
 * A 28px nav with 15px of padding each side cannot fit six top-level items on
 * one row. That selector is (0,3,0) and the rules here were (0,2,0), so the
 * intended 15px never applied at all. Matched below at (0,4,0).
 *
 * Values come from the kit's own SiteHeader in ui_kits/website/SiteChrome.jsx:
 * Montserrat 600 at 15px, NO letter-spacing, --text-muted when inactive,
 * graphite-900 plus a 2px leaf underline for the current item, gap space-6,
 * a 76px bar. Two earlier guesses here were off-spec -- a .01em tracking the
 * kit does not have, and --text-body instead of --text-muted -- and the
 * tracking made the width problem worse.
 *
 * The durable fix is still the Customizer: Header Builder -> Primary Menu ->
 * Typography, set to 15px. A saved Customizer value outlives any stylesheet.
 */
.site-header {
  border-bottom: var(--border-width) solid var(--border-hairline);
}

/* (0,4,0), to beat Astra's (0,3,0) Customizer rule. */
.site-header .ast-builder-menu-1 .menu-item > .menu-link,
.site-header .main-header-menu .menu-item > .menu-link {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-lh);
  letter-spacing: normal;
  white-space: nowrap;
  padding-left: var(--space-3);
  padding-right: var(--space-3);
  color: var(--text-muted);
  transition: var(--transition-control);
}
.site-header .main-header-menu .menu-item:hover > .menu-link,
.site-header .main-header-menu .menu-item > .menu-link:hover,
.site-header .main-header-menu .menu-item > .menu-link:focus-visible {
  color: var(--text-strong);
}

/* Current item: graphite text plus the 2px leaf underline the kit uses, which
   is the same "selected" signal as a tab. */
.site-header .main-header-menu .current-menu-item > .menu-link,
.site-header .main-header-menu .current_page_item > .menu-link,
.site-header .main-header-menu .current-menu-ancestor > .menu-link {
  color: var(--text-strong);
  box-shadow: inset 0 -2px 0 0 var(--accent-primary);
}

/* Dropdowns: a popover card — hairline border, 8px radius, shadow-3.
   Submenu items stay at body-sm with a leaf-050 hover, per the kit. */
.site-header .main-header-menu .sub-menu {
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-3);
}
.site-header .main-header-menu .sub-menu .menu-item > .menu-link {
  font-size: var(--type-body-sm-size);
  white-space: normal;
  color: var(--text-body);
  box-shadow: none;
}
.site-header .main-header-menu .sub-menu .menu-item > .menu-link:hover {
  background: var(--bk-leaf-050);
  color: var(--text-strong);
}

/* The header lockup is the mark plus "Bay Kinetic" in Montserrat Bold; Astra
   renders the text half as <span class="site-title">. The kit sets 22px with
   -.01em tracking. */
.site-title,
.site-title a {
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  font-size: 22px;
  letter-spacing: -.01em;
  color: var(--text-strong);
  white-space: nowrap;
}
.site-title a:hover {
  color: var(--text-link);
}

/* 9b — Footer.
 *
 * Kept on its current light ground. Section 8 of the handover doc specifies a
 * dark footer, and the rule for that is at the end of this section, commented,
 * because enabling it without also swapping the footer logo would hide the
 * logo: the widget currently uses a dark-ink PNG, and the design system has no
 * knockout lockup. See the note there.
 */
.site-footer a {
  color: var(--text-link);
  transition: var(--transition-control);
}
.site-footer a:hover,
.site-footer a:focus-visible {
  color: var(--text-link-hover);
}

/* Column headings: Montserrat, caps, wide tracking — the same treatment as a
   table header or stat label. Headings that wrap a link inherit the heading
   colour instead of turning into body links. */
.site-footer .wp-block-heading {
  font-family: var(--font-display);
  font-size: var(--type-label-size);
  line-height: var(--type-label-lh);
  letter-spacing: var(--type-label-ls);
  text-transform: uppercase;
  font-weight: var(--fw-bold);
  color: var(--text-strong);
  margin-bottom: var(--space-3);
}
.site-footer .wp-block-heading a {
  color: inherit;
}
.site-footer .wp-block-heading a:hover {
  color: var(--text-link);
}

.site-footer .wp-block-list {
  list-style: none;
  padding-left: 0;
}
.site-footer .wp-block-list li {
  margin-bottom: var(--space-2);
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-lh);
}

/* Bottom bar: caption size, faint, per section 8. */
.ast-footer-copyright,
.ast-footer-copyright p {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-lh);
  color: var(--text-faint);
}

/* 9c — Dark footer: WITHDRAWN by the design system (handover section 8).
   The footer stays light. Block removed. */

/* ============================================================
 * 10 — Legacy client-authored banners.
 *
 * The pages built before this theme (/cannabis-compliance/,
 * /licensing-consulting/, /metrc-compliance/, /refund_returns/, and the hero
 * of /book-a-demo/ — re-measured 27 Sep 2026) use two
 * client-authored classes on core cover blocks: .Banner-section-custom for
 * the page hero and .Schedule-banner for the closing CTA. The rules are keyed
 * to those classes, not to pages, so they come out only once the last of
 * those pages is rebuilt — grep each live page for both classes first. Both share one
 * defect, measured rather than guessed:
 *
 *   <span class="wp-block-cover__background has-background-dim"></span>
 *
 * No dim percentage and no overlay colour, so core falls back to black at
 * opacity .5 — a flat, uniform wash. The headline and lead both DO carry a
 * white colour class (has-ast-global-color-5-color), so they are not dark;
 * they are white text on a uniformly half-dimmed photograph, which reads
 * fine for a large headline and disappears for a 16px lead over the bright
 * parts of a greenhouse shot. That is precisely what the design system
 * forbids: "Never set type directly on an unprotected image."
 *
 * The fix is the same one section 8 applies to new heroes — a real scrim
 * token. --scrim-bottom is the right one here because the copy in these
 * banners is centred and sits low, not in a left column.
 *
 * Scoped to the two client classes so no other cover is touched, and drawn
 * with ::after rather than ::before to avoid colliding with anything the
 * original page may already use.
 *
 * These banners are also cramped: neither carries a minHeight, so the copy
 * sits hard against the photo edges.
 * ============================================================ */
.wp-block-cover.Banner-section-custom,
.wp-block-cover.Schedule-banner {
  position: relative;
  padding-block: var(--section-y-tight);
}
.wp-block-cover.Banner-section-custom {
  min-height: 420px;
}
.wp-block-cover.Schedule-banner {
  min-height: 320px;
}

.wp-block-cover.Banner-section-custom::after,
.wp-block-cover.Schedule-banner::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--scrim-bottom);
  z-index: 1;
  pointer-events: none;
}
.wp-block-cover.Banner-section-custom > .wp-block-cover__inner-container,
.wp-block-cover.Schedule-banner > .wp-block-cover__inner-container {
  position: relative;
  z-index: 2;
}

/* Type inside those banners, to the design system's scale. The lead gets a
   measure so it does not run the full 1200px, which is what makes a centred
   paragraph hard to read even once the contrast is fixed. */
.Banner-section-custom .wp-block-heading,
.Schedule-banner .wp-block-heading {
  font-size: var(--type-display-2-size);
  line-height: var(--type-display-2-lh);
  letter-spacing: var(--type-display-2-ls);
  color: var(--bk-white);
}
.Banner-section-custom p,
.Schedule-banner p {
  font-size: var(--type-lead-size);
  line-height: var(--type-lead-lh);
  color: var(--bk-white);
  max-width: 46em;
  margin-inline: auto;
}

/* Any text inside a cover that carries no explicit colour still needs to be
   legible on a scrim. Covers WordPress marked as light-background are left
   alone, since their copy is intentionally dark. */
.wp-block-cover:not(.is-light) .wp-block-cover__inner-container > *:not([class*="-color"]) {
  color: var(--bk-white);
}

/* ============================================================
 * 11 — Gravity Forms (Orbital), mapped onto the form components (W-11).
 *
 * The forms use Gravity Forms 3.1.2's Orbital theme
 * (.gform-theme--framework.gform-theme--orbital), which is styled through
 * its CSS API: --gf-* custom properties. docs.gravityforms.com/css-api/
 * Nothing here sets a property on a Gravity Forms element except the focus
 * fix at the end; everything else is a variable Orbital already consumes.
 *
 * WHY THE VARIABLES ARE SET ON <form>, NOT ON THE WRAPPER. Gravity Forms
 * prints an inline block per form, keyed on the form's id:
 *
 *   #gform_wrapper_1[data-form-index="0"].gform-theme{--gf-color-primary:
 *     #204ce5; --gf-radius:3px; --gf-ctrl-size:...; --gf-ctrl-border-color:
 *     ...; --gf-ctrl-label-color-primary:...; --gf-ctrl-btn-size:...}
 *
 * That is (1,2,0), so a .gform-theme--framework rule here would lose
 * silently. Custom properties inherit, though, and <form> is a child of the
 * wrapper: declaring them on it overrides the wrapper's value for every field
 * and button inside, with no specificity contest and no !important.
 *
 * The catch is that derived variables are computed where they are declared.
 * --gf-ctrl-border-color-focus is var(--gf-color-primary) resolved ON THE
 * WRAPPER, so redefining --gf-color-primary here would change nothing below.
 * Hence each leaf variable is set directly. The base palette (primary colour,
 * which also drives checkboxes, radios and the date picker) is set at its
 * source by the gform_default_styles filter in inc/gravity-forms.php.
 *
 * Values are copied from components.css (.bk-field*, .bk-input) and from
 * section 6c's primary pill.
 * ============================================================ */
.gform_wrapper.gform-theme--orbital > form {
  /* Input — .bk-input */
  --gf-ctrl-size: 44px;
  --gf-ctrl-font-family: var(--font-body);
  --gf-ctrl-font-size: 15px;
  --gf-ctrl-color: var(--text-strong);
  --gf-ctrl-bg-color: var(--surface-card);
  --gf-ctrl-radius: var(--radius-control);
  --gf-ctrl-shadow: none;
  --gf-ctrl-border-color: var(--border-default);
  --gf-ctrl-border-color-hover: var(--bk-graphite-400);
  --gf-ctrl-border-color-focus: var(--accent-primary);
  --gf-ctrl-border-color-error: var(--bk-violation);

  /* Label — .bk-field__label; the 6px gap is .bk-field's */
  --gf-ctrl-label-font-family-primary: var(--font-display);
  --gf-ctrl-label-font-weight-primary: var(--fw-semibold);
  --gf-ctrl-label-font-size-primary: var(--type-label-size);
  --gf-ctrl-label-letter-spacing-primary: var(--type-label-ls);
  --gf-ctrl-label-color-primary: var(--text-strong);
  --gf-ctrl-label-color-req: var(--bk-violation);
  --gf-label-space-primary: 6px;

  /* Choice labels and hints — .bk-field__hint. (Orbital's "secondary"
     labels are radio and checkbox labels; the "First"/"Last" sub-labels
     are its "tertiary" set, left at Orbital's values. Checked in the
     deployed framework CSS, 28 Sep 2026.) */
  --gf-ctrl-label-font-family-secondary: var(--font-body);
  --gf-ctrl-label-font-size-secondary: var(--type-caption-size);
  --gf-ctrl-label-color-secondary: var(--text-muted);
  --gf-ctrl-desc-font-family: var(--font-body);
  --gf-ctrl-desc-font-size: var(--type-caption-size);
  --gf-ctrl-desc-color: var(--text-muted);
  --gf-ctrl-desc-color-error: var(--bk-violation);

  /* Submit — section 6c's primary pill */
  --gf-ctrl-btn-size: 44px;
  --gf-ctrl-btn-font-family: var(--font-display);
  --gf-ctrl-btn-font-weight: var(--fw-bold);
  --gf-ctrl-btn-font-size: 15px;
  --gf-ctrl-btn-letter-spacing: .01em;
  --gf-ctrl-btn-padding-x: var(--space-6);
  --gf-ctrl-btn-radius: var(--radius-button);
  --gf-ctrl-btn-shadow: none;
  --gf-ctrl-btn-shadow-hover: none;
  --gf-ctrl-btn-shadow-focus: var(--shadow-focus);
  --gf-ctrl-btn-border-width-primary: var(--border-width-strong);
  --gf-ctrl-btn-bg-color-primary: var(--accent-primary);
  --gf-ctrl-btn-border-color-primary: var(--accent-primary);
  --gf-ctrl-btn-color-primary: var(--accent-contrast);
  --gf-ctrl-btn-bg-color-hover-primary: var(--accent-primary-hover);
  --gf-ctrl-btn-border-color-hover-primary: var(--accent-primary-hover);
  --gf-ctrl-btn-color-hover-primary: var(--bk-white);
}

/* Focus — restores the ring Astra removes.
 *
 * Measured in headless Chrome against the live /contact-us/ page on
 * 27 Sep 2026: a keyboard-focused input showed NO change at all — same grey
 * border, no outline, no ring. Astra's compatibility sheet does it:
 *
 *   astra gravity-forms.min.css  .gform_wrapper input:not([type=submit]):focus
 *     {border-color:var(--ast-border-color);outline:0;box-shadow:none} (0,3,1)
 *
 * Orbital draws focus through real properties fed by its --gf-local-*
 * variables at a lower weight, so Astra wins. This is the one place real
 * properties are needed: (0,5,1). The ring is the design system's control
 * treatment, --shadow-focus, rather than Orbital's outline. The border reads
 * Orbital's own --gf-local-border-color, so it follows Orbital's states.
 *
 * Measured the same way with .gfield_error added: unfocused border and
 * message are violation red, the label stays graphite; focused, the ring is
 * red and the border goes green. Orbital sets that green on error focus, and
 * it matches components.css, where .bk-input:focus (0,2,0) outranks
 * .bk-input--invalid (0,1,0). (Headless Chrome reports the ring as zero
 * unless transitions are disabled first; that is a timing artifact.) */
.gform_wrapper.gform-theme--orbital .gfield :is(input[type], select, textarea):focus {
  border-color: var(--gf-local-border-color);
  outline: none;
  box-shadow: var(--shadow-focus);
}
/* .bk-input--invalid:focus. The literal is components.css's own. */
.gform_wrapper.gform-theme--orbital .gfield_error :is(input[type], select, textarea):focus {
  box-shadow: 0 0 0 3px rgba(194,64,47,.28);
}

/* 11b — The Book a Demo form: form 4 in the #book card on /book-a-demo/.
 *
 * Book a Demo Handover §3. The same method as above, variables on <form>,
 * for what that form does differently from the site-wide one. Each value is
 * a token, or the literal components.css itself uses for the component
 * named beside it. Behaviour (blur validation, "Sending…") is in site.js. */
#book .gform_wrapper.gform-theme--orbital > form {
  /* One column, 16px between fields. */
  --gf-form-gap-y: var(--space-4);

  /* Submit — .bk-btn--lg */
  --gf-ctrl-btn-size: 54px;
  --gf-ctrl-btn-font-size: 17px;
  --gf-ctrl-btn-padding-x: var(--space-7);

  /* Radios — .bk-choice: a 20px box, its label body-sm in body colour.
     Orbital sets choice labels from its "secondary" label variables. */
  --gf-ctrl-choice-size: 20px;
  --gf-ctrl-choice-check-color: var(--bk-graphite-900);
  --gf-ctrl-label-font-size-secondary: var(--type-body-sm-size);
  --gf-ctrl-label-line-height-secondary: var(--type-body-sm-lh);
  --gf-ctrl-label-color-secondary: var(--text-body);

  /* A failed send — .bk-alert--danger */
  --gf-form-validation-bg-color: var(--bk-violation-soft);
  --gf-form-validation-border-color: #f0c8c1;
  --gf-form-validation-border-color-focus: #f0c8c1;
  --gf-form-validation-color: #963223;
  --gf-form-validation-heading-color: #963223;
  --gf-form-validation-font-family: var(--font-body);
  --gf-form-validation-font-size: var(--type-body-sm-size);
  --gf-form-validation-heading-font-family: var(--font-display);
  --gf-form-validation-heading-font-size: 15px;
  --gf-form-validation-heading-icon-color: #963223;
  --gf-form-validation-heading-icon-border-color: #963223;
  --gf-form-validation-border-width: var(--border-width);
  --gf-form-validation-radius: var(--radius-md);
  --gf-form-validation-padding-x: var(--space-4);
  --gf-form-validation-padding-y: var(--space-4);
  --gf-form-validation-shadow: none;
}

/* Phone — .bk-input--mono. A phone number is a machine-readable value. */
#book .gform_wrapper.gform-theme--orbital .gfield--type-phone {
  --gf-ctrl-font-family: var(--font-mono);
}

/* Submit — .bk-btn--block. */
#book .gform_wrapper.gform-theme--orbital .gform_footer .gform_button {
  width: 100%;
}

/* Required fields carry the asterisk (.bk-field__req, the form's
   "Asterisk" indicator setting) and no "* indicates required fields"
   legend, per the handover. aria-required stays on every control. */
#book .gform_required_legend {
  display: none;
}

/* ============================================================
 * 12 — Component combinations components.css resolves unintentionally.
 * ============================================================ */

/* Brand-toned Stat on a dark band. In components.css
 * .bk-stat--onDark .bk-stat__value (0,2,0) outranks .bk-stat__value--brand
 * (0,1,0), so the brand tone was silently white on dark. The case-study
 * handover (§3.2) asks for exactly this pairing. This restores the
 * component's own brand value; leaf-600 on graphite-900 is 5.1:1. (0,3,0). */
.bk-stat--onDark .bk-stat__value.bk-stat__value--brand {
  color: var(--bk-leaf-600);
}

/* A .bk-table sets only a bottom hairline per cell. Astra's
 * `table, td, th { border: 1px solid var(--ast-border-color) }` (0,0,1)
 * draws the other three sides, so every .bk-table rendered as a grid (seen
 * in a render of the Scales Guide jar table, 28 Sep). This removes those,
 * leaving components.css's bottom border. Short mono values ("3.3 g") no
 * longer break across two lines in a narrow column. */
.bk-table { border: 0; }
.bk-table :is(th, td) { border-top: 0; border-inline: 0; }
.bk-table .bk-table__mono { white-space: nowrap; }

/* A linked card title (the Scales Guide's "Three setups" cards link to their
 * sections). Astra's link colour would turn the title green; it keeps the
 * title's own colour and shows the underline on hover and focus. (0,2,1)
 * ties Astra's `.ast-single-post .entry-content a` underline and wins on
 * order; it beats a:hover, a:focus (0,1,1). */
.bk-card .bk-card__title a { color: inherit; text-decoration: none; }
.bk-card .bk-card__title a:is(:hover, :focus-visible) {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ============================================================
 * 13 — Table scroll wrapper.
 *
 * A .bk-table is 100% wide and never wraps its mono cells, so at 375px a
 * four-column table pushes the page sideways. Wrap it in a Custom HTML
 * <div class="bk-table-scroll"> and the table scrolls inside its own box.
 * Earlier pastes used an inline overflow style for the same thing.
 * ============================================================ */
.bk-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* ============================================================
 * 14 — Article components (BaykedFarm case-study handover, 28 Sep 2026).
 *
 * Pull lines, the step list, the comparison table, stat grids and the
 * screenshot panel. They load site-wide, in the editor too, because the
 * block styles in inc/editor.php are offered on every screen.
 *
 * Inside a post, blog.css sets p and li at (0,1,1). Each rule here that has
 * to beat it is scoped by `:is(.entry-content, .is-root-container)`
 * (front end, editor canvas), which lifts it to (0,2,0) or higher.
 * ============================================================ */

/* 14a — Tokens the design system doesn't have yet (handover §5). They are
 * here, not in tokens/, because tokens/ is a verbatim copy. Requested
 * upstream; delete each one here once a re-copy brings it.
 *
 *   --type-article-size/-lh  long-form article body (§5 row 1)
 *   --post-hero-*            case-study hero: min height, h1 measure, headshot
 *   --post-aside-min/-max    the post sidebar's column (§2 row 4)
 *   --table-compare-min      the comparison table's scroll width (§3)
 *   --stat-grid-min          auto-fit column floor, stat band (§2 row 3)
 *   --stat-card-min          auto-fit column floor, stat cards (§3)
 *   --tap-target             the 44px minimum the acceptance list asks for
 *
 * Harvest cost handover (28 Sep 2026), which restyled the case-study hero
 * (min height 600 -> 620, h1 measure 880 -> 920) and added:
 *   --post-hero-title-min/-fluid  the h1's clamp(34px, 5vw, display-1)
 *   --post-hero-lead-max          the hero lead's measure
 *   --post-aside-start-*, --post-article-max  the sidebar-first layout
 *   --author-photo-*, --author-body-min       the author card
 *   --related-card-min            "Keep Reading" auto-fit floor
 *   --case-card-min               farm cards' auto-fit floor
 *   --chart-*                     the bar chart (15e): plot height, column
 *                                 floor, bar gap, 10px value labels, swatch
 *   --highlight-rule-w            the highlight's leaf rule
 */
:root {
  --type-article-size: 19px;
  --type-article-lh: 1.65;
  --post-hero-avatar: 48px;
  --post-aside-min: 260px;
  --post-aside-max: 320px;
  --table-compare-min: 620px;
  --stat-grid-min: 200px;
  --stat-card-min: 220px;
  --tap-target: 44px;
  --post-hero-min-height: 620px;
  --post-hero-title-max: 920px;
  --post-hero-title-min: 34px;
  --post-hero-title-fluid: 5vw;
  --post-hero-lead-max: 640px;
  --post-aside-start-min: 220px;
  --post-aside-start-max: 280px;
  --post-article-max: 760px;
  --author-photo-h: 260px;
  --author-photo-min: 220px;
  --author-body-min: 280px;
  --related-card-min: 260px;
  --case-card-min: 210px;
  --chart-plot-h: 160px;
  --chart-col-min: 190px;
  --chart-bar-gap: 6px;
  --chart-label-size: 10px;
  --chart-swatch: 10px;
  --highlight-rule-w: 44px;
}

/* 14b — Pull line (block styles bk-pull-lg / -md / -sm on core/paragraph
 * and core/quote). A standalone display line: no rule, no quote marks, no
 * coloured border. On core/quote, the <blockquote> is reset (Astra and
 * core both give it a left border and padding) and its paragraph takes
 * the type. */
:is(.entry-content, .is-root-container) :is(.is-style-bk-pull-lg, .is-style-bk-pull-md, .is-style-bk-pull-sm) {
  margin: var(--space-7) 0;
  padding: 0;
  border: 0;
  font-family: var(--font-display);
  font-style: normal;
  color: var(--text-strong);
  text-wrap: balance;
}
/* Astra's inline `.wp-block-quote:not(.has-text-align-right):not(
   .has-text-align-center) { border-left: 5px solid }` is (0,3,0). (0,3,1). */
:is(.entry-content, .is-root-container) blockquote.wp-block-quote:is(.is-style-bk-pull-lg, .is-style-bk-pull-md, .is-style-bk-pull-sm) {
  border: 0;
  padding: 0;
}
:is(.entry-content, .is-root-container) :is(.is-style-bk-pull-lg, .is-style-bk-pull-md, .is-style-bk-pull-sm) > p {
  margin: 0;
  font: inherit;
  color: inherit;
}
:is(.entry-content, .is-root-container) .is-style-bk-pull-lg {
  font-size: var(--type-h1-size);
  line-height: var(--type-h1-lh);
  letter-spacing: var(--type-h1-ls);
  font-weight: var(--fw-black);
}
:is(.entry-content, .is-root-container) .is-style-bk-pull-md {
  font-size: var(--type-h2-size);
  line-height: var(--type-h2-lh);
  letter-spacing: var(--type-h2-ls);
  font-weight: var(--fw-black);
}
:is(.entry-content, .is-root-container) .is-style-bk-pull-sm {
  font-size: var(--type-h3-size);
  line-height: var(--type-h3-lh);
  letter-spacing: var(--type-h3-ls);
  font-weight: var(--fw-bold);
}

/* 14c — Step list. A real <ol class="bk-card bk-step-list"> in Custom HTML
 * (core/list-item takes no class, and a run of steps needs one). Numbers
 * are a counter, 01, 02, … so the markup stays a plain list. Each <li> is
 * a two-column grid, number then text, so wrap mixed text and markup in
 * one <span>. .bk-step-list__item--loop marks a run of repeated steps on
 * the sunken ground; <strong> inside a step is the one that matters. */
:is(.entry-content, .is-root-container) .bk-step-list {
  counter-reset: bk-step;
  overflow: hidden;
  margin: var(--space-7) 0;
  padding: var(--space-2) 0;
  list-style: none;
}
:is(.entry-content, .is-root-container) .bk-step-list > li {
  counter-increment: bk-step;
  display: grid;
  grid-template-columns: var(--space-9) 1fr;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-2) var(--space-5);
  border-bottom: var(--border-width) solid var(--bk-graphite-100);
  font-size: var(--type-body-size);
  line-height: var(--type-body-lh);
}
:is(.entry-content, .is-root-container) .bk-step-list > li:last-child { border-bottom: 0; }
.bk-step-list > li::before {
  content: counter(bk-step, decimal-leading-zero);
  padding-top: var(--space-1);
  font-family: var(--font-mono);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-lh);
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
.bk-step-list > .bk-step-list__item--loop { background: var(--surface-sunken); }
/* graphite-500 on graphite-050 is 4.34:1, under AA for 13px. */
.bk-step-list > .bk-step-list__item--loop::before { color: var(--text-body); }
.bk-step-list strong {
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
}

/* 14d — Comparison table: <table class="bk-table bk-table--compare"> in a
 * <div class="bk-card bk-card--pad-none bk-table-scroll">, so it scrolls
 * inside the card on a phone rather than widening the page (§13).
 * Row labels are <th scope="row">, set as body text rather than as the
 * caps column headers. .bk-table__col--highlight marks every cell of the
 * column to read first; add .bk-table__cell--key to its one key value.
 * Header text on the sunken row is --text-body, as in 14c. */
.bk-table--compare { min-width: var(--table-compare-min); }
.bk-table--compare thead th {
  background: var(--surface-sunken);
  border-bottom-width: var(--border-width);
  color: var(--text-body);
  white-space: normal; /* nowrap caps headers starve the row-label column */
  vertical-align: bottom;
}
.bk-table--compare tbody th[scope="row"] {
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--border-width) solid var(--bk-graphite-100);
  font-family: var(--font-body);
  font-size: inherit;
  letter-spacing: normal;
  text-transform: none;
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
  white-space: normal;
}
.bk-table--compare td { border-bottom-color: var(--bk-graphite-100); }
.bk-table--compare tbody tr:last-child > * { border-bottom: 0; }
.bk-table .bk-table__col--highlight {
  background: var(--bk-leaf-050);
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
}
.bk-table thead th.bk-table__col--highlight {
  border-bottom: calc(var(--border-width) + var(--border-width-strong)) solid var(--accent-primary);
  font-weight: var(--fw-black);
  color: var(--text-strong);
}
.bk-table .bk-table__col--highlight.bk-table__cell--key {
  background: var(--bk-leaf-100);
  font-size: var(--type-mono-size);
}

/* 14e — Stat grid: .bk-stat items in an auto-fit grid. On a dark band,
 * add .alignwide so the grid takes the 1200px container, not the post's
 * 720px measure. .bk-stat-grid--cards is the same grid of .bk-card-wrapped
 * stats inside an article, one step smaller so a range such as
 * "$3,500–$5,000" fits a half-column card. */
.bk-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--stat-grid-min)), 1fr));
  gap: var(--space-7);
}
.bk-stat-grid--cards {
  --stat-grid-min: var(--stat-card-min);
  gap: var(--space-4);
  margin-block: var(--space-7);
}
.bk-stat-grid--cards .bk-stat__value {
  font-size: var(--type-h1-size);
  line-height: var(--type-h1-lh);
}

/* 14f — Screen on panel (block style bk-screen on core/image). A product
 * screenshot on a sunken panel: the panel has the card radius, the image
 * the photo radius and a shadow. The caption is --text-body, as in 14c. */
.wp-block-image.is-style-bk-screen {
  padding: var(--space-6);
  border-radius: var(--radius-card);
  background: var(--surface-sunken);
}
.wp-block-image.is-style-bk-screen img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-photo);
  box-shadow: var(--shadow-3);
}
:is(.entry-content, .is-root-container) .wp-block-image.is-style-bk-screen .wp-element-caption {
  margin: var(--space-3) 0 0;
  color: var(--text-body);
}

/* ============================================================
 * 15 — Results components (harvest cost case study, 28 Sep 2026).
 *
 * Custom HTML in a post's .bk-post-section groups; site-wide like 14, so a
 * page can use them. Scoped by :is(.entry-content, .is-root-container)
 * wherever blog.css's p, li and h3 rules (0,1,1) would otherwise win.
 * ============================================================ */

/* 15a — Strong label: an eyebrow in --text-strong, used with
 * .bk-eyebrow--plain for list labels ("That one press", "Snapshot"). */
.bk-eyebrow.bk-eyebrow--strong { color: var(--text-strong); }

/* 15b — Case cards: <div class="bk-case-cards"> of
 * <div class="bk-card bk-card--pad-md bk-case-card">, each an icon badge,
 * an h3 name, a mono spec line and one short paragraph. */
.bk-case-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--case-card-min)), 1fr));
  gap: var(--space-4);
}
.bk-case-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
:is(.entry-content, .is-root-container) .bk-case-card h3.bk-case-card__name {
  margin: var(--space-2) 0 0;
  font-family: var(--font-display);
  font-size: var(--type-h3-size);
  line-height: var(--type-h3-lh);
  letter-spacing: var(--type-h3-ls);
  font-weight: var(--fw-bold);
  color: var(--text-strong);
}
:is(.entry-content, .is-root-container) .bk-case-card .bk-case-card__spec {
  margin: calc(-1 * var(--space-2)) 0 0; /* 2px under the name, as one block */
  font-family: var(--font-mono);
  font-size: var(--type-mono-sm-size);
  line-height: var(--type-mono-sm-lh);
  color: var(--text-muted);
}
:is(.entry-content, .is-root-container) .bk-case-card p.bk-case-card__text {
  margin: 0;
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-lh);
  color: var(--text-body);
}

/* 15c — Icon row: an icon badge beside a title and a line of text.
 * <ul class="bk-icon-list"> of <li class="bk-icon-row"> rows between
 * hairlines, or one <div class="bk-card bk-card--flat bk-card--pad-md
 * bk-icon-row"> as a note card. */
.bk-icon-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-5);
}
.bk-icon-row__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}
.bk-icon-row__title {
  font-family: var(--font-display);
  font-size: var(--type-h4-size);
  line-height: var(--type-h4-lh);
  font-weight: var(--fw-bold);
  color: var(--text-strong);
}
.bk-card.bk-icon-row .bk-icon-row__body { gap: var(--space-2); }
:is(.entry-content, .is-root-container) .bk-card.bk-icon-row p {
  margin: 0;
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-lh);
  color: var(--text-body);
}
:is(.entry-content, .is-root-container) ul.bk-icon-list {
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
  border-top: var(--border-width) solid var(--border-hairline);
}
:is(.entry-content, .is-root-container) .bk-icon-list > li.bk-icon-row {
  margin: 0;
  padding: var(--space-5) 0;
  border-bottom: var(--border-width) solid var(--border-hairline);
}
/* The label above the list sits 12px over it. */
:is(.entry-content, .is-root-container) p.bk-eyebrow + ul.bk-icon-list { margin-top: var(--space-3); }
.bk-icon-row .bk-mono {
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
  color: var(--text-strong);
}

/* 15d — Highlight: a group .bk-highlight holding a display line
 * (p.bk-highlight__line) and a muted note (p.bk-highlight__note), under a
 * short leaf rule. Not a quotation, so not a <blockquote>. */
:is(.entry-content, .is-root-container) .bk-highlight {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: var(--space-9) 0 var(--space-8);
}
.bk-highlight::before {
  content: "";
  width: var(--highlight-rule-w);
  height: calc(var(--border-width) + var(--border-width-strong)); /* 3px, as 14d's highlight rule */
  border-radius: var(--radius-xs);
  background: var(--accent-primary);
}
:is(.entry-content, .is-root-container) .bk-highlight > * { margin: 0; }
:is(.entry-content, .is-root-container) .bk-highlight p.bk-highlight__line {
  font-family: var(--font-display);
  font-size: var(--type-h2-size);
  line-height: var(--type-h2-lh);
  letter-spacing: var(--type-h2-ls);
  font-weight: var(--fw-bold);
  color: var(--text-strong);
  text-wrap: balance;
}
:is(.entry-content, .is-root-container) .bk-highlight p.bk-highlight__note {
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-lh);
  color: var(--text-muted);
  text-wrap: pretty;
}

/* 15e — Bar chart: <figure class="bk-card bk-card--flat bk-card--pad-md
 * bk-bar-chart">. A head (title, legend), then one .bk-bar-chart__series
 * per farm: a name and change, a plot of .bk-bar columns, and day labels.
 * Each bar's height is its style="--bar:<n>%"; .bk-bar__fill--best is the
 * leaf bar, .bk-bar--pending a dashed empty slot. Each plot is role="img"
 * with its numbers in aria-label; the table below carries them too. */
.bk-bar-chart {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  margin: var(--space-7) 0;
}
.bk-bar-chart__head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-3);
}
.bk-bar-chart__title {
  font-family: var(--font-display);
  font-size: var(--type-h4-size);
  line-height: var(--type-h4-lh);
  font-weight: var(--fw-bold);
  color: var(--text-strong);
}
.bk-bar-chart__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-lh);
  color: var(--text-muted);
}
.bk-bar-chart__key {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.bk-bar-chart__key::before {
  content: "";
  width: var(--chart-swatch);
  height: var(--chart-swatch);
  border-radius: var(--radius-xs);
  background: var(--bk-graphite-400);
}
.bk-bar-chart__key--best::before { background: var(--accent-primary); }
.bk-bar-chart__key--pending::before {
  box-sizing: border-box;
  border: var(--border-width) dashed var(--bk-graphite-400);
  background: none;
}
.bk-bar-chart__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--chart-col-min)), 1fr));
  gap: var(--space-6);
}
.bk-bar-chart__series {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
}
.bk-bar-chart__series-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-2);
}
.bk-bar-chart__name {
  font-family: var(--font-display);
  font-size: var(--type-body-sm-size);
  font-weight: var(--fw-bold);
  color: var(--text-strong);
}
.bk-bar-chart__change {
  font-family: var(--font-mono);
  font-size: var(--type-mono-sm-size);
  font-weight: var(--fw-semibold);
  color: var(--text-brand);
}
.bk-bar-chart__plot,
.bk-bar-chart__days {
  display: flex;
  gap: var(--chart-bar-gap);
}
.bk-bar-chart__plot {
  align-items: flex-end;
  height: var(--chart-plot-h);
  padding-top: var(--space-5);
  border-bottom: var(--border-width) solid var(--border-default);
}
.bk-bar {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  gap: var(--space-1);
  height: 100%;
  min-width: 0;
}
.bk-bar__value,
.bk-bar-chart__days > span {
  font-family: var(--font-mono);
  font-size: var(--chart-label-size);
  line-height: var(--type-mono-sm-lh);
  white-space: nowrap;
}
.bk-bar__value { color: var(--text-strong); }
.bk-bar__fill {
  box-sizing: border-box;
  width: 100%;
  height: var(--bar, 0%);
  min-height: var(--border-width-strong);
  border-radius: var(--radius-xs) var(--radius-xs) 0 0;
  background: var(--bk-graphite-400);
  transition: height var(--dur-slow) var(--ease-standard);
}
.bk-bar__fill--best { background: var(--accent-primary); }
.bk-bar--pending .bk-bar__fill {
  height: 100%;
  border: var(--border-width) dashed var(--bk-graphite-300);
  border-bottom: 0;
  background: none;
}
.bk-bar-chart__days > span {
  flex: 1;
  text-align: center;
  color: var(--text-muted);
}
:is(.entry-content, .is-root-container) .bk-bar-chart figcaption {
  margin: 0;
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-lh);
  color: var(--text-muted);
}

/* 15f — A .bk-table too wide for a phone keeps its columns and scrolls
 * inside its .bk-table-scroll (13). */
.bk-table.bk-table--min { min-width: var(--table-compare-min); }
.bk-table--min :is(th, td) { white-space: nowrap; }

/* Numeric column headers align with their values but keep the caps face. */
.bk-table th.bk-table__num { font-family: var(--font-display); }

/* 15g — A stat card's note is prose on white, where --text-faint
 * (graphite-400) is 2.8:1. Muted is AA. */
.bk-stat-grid--cards .bk-stat__note { color: var(--text-muted); }

/* ============================================================
 * 16 — Shared fixes from the 29 Sep page rebuilds. Four page agents
 * (Cannabis Compliance, METRC Compliance, California Compliance,
 * California Licensing) found these independently; the merge keeps one
 * copy of each. Page-specific rules follow in 17–21.
 * ============================================================ */

/* 16a — Anchor offset. The id goes on the .bk-section group (the block's
 * "HTML anchor"). The live header scrolls away (it isn't sticky, checked
 * 29 Sep), so a jump only needs a little air above the target; Kapono, 29
 * Sep: no sticky header planned. --anchor-offset is the one value every
 * jump target uses (here, 22a's calculator card, blog.css's post
 * headings). If a sticky header ever ships, set it to
 * calc(var(--header-height) + var(--space-4)). --header-height is 9a's
 * 76px bar; the design system has no token for either yet, so they live
 * here, as 14a's do. */
:root {
  --header-height: 76px;
  --anchor-offset: var(--space-4);
}
.bk-section[id] {
  scroll-margin-top: var(--anchor-offset);
}

/* 16b — Eyebrow on a photo hero. Astra prints, inline,
 *   body .wp-block-cover:not(.has-text-color.has-link-color) p
 *     { color: var(--ast-global-color-3) }             (0,3,2)
 * which beats .bk-eyebrow--onDark (0,1,0): the eyebrow rendered graphite
 * on the graphite scrim, about 1.0:1. Affects every bk/hero-photo-scrim
 * hero, including the live home and /about-us/. (0,4,2). */
body .wp-block-cover .wp-block-cover__inner-container p.bk-eyebrow.bk-eyebrow--onDark {
  color: var(--accent-primary);
}

/* 16c — Side gutter on full-width covers. Astra pads `.entry-content >
 * .wp-block-cover` with --wp--custom--ast-default-block-*-padding, which
 * are blank on this site, so below the 1200px container the copy touched
 * the screen edge. Found on the photo hero (home hero included), then on
 * bk/cta-band covers (/licensing-consulting/, 29 Sep), so it covers every
 * full-width cover, not only .bk-hero-scrim. Desktop doesn't move. */
.entry-content > .wp-block-cover.alignfull {
  padding-inline: var(--gutter-inline);
}

/* 16d — Scrim on tablet and phone. --scrim-left fades to .18/.05 at the
 * right, and below 921px the copy spans the full width, so white text ran
 * over a nearly bare photo (lead 3.70:1 at 390 over Plantings.jpg).
 * Drawing the same token over twice the width keeps its dark half:
 * minimum 5.2:1 at 390. Cover heroes only; the post hero has its own. */
@media (max-width: 921px) {
  .wp-block-cover.bk-hero-scrim::before { background-size: 200% 100%; }
}

/* 16e — Hero lead measure, opt-in on the lead paragraph. The 1200px inner
 * container let a lead run past the scrim onto the photo's bright side.
 * Two agents named it differently and both paste files use their own
 * name, so both classes are served here; prefer .bk-hero-scrim__lead. */
.bk-hero-scrim :is(.bk-hero-scrim__lead, .bk-hero-lead) {
  max-width: var(--post-hero-lead-max);
}

/* ============================================================
 * 17 — Cannabis Compliance page (ticket
 * 2026-09-27-triage-cannabis-compliance, 29 Sep 2026). Source:
 * "Cannabis Compliance Page Handover.dc.html" rev 1.0, §2 and §6.
 *
 * 17b and 17c are opt-in classes. (The anchor offset and hero lead
 * measure moved to 16a and 16e.)
 * ============================================================ */

/* 17b — Linked card: the whole card is the link target.
 * <div class="bk-card bk-card--pad-lg bk-card--interactive bk-card--link">
 *   <span class="bk-iconbadge …">…</span>
 *   <h3 class="bk-card__title"><a href="#…">Title</a></h3>
 *   <p class="bk-card__body">…</p>
 *   <span class="bk-card__cue" aria-hidden="true">Learn More</span>
 * </div>
 * The title's link is stretched over the card, so the link's accessible
 * name is the title and the visible "Learn More" is a cue, not a second
 * link. It's a separate modifier because the services page's
 * --interactive cards hold a .bk-btn, which a flex column would stretch.
 * Title rules are (0,3,0), over Astra's `.entry-content :where(h3)`
 * (0,1,0) size and 20px bottom margin. */
.bk-card--link {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  height: 100%;
}
.bk-card.bk-card--link .bk-card__title {
  margin: var(--space-5) 0 0;
  font-size: var(--type-h4-size);
  line-height: var(--type-h4-lh);
  letter-spacing: var(--type-h4-ls);
}
.bk-card--link .bk-card__title a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius-card);
}
.bk-card.bk-card--link .bk-card__title a:focus-visible { outline: none; }
.bk-card.bk-card--link .bk-card__title a:focus-visible::after { box-shadow: var(--shadow-focus); }
.bk-card--link .bk-card__cue {
  margin-top: auto;
  padding-top: var(--space-5);
  font-family: var(--font-display);
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-lh);
  font-weight: var(--fw-bold);
  color: var(--text-link);
}
.bk-card--link:hover .bk-card__cue {
  text-decoration: underline;
  text-underline-offset: .2em;
}

/* 17c — Item list: a group .bk-item-list of core heading (h3) and
 * paragraph pairs, one sentence each, with a hairline between items. No
 * bullets and no bold labels (handover §2, band C). Core blocks rather
 * than Custom HTML, so the copy stays editable. (0,2,1) beats Astra's
 * `.entry-content :where(h3)` and core's `:root :where(.is-layout-flow) > *`
 * (both 0,1,0). */
.wp-block-group.bk-item-list { margin-top: var(--space-6); }
.wp-block-group.bk-item-list > h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--type-h4-size);
  line-height: var(--type-h4-lh);
  letter-spacing: var(--type-h4-ls);
  font-weight: var(--fw-bold);
  color: var(--text-strong);
}
.wp-block-group.bk-item-list > p {
  margin: var(--space-2) 0 0;
  font-size: var(--type-body-size);
  line-height: var(--type-body-lh);
  color: var(--text-body);
}
.wp-block-group.bk-item-list > p + h3 {
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: var(--border-width) solid var(--border-hairline);
}

/* ============================================================
 * 18 — METRC Compliance page (to-theme ticket
 * 2026-09-27-triage-metrc-compliance, 29 Sep 2026).
 *
 * Source: METRC Compliance Page Handover.dc.html rev 1.0, plus the
 * ticket's SEO-COPY.md rev 2 (sections 5b and 8b). Each rule keys off a
 * class, not the page, so any page can use it. (The anchor offset and
 * hero eyebrow fix moved to 16a and 16b.)
 * ============================================================ */

/* 18b — Hairline between two white bands (handover §2: "a hairline
 * --border-hairline rule at container width, not a third band colour").
 * Put .bk-section--rule on the second band. The rule sits on the band's
 * top edge, as wide as the band's content: 2's container inside 6a's
 * gutter. */
.bk-section.bk-section--rule {
  position: relative;
}
.bk-section.bk-section--rule::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: min(var(--container-max), calc(100% - 2 * var(--gutter-inline)));
  transform: translateX(-50%);
  border-top: var(--border-width) solid var(--border-hairline);
}

/* 18c — Proof bar: four stats across, two below 782px (core's columns
 * breakpoint), per handover §3 section 2. 14e's auto-fit grid drops to
 * one column at 390px, so this fixes the count instead. */
.bk-stat-grid.bk-stat-grid--4up {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 781px) {
  .bk-stat-grid.bk-stat-grid--4up {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-6);
  }
}

/* 18d — Text link: put .bk-textlink on the paragraph that holds a lone
 * link. It's a plain --text-link link, not a button, and its box meets
 * the 44px tap target (handover §5, "including the text links in
 * section 3"). (0,1,1) ties Astra's `a:hover, a:focus` and wins on order. */
.bk-textlink {
  margin: var(--space-3) 0 0;
}
.bk-textlink > a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-target);
  font-family: var(--font-display);
  font-size: var(--type-body-sm-size);
  font-weight: var(--fw-semibold);
  color: var(--text-link);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.bk-textlink > a:hover {
  color: var(--text-link-hover);
}

/* 18e — Prose table: <table class="bk-table bk-table--prose"> for tables
 * with a sentence in every cell. The row label is <th scope="row"> in
 * Montserrat 700 (handover §3 section 6, SEO-COPY 5b), not the
 * component's caps header face. Headers may wrap, since nowrap caps
 * headers starve the text columns on a phone, and cells align to the top
 * so a short label doesn't float beside a three-line cell. */
.bk-table--prose th {
  white-space: normal;
}
.bk-table--prose :is(th, td) {
  vertical-align: top;
}
.bk-table--prose tbody th[scope="row"] {
  border-bottom: var(--border-width) solid var(--border-hairline);
  font-family: var(--font-display);
  font-size: var(--type-body-sm-size);
  letter-spacing: normal;
  text-transform: none;
  font-weight: var(--fw-bold);
  color: var(--text-strong);
}
/* On a phone, three prose columns share about 340px. Narrower cell padding
 * gives the text columns back 24px each, rather than scrolling sideways. */
@media (max-width: 781px) {
  .bk-table--prose :is(th, td) {
    padding-inline: var(--space-2);
  }
  .bk-table--prose tr > :first-child {
    padding-inline-start: 0;
  }
}

/* 18f — Inline links on a dark band. Astra's `a { color: leaf-700 }` is
 * about 3.3:1 on graphite-900, so links in dark-band copy read white and
 * underlined, with leaf on hover. (0,1,2) and (0,2,2) beat Astra's `a`
 * and `a:hover`. */
.bk-section--dark :is(p, li) a {
  color: var(--text-inverse);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.bk-section--dark :is(p, li) a:hover {
  color: var(--accent-primary);
}

/* ============================================================
 * 19 — California Compliance page — ticket
 * 2026-09-27-triage-california-cannabis-compliance (29 Sep 2026).
 *
 * Source: California Compliance Page Handover.dc.html, rev 1.0. Three
 * small pieces the page's patterns can't do as shipped. (Its hero lead
 * measure and side gutter moved to 16e and 16c.) All three are
 * written for any page, not keyed to this one.
 * ============================================================ */

/* CA-a — Feature grid: <div class="bk-feature-grid"> of
 * <div class="bk-card bk-card--flat bk-card--pad-lg"> cards, each an icon
 * badge, an <h3 class="bk-card__title"> and a <p class="bk-card__body">.
 * At most three columns, so five items wrap 3 + 2 on desktop (handover
 * §3.3), then 2-up and 1-up as the row narrows. core/columns can't wrap
 * like that: it keeps every column on one row above 782px.
 *
 * The h3 is the handover's outline (§4). Astra's `.entry-content :where(h3)`
 * (0,1,0) and our h3 rule (§4) would size it as an h3 and give it Astra's
 * margins, so the title is reset to the card title's h4 step at (0,3,1).
 *
 *   --feature-grid-min   a card's floor before the grid drops a column */
:root {
  --feature-grid-min: 280px;
}
.bk-feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, max(var(--feature-grid-min), calc((100% - 2 * var(--space-5)) / 3))), 1fr));
  gap: var(--space-5);
}
.bk-feature-grid > .bk-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}
:is(.entry-content, .is-root-container) .bk-feature-grid h3.bk-card__title {
  margin: var(--space-2) 0 0;
  font-size: var(--type-h4-size);
  line-height: var(--type-h4-lh);
  letter-spacing: var(--type-h4-ls);
}
:is(.entry-content, .is-root-container) .bk-feature-grid .bk-card__body {
  margin: 0;
}

/* CA-b — FAQ question as a heading. The handover (§3.6, §4) wants each
 * question to be an h3, so the accordion's <summary class="bk-card__title">
 * wraps an <h3 class="bk-faq__q">. Summary is display:list-item, so a
 * block h3 inside it would drop below the disclosure marker; inline keeps
 * them on one line. The h3 takes the summary's type, not Astra's h3 size.
 * (0,2,3) beats `.entry-content :where(h3)` (0,1,0). */
:is(.entry-content, .is-root-container) details > summary > h3.bk-faq__q {
  display: inline;
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
}

/* CA-c — A link in a stat's note on a dark band ("Held by our clients
 * since 2019" -> /california-cannabis-licensing/). Astra's link colour is
 * leaf-700, about 3:1 on graphite-900. The note keeps its own colour and
 * is underlined; hover and focus go white. (0,2,1) ties
 * `.ast-single-post .entry-content a` and wins on order. */
.bk-stat--onDark .bk-stat__note a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.bk-stat--onDark .bk-stat__note a:is(:hover, :focus-visible) {
  color: var(--bk-white);
}

/* ============================================================
 * 20 — California Licensing page (ticket
 * 2026-09-27-triage-california-cannabis-licensing, California Licensing
 * Page Brief rev 1.2, 27 Sep 2026). Two layout utilities the brief's blocks
 * need and core blocks can't express. (Its hero fixes moved to 16b–16d.) Both are site-wide and page-agnostic.
 * No new tokens.
 * ============================================================ */

/* 20a — Four-up grid: 4 across, 2x2 from the 921px tablet breakpoint, 1-up
 * at 560px and below. A core Columns block goes straight from 4 to 1 at
 * 782px, and the brief (§5) asks for 2x2 on tablet. An auto-fit grid
 * (.bk-stat-grid) would give 3 + 1 there. Custom HTML
 * <div class="bk-grid-quad"> of .bk-stat or .bk-card children. */
.bk-grid-quad {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-6);
}
@media (max-width: 921px) {
  .bk-grid-quad { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .bk-grid-quad { grid-template-columns: minmax(0, 1fr); }
}
/* Stat labels are 12px caps; --text-muted on the sunken band is 4.34:1,
 * under AA (as 14c). Body text colour is. */
.bk-section--sunken .bk-grid-quad .bk-stat__label { color: var(--text-body); }

/* 20b — Narrow measure, left-aligned: a flow-layout group
 * <div class="wp-block-group bk-measure"> inside a constrained section.
 * The group spans the 1200 container; its children stop at the 720px
 * measure and stay on the container's left edge, where core's constrained
 * layout would centre them (and its "justifyContent":"left" would pin them
 * to the viewport gutter instead). */
.bk-measure > * { max-width: var(--container-narrow); }

/* ============================================================
 * 21 — Licensing Consulting page (2026-09-27-triage-licensing-consulting),
 * four-up rows (W-19).
 *
 * /licensing-consulting/ has a four-step process row and a four-stat
 * band, and the handover wants them 4 across at 1440, 2 at 768 and 1 at
 * 390. Core columns can't do the middle step: below 782px core forces
 * every column to flex-basis:100% with !important, so a four-column
 * row stacks straight to one.
 *
 * Put .bk-columns-4 on the core/columns block (Additional CSS class)
 * and the block becomes a grid. Grid ignores flex-basis and flex-wrap,
 * so core's !important rules stop mattering and nothing here needs one.
 * The columns' blockGap still spaces the grid, because gap works for
 * both. The breakpoints are Astra's own (921 tablet, 544 mobile), the
 * same ones §6a uses, so this adds no breakpoint system.
 *
 * (0,2,0) beats core's .wp-block-columns{display:flex} (0,1,0) and the
 * layout engine's body .is-layout-flex (0,1,1).
 * ============================================================ */
.wp-block-columns.bk-columns-4 {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 921px) {
  .wp-block-columns.bk-columns-4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 544px) {
  .wp-block-columns.bk-columns-4 {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* Cards in a row share a height, so a two-line body doesn't leave a
 * short white card next to a tall one on the sunken band. */
.bk-columns-4 > .wp-block-column > .bk-card {
  height: 100%;
}

/* ============================================================
 * 22 — Calculator hero and calculator
 *      (2026-09-27-triage-metrc-cost-savings-calculator, 29 Sep 2026).
 *
 * METRC Calculator Page Handover rev 1.0, §3 row 01, §4 and §7.
 * Markup: patterns/calculator-hero.php (bk/calculator-hero, generic, for
 * the ROI calculator too), template-parts/calculator-metrc.php and
 * -method.php. Behaviour: assets/js/calculator.js.
 * ============================================================ */

/* 22a — The hero grid: copy 5/12, card 7/12, stacked (copy first) below
 * the design system's 921px breakpoint. A grid on a group rather than core
 * Columns, which only stack at 781px. The flow layout's top margin on the
 * card would push it down beside the copy, so it's zeroed: (0,2,0) beats
 * core's :root :where(.is-layout-flow) > * (0,1,0). */
.bk-calc-hero {
  display: grid;
  gap: var(--space-9);
  align-items: start;
}
.bk-section .bk-calc-hero > * { margin-block: 0; }
@media (min-width: 922px) {
  .bk-calc-hero {
    grid-template-columns: 5fr 7fr;
    gap: var(--space-10);
  }
}

/* Links to #calculator land with a little air above the card (16a). */
.bk-calc-hero__card[id] { scroll-margin-top: var(--anchor-offset); }

/* The card title ("Your Operation") is an h2 at h3 size. (0,2,0) beats
 * Astra's .entry-content :where(h2) (0,1,0). */
.bk-calc-hero .bk-calc-hero__title {
  margin: 0;
  font-size: var(--type-h3-size);
  line-height: var(--type-h3-lh);
  letter-spacing: var(--type-h3-ls);
}

/* 22b — Inputs. Two columns for fields 1-2 and 4-5 once the card is wide
 * enough, rate full width. Each field is a subgrid of its four rows (label,
 * control, hint, error) so paired inputs line up when one label wraps. */
.bk-calc { container-type: inline-size; }
.bk-calc__fields {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
}
@container (min-width: 30rem) {
  .bk-calc__fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bk-calc__field {
    display: grid;
    grid-row: span 4;
    grid-template-rows: subgrid;
    row-gap: 6px;
    align-content: start;
  }
  .bk-calc__field .bk-field__label { align-self: end; }
}
.bk-calc__field--wide { grid-column: 1 / -1; }

/* Hint and error are <p>: Astra's p { margin-bottom: 1.75em } (0,0,1). */
.bk-calc :is(.bk-field__hint, .bk-field__error, .bk-calc__prompt) { margin: 0; }

/* .bk-input again, because Astra's input[type=number] (0,1,1) outranks
 * .bk-input (0,1,0) on colour, padding, height, border and background.
 * Values are components.css's own. The invalid border yields to the focus
 * border, as components.css's (0,2,0) :focus over (0,1,0) --invalid does. */
.bk-calc .bk-input {
  height: var(--tap-target);
  padding: 0 var(--space-3);
  color: var(--text-strong);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-control);
  transition: var(--transition-control);
  font-variant-numeric: tabular-nums;
}
.bk-calc .bk-input--invalid:not(:focus) { border-color: var(--bk-violation); }

/* Labels and hints inherit Astra's body line height (about 1.6 of 17px),
 * which spaced 13px text like a paragraph. The type tokens' own. */
.bk-calc .bk-field__label { line-height: var(--type-label-lh); }
.bk-calc :is(.bk-field__hint, .bk-field__error) { line-height: var(--type-caption-lh); }

/* 22c — Rate: a $ prefix inside the input, and the Per Hour / Per Year
 * toggle (.bk-tabs--pill) beside it, wrapping below on a phone. */
.bk-calc__control {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
}
.bk-calc__money {
  position: relative;
  flex: 1 1 10rem;
}
.bk-calc__affix {
  position: absolute;
  left: var(--space-3);
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
  pointer-events: none;
}
.bk-calc .bk-calc__money .bk-input { padding-left: var(--space-7); }

/* The toggle is two radios in <label class="bk-tabs__tab">, so arrow keys
 * move between them natively. Each label is the 44px target; the white
 * active pill sits 4px inside it (transparent border, padding-box
 * background), so the pill keeps its look at the input's height. */
.bk-calc__unit {
  flex: none;
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.bk-calc__unit .bk-tabs__tab {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-target);
  padding: 0 var(--space-4);
  border: 4px solid transparent;
  background-clip: padding-box;
  font-size: var(--type-body-sm-size);
  white-space: nowrap;
}
.bk-calc__unit .bk-tabs__tab--active { box-shadow: none; }
.bk-calc__unit input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.bk-calc__unit .bk-tabs__tab:has(input:focus-visible) { box-shadow: var(--shadow-focus); }

/* 22d — Results: a hairline, three costs, then total beside the savings
 * range. Tabular figures so values don't jitter while typing. */
.bk-calc__results {
  margin-top: var(--space-6);
  padding-top: var(--space-6);
  border-top: var(--border-width) solid var(--border-hairline);
}
.bk-calc__prompt {
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-lh);
  color: var(--text-muted);
}
.bk-calc__output:not([hidden]) {
  display: grid;
  gap: var(--space-6);
}
.bk-calc__costs {
  display: grid;
  gap: var(--space-4);
}
@container (min-width: 30rem) {
  .bk-calc .bk-calc__costs { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.bk-calc__totals {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5) var(--space-8);
  padding-top: var(--space-5);
  border-top: var(--border-width) solid var(--border-hairline);
}
.bk-calc .bk-calc__value {
  font-size: var(--type-h2-size);
  line-height: var(--type-h2-lh);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.bk-calc .bk-calc__value--metric {
  font-size: var(--type-metric-size);
  line-height: var(--type-metric-lh);
}
/* The range may break at the dash, never inside a figure. */
.bk-calc .bk-stat__value--brand { white-space: normal; }
.bk-calc .bk-stat__value--brand > span { white-space: nowrap; }
.bk-calc .bk-stat__value--brand > .bk-calc__dash { white-space: normal; }
.bk-calc__output:not([hidden]),
.bk-calc__costs { grid-template-columns: minmax(0, 1fr); }
.bk-calc .bk-stat__note a { color: var(--text-link); }

/* 22e — The email step: a group .bk-calc-email after the calculator,
 * holding Gravity Forms. Hidden until the calculator has a full result
 * (data-bk-calc-state="ready", set by calculator.js), so it never shows
 * before the numbers it would send, or with savings still pending. */
.bk-calc-email { display: none; }
[data-bk-calc-state="ready"] .bk-calc-email {
  display: block;
  padding-top: var(--space-6);
  border-top: var(--border-width) solid var(--border-hairline);
}
.bk-calc-email h3 {
  margin: 0 0 var(--space-4);
  font-size: var(--type-h4-size);
  line-height: var(--type-h4-lh);
}
/* The booking link moves into the form footer, beside Email My Estimate. */
.bk-calc-email .gform_wrapper.gform-theme--orbital .gform_footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.bk-calc-email .bk-calc-email__call { margin: var(--space-4) 0 0; }
.bk-calc-email .gform_footer .bk-btn { margin: 0; }
/* A bare a.bk-btn in content: Astra's .ast-single-post .entry-content a (0,2,1) underlines
 * it; (0,3,1) here. Its link colour loses to (0,2,0). components.css's :hover rules (0,3,0) still win. */
.bk-calc-hero .bk-calc-email a.bk-btn { text-decoration: none; }
.bk-calc-email .bk-btn--secondary { color: var(--bk-leaf-800); }

/* 22f — The method table (row 02). Row headers read as the bucket name,
 * not as a caps column header; pending factors read as muted. */
.bk-calc-method tbody th {
  font-family: var(--font-body);
  font-size: var(--type-body-sm-size);
  letter-spacing: 0;
  text-transform: none;
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
  white-space: normal;
  border-bottom: var(--border-width) solid var(--border-hairline);
  vertical-align: top;
}
.bk-calc-method td { vertical-align: top; }
.bk-calc-method td[data-bk-pending] { color: var(--text-muted); font-style: italic; }

/* 22g — FAQ rows as 44px+ targets. In bk/faq-accordion only the summary's
 * text line (about 23px) toggles a row. With .bk-faq__item (which also
 * feeds inc/faq-schema.php) the card's padding moves onto the summary, so
 * the whole row is the target. Only markup carrying the class changes. */
.bk-faq .bk-faq__item.bk-card { padding: 0; }
.bk-faq .bk-faq__item > summary { padding: var(--space-6); }
.bk-faq .bk-faq__item > p {
  margin: 0;
  padding: 0 var(--space-6) var(--space-4);
}
.bk-faq .bk-faq__item > p:last-child { padding-bottom: var(--space-6); }

/* ============================================================
 * 23 — BaykedFarm ROI calculator and its page
 *      (2026-09-27-triage-baykedfarm-roi-calculator, 29 Sep 2026).
 *
 * BaykedFarm ROI Calculator Handover rev 1.0, §3 and §4. Markup:
 * patterns/roi-calculator.php (bk/roi-calculator) and
 * template-parts/calculator-roi.php. Behaviour: assets/js/calculator.js
 * (engine) and roi-calculator.js (model). The form also carries .bk-calc,
 * so 22b's field grid and input and label fixes, and 22d's range
 * wrapping, apply unchanged; only what differs is here. 23d–23g are
 * page-agnostic classes the ROI page's paste uses. No new tokens; the one
 * literal is 22a's 921px breakpoint, which a media query can't take as a
 * variable.
 * ============================================================ */

/* 23a — Two peer cards, inputs 7/12 and results 5/12, stacked (inputs
 * first) below 921px. Not sticky: the system allows no fixed element but
 * the header (handover §4, "Layout"). The form is no longer 22b's size
 * container; the inputs card is, so the fields answer to its width. */
.bk-roi {
  display: grid;
  gap: var(--space-6);
  align-items: start;
  margin-top: var(--space-7);
  container-type: normal;
}
@media (min-width: 922px) {
  .bk-roi { grid-template-columns: 7fr 5fr; }
}
.bk-roi__inputs { container-type: inline-size; }

/* 23b — Three groups under --type-label subheads. A <fieldset> per group,
 * reset to no box; the legend is the subhead. Space between groups, not a
 * rule: a fieldset draws its legend inside its top border, so a hairline
 * there runs through the subhead. */
.bk-roi__group {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.bk-roi__group + .bk-roi__group { margin-top: var(--space-7); }
.bk-roi .bk-roi__legend {
  margin: 0 0 var(--space-4);
  padding: 0;
  font-family: var(--font-display);
  font-size: var(--type-label-size);
  line-height: var(--type-label-lh);
  letter-spacing: var(--type-eyebrow-ls);
  text-transform: uppercase;
  font-weight: var(--fw-bold);
  color: var(--text-brand);
}
/* These fields have no hint: three subgrid rows (label, input, error), not
 * 22b's four. (0,2,0) over 22b's (0,1,0). */
@container (min-width: 30rem) {
  .bk-roi .bk-calc__field { grid-row: span 3; }
}
.bk-roi__submit { margin: var(--space-6) 0 0; }

/* 23c — The results card. Its parts stack with even spacing; the headline
 * is the component's metric size, the savings range one step down so a
 * six-figure range fits the 5/12 card. */
.bk-roi__results,
.bk-roi__output:not([hidden]) {
  display: grid;
  gap: var(--space-6);
}
.bk-roi .bk-roi__total {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.bk-roi .bk-roi__range {
  font-size: var(--type-h1-size);
  line-height: var(--type-h1-lh);
  font-variant-numeric: tabular-nums;
}

/* The breakdown: a .bk-table on dark. components.css colours it for white
 * (body text, graphite-200 rules, a leaf-050 hover), so each is restated
 * for graphite-900. (0,3,1) beats 12's `.bk-table :is(th, td)` and
 * components.css's `.bk-table td` and `tbody tr:hover`. */
.bk-roi .bk-roi__table { margin: 0; }
.bk-roi .bk-roi__table :is(th, td) {
  padding: var(--space-3) 0;
  border-bottom: var(--border-width) solid var(--bk-graphite-700);
  font-size: var(--type-body-sm-size);
  color: var(--bk-graphite-200);
  background: none;
}
.bk-roi .bk-roi__table th[scope="row"] {
  font-family: var(--font-body);
  letter-spacing: normal;
  text-transform: none;
  font-weight: var(--fw-regular);
  white-space: normal;
}
.bk-roi .bk-roi__table td.bk-table__num { color: var(--bk-white); }
.bk-roi .bk-roi__table tbody tr:hover { background: none; }

/* The assumptions: a closed <details>. The summary is the 44px target,
 * with a chevron drawn from two borders rather than the UA marker. */
.bk-roi .bk-roi__method > summary {
  display: flex;
  align-items: center;
  min-height: var(--tap-target);
  list-style: none;
  cursor: pointer;
  font-family: var(--font-display);
  font-size: var(--type-body-sm-size);
  font-weight: var(--fw-semibold);
  color: var(--bk-white);
}
.bk-roi .bk-roi__method > summary::-webkit-details-marker { display: none; }
.bk-roi .bk-roi__method > summary::before {
  content: "";
  flex: none;
  width: var(--space-2);
  height: var(--space-2);
  margin-right: var(--space-3);
  border-right: var(--border-width-strong) solid currentColor;
  border-bottom: var(--border-width-strong) solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--dur-fast) var(--ease-standard);
}
.bk-roi .bk-roi__method[open] > summary::before { transform: rotate(45deg); }
.bk-roi .bk-roi__method ul {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  padding-left: var(--space-5);
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-lh);
  color: var(--bk-graphite-200);
}
.bk-roi .bk-roi__method strong {
  font-weight: var(--fw-semibold);
  color: var(--bk-white);
}
.bk-roi__const--pending { font-style: italic; }

/* The CTA under the results. A bare a.bk-btn in content: Astra underlines
 * content links at (0,2,1); (0,3,1) here, as 22e does. */
.bk-roi__cta { margin: 0; }
.bk-roi .bk-roi__cta a.bk-btn { text-decoration: none; }

/* 23d — Step number: a mono "01" above a card title, in place of an icon
 * badge (handover §3 row 5). <p class="bk-step-num">01</p> as the card's
 * first child. (0,1,1) with the :is() over Astra's p margin. */
:is(.entry-content, .is-root-container) .bk-step-num {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
  line-height: var(--type-mono-lh);
  letter-spacing: var(--type-mono-ls);
  font-weight: var(--fw-semibold);
  color: var(--text-brand);
}

/* 23e — Yes / No in a comparison cell: a check or remove glyph beside the
 * word, never a glyph alone (handover §2, the unicode ✓ ✗ row). Custom
 * HTML <span class="bk-yesno bk-yesno--yes">icon Yes</span>. */
.bk-yesno {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.bk-yesno--yes .bk-icon { color: var(--text-brand); }
.bk-yesno--no .bk-icon { color: var(--text-muted); }

/* 23f — Stat notes on a light band. components.css sets them in
 * --text-faint, 2.8:1 on white; muted is AA (as 15g does for stat cards).
 * .bk-stat__note--mono sets a note in the mono face, for data such as
 * hours ("support hours as .bk-stat__note in mono", handover §3 row 7). */
.bk-stat-grid > .bk-stat:not(.bk-stat--onDark) .bk-stat__note { color: var(--text-muted); }
.bk-stat__note--mono {
  font-family: var(--font-mono);
  font-size: var(--type-mono-sm-size);
  line-height: var(--type-mono-sm-lh);
}
.bk-stat-grid .bk-stat__note { line-height: var(--type-caption-lh); }

/* 23g — A comparison table fills its scroll card: Astra's table
 * margin-bottom left an empty strip under the last row. */
.bk-table-scroll > .bk-table--compare { margin: 0; }

/* ============================================================
 * 24 — Blog post components (OCM readiness post handover rev 1,
 * 1 Oct 2026, ticket 2026-10-01-triage-ocm-readiness-post; compliant
 * harvest METRC post handover rev 1, 1 Oct 2026, ticket
 * 2026-10-02-triage-compliant-harvest-metrc-post).
 *
 * Site-wide like 14 and 15, so a page or a later post can use them; the
 * checklist card and the product callout are also patterns
 * (bk/checklist-card, bk/product-callout). Scoped by
 * :is(.entry-content, .is-root-container) wherever blog.css's p, li, ul
 * and h3 rules (0,1,1) or core's flow gap (0,1,0) would otherwise win.
 * Layout pieces that only a post has (the sticky rail, the featured-image
 * caption, buttons in a post body) are in blog.css §6.
 * ============================================================ */

/* 24a — Tokens these handovers use that the design system doesn't have.
 * Requested upstream, as 14a's are.
 *
 *   --product-callout-photo-*  the callout's photo column: 240px wide,
 *                              280–340px tall beside the copy, 220px tall
 *                              stacked (compliant harvest §3.4)
 *   --stat-ruled-min           the ruled stat strip's auto-fit floor (§3.5)
 */
:root {
  --product-callout-photo-w: 240px;
  --product-callout-photo-min: 280px;
  --product-callout-photo-max: 340px;
  --product-callout-photo-stacked: 220px;
  --stat-ruled-min: 150px;
}

/* 24b — Numbered H2 (compliant harvest §3.3): <h2 id="tags"><span
 * class="bk-h2-num">01</span> Plant tags…</h2>. A mono prefix in the brand
 * colour on the heading's baseline. The space in the markup plus a
 * margin gives the gap, so the heading still reads "01 Plant tags…" to a
 * screen reader and in the RSS feed. */
.bk-h2-num {
  margin-inline-end: var(--space-1);
  font-family: var(--font-mono);
  font-size: var(--type-body-sm-size);
  font-weight: var(--fw-medium);
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  color: var(--text-brand);
  vertical-align: baseline;
}

/* 24c — Ruled pull line (OCM §3 band 3): the bk-pull-* block style plus
 * .bk-pull--ruled, a 2px leaf rule above and a hairline below. (0,3,0)
 * beats 14b's border/padding reset. */
:is(.entry-content, .is-root-container) :is(.is-style-bk-pull-lg, .is-style-bk-pull-md, .is-style-bk-pull-sm).bk-pull--ruled {
  margin-block: var(--space-9);
  padding-block: var(--space-7);
  border-top: var(--border-width-strong) solid var(--accent-primary);
  border-bottom: var(--border-width) solid var(--border-hairline);
}

/* 24d — Checklist card (OCM §8 item 1), the bk/checklist-card pattern.
 * Custom HTML: <div class="bk-card bk-card--pad-lg bk-checklist">, a head
 * row (sm icon badge + strong label, hairline under it) and a
 * <ul class="bk-checklist__list"> whose items each start with a check
 * icon. Static: no hover. Two columns from 560px, one below. The card
 * takes the article measure because it is a top-level block. */
:is(.entry-content, .is-root-container) .bk-checklist {
  margin-block: var(--space-6) var(--space-7);
}
.bk-checklist__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-bottom: var(--space-5);
  border-bottom: var(--border-width) solid var(--border-hairline);
}
.bk-checklist__label {
  font-family: var(--font-display);
  font-size: var(--type-eyebrow-size);
  line-height: var(--type-eyebrow-lh);
  letter-spacing: var(--type-eyebrow-ls);
  text-transform: uppercase;
  font-weight: var(--fw-bold);
  color: var(--text-strong);
}
:is(.entry-content, .is-root-container) ul.bk-checklist__list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3) var(--space-7);
  margin: 0;
  padding: var(--space-5) 0 0;
  list-style: none;
}
@media (min-width: 560px) {
  :is(.entry-content, .is-root-container) ul.bk-checklist__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
:is(.entry-content, .is-root-container) ul.bk-checklist__list > li {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
  font-size: var(--type-body-size);
  line-height: var(--type-body-lh);
  color: var(--text-body);
}
.bk-checklist__list .bk-icon { color: var(--text-brand); }

/* 24e — Product callout (compliant harvest §3.4), the bk/product-callout
 * pattern. Custom HTML: <aside class="bk-product-callout"> holding an
 * <img class="bk-product-callout__photo"> and a body div (plain eyebrow,
 * title, one line, a secondary button). A card on the sunken ground: the
 * photo a fixed 240px column, 280–340px tall, cropped at 60% 45%; the copy
 * centred beside it. Below 720px the photo stacks on top, full width and
 * 220px tall. The card isn't interactive; the button carries the states. */
:is(.entry-content, .is-root-container) .bk-product-callout {
  display: flex;
  overflow: hidden;
  margin-block: var(--space-8);
  border: var(--border-width) solid var(--border-hairline);
  border-radius: var(--radius-xl);
  background: var(--surface-sunken);
}
.bk-product-callout__photo {
  display: block;
  flex: 0 0 var(--product-callout-photo-w);
  width: var(--product-callout-photo-w);
  max-width: 100%;
  height: auto;
  min-height: var(--product-callout-photo-min);
  max-height: var(--product-callout-photo-max);
  align-self: stretch;
  object-fit: cover;
  object-position: 60% 45%;
}
.bk-product-callout__body {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-7);
}
:is(.entry-content, .is-root-container) .bk-product-callout p { margin: 0; }
:is(.entry-content, .is-root-container) .bk-product-callout p.bk-product-callout__title {
  font-family: var(--font-display);
  font-size: var(--type-h3-size);
  line-height: var(--type-h3-lh);
  letter-spacing: var(--type-h3-ls);
  font-weight: var(--fw-bold);
  color: var(--text-strong);
}
:is(.entry-content, .is-root-container) .bk-product-callout p.bk-product-callout__text {
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-lh);
  color: var(--text-muted);
}
.bk-product-callout__body .bk-btn { margin-top: var(--space-2); }
/* On a page, Astra's .entry-content a (0,2,1) would underline the button. */
:is(.entry-content, .is-root-container) .bk-product-callout a.bk-btn { text-decoration: none; }
@media (max-width: 719px) {
  :is(.entry-content, .is-root-container) .bk-product-callout { flex-direction: column; }
  .bk-product-callout__photo {
    flex: none;
    width: 100%;
    height: var(--product-callout-photo-stacked);
    min-height: 0;
    max-height: none;
  }
  .bk-product-callout__body { padding: var(--space-6); }
}

/* 24f — Ruled stat strip (compliant harvest §3.5): .bk-stat-grid
 * .bk-stat-grid--ruled, tiles on white divided by hairlines inside one
 * bordered card. The 1px gap shows the hairline background between tiles.
 * One column below 560px, so a lone third tile never leaves an empty grey
 * cell beside it. The attribution under it is p.bk-stat-source. */
:is(.entry-content, .is-root-container) .bk-stat-grid.bk-stat-grid--ruled {
  --stat-grid-min: var(--stat-ruled-min);
  gap: var(--border-width);
  overflow: hidden;
  margin-block: var(--space-8) var(--space-3);
  border: var(--border-width) solid var(--border-hairline);
  border-radius: var(--radius-card);
  background: var(--border-hairline);
}
@media (max-width: 559px) {
  :is(.entry-content, .is-root-container) .bk-stat-grid.bk-stat-grid--ruled { grid-template-columns: minmax(0, 1fr); }
}
.bk-stat-grid--ruled > .bk-stat {
  padding: var(--space-6);
  background: var(--surface-card);
}
.bk-stat-grid--ruled .bk-stat__value {
  font-size: var(--type-h1-size);
  line-height: var(--type-h1-lh);
  font-variant-numeric: tabular-nums;
}
:is(.entry-content, .is-root-container) p.bk-stat-source {
  margin: 0 0 var(--space-8);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-lh);
  color: var(--text-muted);
}

/* ============================================================
 * 25 — Homepage, /services/ hub, header button and footer menus
 * (homepage handover rev 1, 3 Oct 2026; ticket
 * 2026-10-03-triage-homepage-nav-footer, T-1 to T-5).
 *
 * Checked, not added: T-3 links in a dark stat band are 18f's (white,
 * underlined, leaf on hover) when they sit in a <p>; the paste puts each
 * tile's link in a p.bk-textlink. T-5 anchor offsets are 16a's
 * (.bk-section[id]); #what-we-do and #tools go on the band groups.
 * ============================================================ */

/* 25a — Hero proof line (T-2): Montserrat 700 under the H1, white.
 * The handover asked for leaf-500 if it reaches 4.5:1 at 18px/700, which
 * is under the large-text threshold. It can't: 16d measured the darkest
 * the scrim keeps the background behind hero copy at 390px, a background
 * on which white is 5.2:1, and leaf-500 (#8ac340, luminance 0.45) is about
 * 2.5:1 there. So white, the handover's fallback. Colour comes from the
 * block's bk-white text colour (16b's Astra cover-p trap); this sets type. */
.wp-block-cover .wp-block-cover__inner-container p.bk-hero-proof {
  font-family: var(--font-display);
  font-size: var(--type-h4-size);
  line-height: var(--type-h4-lh);
  font-weight: var(--fw-bold);
}

/* 25b — Proof strip: .bk-stat-grid--4up.bk-stat-grid--ruled. Four across,
 * 2 × 2 below 782px (24f alone drops a ruled strip to one column under
 * 560px). Under 560px a tile is about 170px wide, so values step down to
 * h3 size to keep "340,000+" on one line. (0,4,0) beats 24f's (0,3,0). */
:is(.entry-content, .is-root-container) .bk-stat-grid.bk-stat-grid--ruled.bk-stat-grid--4up {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 781px) {
  :is(.entry-content, .is-root-container) .bk-stat-grid.bk-stat-grid--ruled.bk-stat-grid--4up {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 559px) {
  .bk-stat-grid--ruled.bk-stat-grid--4up > .bk-stat { padding: var(--space-4); }
  .bk-stat-grid--ruled.bk-stat-grid--4up .bk-stat__value {
    font-size: var(--type-h3-size);
    line-height: var(--type-h3-lh);
  }
}

/* 25c — Inline stats in a split row (3A–3C): Custom HTML
 * <div class="bk-inline-stats"> of .bk-inline-stat, each a value and a
 * label, between hairlines. Auto-fit, so two or three sit in a row and
 * wrap on a phone. */
.bk-inline-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 140px), 1fr));
  gap: var(--space-4) var(--space-6);
  margin-block: var(--space-6);
  padding-block: var(--space-4);
  border-block: var(--border-width) solid var(--border-hairline);
}
.bk-inline-stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.bk-inline-stat__value {
  font-family: var(--font-display);
  font-size: var(--type-h2-size);
  line-height: var(--type-h2-lh);
  font-weight: var(--fw-black);
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
  white-space: nowrap;
}
.bk-inline-stat__label {
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-lh);
  color: var(--text-muted);
}

/* 25d — A text link (18d) with a trailing arrow_forward icon. A run of
 * text links stacks as 44px rows: Astra's p bottom margin (0,1,1) plus
 * 18d's top margin had put about 70px between them. */
.bk-textlink > a { gap: var(--space-1); }
.bk-textlink > a > .bk-icon { flex: none; }
:is(.entry-content, .is-root-container) p.bk-textlink:has(+ p.bk-textlink) { margin-bottom: 0; }
:is(.entry-content, .is-root-container) p.bk-textlink + p.bk-textlink { margin-top: 0; }

/* 25e — Attribution / caption line under a figure on a page: caption size,
 * muted. (0,2,1) beats Astra's entry-content p. */
:is(.entry-content, .is-root-container) p.bk-caption {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-lh);
  color: var(--text-muted);
}

/* 25f — Two testimonial cards (T-4): put .bk-columns--narrow on the
 * pattern's Columns block. Centred at 980px; core still stacks it below
 * 782px. No pattern change: patterns are snapshots. */
.wp-block-columns.bk-columns--narrow {
  max-width: 980px;
  margin-inline: auto;
}

/* 25g — Interest links under a CTA band's button: p.bk-cta-links, with the
 * block's bk-white text colour. The handover drew leaf-500 links; on the
 * 70% overlay over a bright sky that is under 3:1, so they are white and
 * underlined like 18f, leaf on hover. (0,4,2) beats Astra's cover link
 * colour, as 16b does for the eyebrow. */
body .wp-block-cover .wp-block-cover__inner-container p.bk-cta-links a {
  color: var(--text-inverse);
  text-decoration: underline;
  text-underline-offset: 3px;
}
body .wp-block-cover .wp-block-cover__inner-container p.bk-cta-links a:hover {
  color: var(--accent-primary);
}

/* 25h — Header button: the menu item with CSS class bk-menu-cta
 * (Appearance → Menus → CSS Classes) is a small primary pill, without
 * 9a's current-item underline. (0,5,0) and (0,6,0) beat 9a's (0,4,0) link
 * and (0,5,0) hover rules. */
.site-header .main-header-menu .menu-item.bk-menu-cta > .menu-link {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  margin-left: var(--space-3);
  padding: 0 var(--space-5);
  border-radius: var(--radius-button);
  background: var(--accent-primary);
  color: var(--accent-contrast);
  font-weight: var(--fw-bold);
  box-shadow: none;
}
.site-header .main-header-menu .menu-item.bk-menu-cta:hover > .menu-link,
.site-header .main-header-menu .menu-item.bk-menu-cta > .menu-link:is(:hover, :focus-visible) {
  background: var(--accent-primary-hover);
  color: var(--bk-white);
}

/* 25i — Footer link columns ([bk_footer_menus], inc/footer-menus.php).
 * Five columns beside the widget's brand column, three on a tablet, one
 * below 601px, where each column is a closed <details> row that opens on
 * tap (site.js initFooterMenus). Headings reuse 9b's .wp-block-heading
 * label style; items match 9b's list. */
.bk-footer-menus {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--space-6);
}
@media (max-width: 921px) {
  .bk-footer-menus { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.bk-footer-menu__head {
  display: block;
  list-style: none;
  cursor: default;
}
.bk-footer-menu__head::-webkit-details-marker { display: none; }
.site-footer .bk-footer-menu__title { margin: 0 0 var(--space-3); }
.site-footer .bk-footer-menu__list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.site-footer .bk-footer-menu__list li {
  margin: 0 0 var(--space-2);
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-lh);
}
@media (max-width: 600px) {
  .bk-footer-menus {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }
  .bk-footer-menu { border-top: var(--border-width) solid var(--border-hairline); }
  .bk-footer-menu:last-child { border-bottom: var(--border-width) solid var(--border-hairline); }
  .bk-footer-menu__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: var(--tap-target);
    cursor: pointer;
  }
  .site-footer .bk-footer-menu__title { margin: 0; }
  /* Chevron: a bordered square turned 45°, down when closed, up when open. */
  .bk-footer-menu__head::after {
    content: "";
    flex: none;
    width: 8px;
    height: 8px;
    margin: 0 var(--space-2) var(--space-1);
    border-right: var(--border-width-strong) solid var(--text-muted);
    border-bottom: var(--border-width-strong) solid var(--text-muted);
    transform: rotate(45deg);
    transition: transform var(--dur-fast) var(--ease-standard);
  }
  .bk-footer-menu[open] > .bk-footer-menu__head::after {
    margin-bottom: 0;
    transform: rotate(-135deg);
  }
  .site-footer .bk-footer-menu__list { padding-bottom: var(--space-4); }
  .site-footer .bk-footer-menu__list li a {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap-target);
  }
  .site-footer .bk-footer-menu__list li { margin: 0; }
}
.bk-footer-menu__head:focus-visible {
  outline: var(--border-width-strong) solid var(--focus-ring);
  outline-offset: 2px;
}

/* 25j — Photo first on a phone for a split row whose photo is the second
 * column (3B): put .bk-columns--photo-first on its Columns block. Core
 * stacks columns in source order below 782px, which would put the copy
 * above the photo; the handover wants the photo above everywhere. */
@media (max-width: 781px) {
  .wp-block-columns.bk-columns--photo-first { flex-direction: column-reverse; }
}

/* 25k — A value set in mono inside running text (support hours in the FAQ
 * and footer: "times in mono", handover R18). Not 14px: it sits in body
 * copy, so it keeps the surrounding size, as 15c's .bk-icon-row .bk-mono. */
.bk-mono {
  font-family: var(--font-mono);
  font-size: .92em;
}

/* 25l — A long hero H1 on a phone: .bk-hero-scrim--long on the cover
 * steps display-2 (48px) down to 32px at 600px and below (homepage
 * handover §3 band 1: "At 390px the H1 is 32px"). At 48px the 76-character
 * homepage H1 broke "Manufacturers" mid-word. Opt-in, so other heroes are
 * unchanged. The preset class carries !important, so this redefines the
 * preset's variable on the cover instead. */
@media (max-width: 600px) {
  .wp-block-cover.bk-hero-scrim--long { --wp--preset--font-size--bk-display-2: 32px; }
}
