/**
 * Footer component styles — patterns/footer/footer.css.
 *
 * Auto-enqueued by the pattern glob in includes/enqueue.php (handle
 * ftm-pattern-footer, dependency ftm-style) — nothing to register
 * (build-knowledge.md §1).
 *
 * Scheme paint follows build-knowledge.md §3: roles are applied as
 * var(--ftm-scheme-*) directly on the wrapper, NEVER via the scheme-bg /
 * scheme-text block colour presets (their :root var() freezes to white).
 * The header's primary-600 remap is scoped to .site-header and does not
 * reach here — this surface is the scheme's primary-800 navy.
 *
 * Icon convention (build-knowledge.md §6): contract-first with a theme
 * fallback — var(--ftps-icon-{slug}, var(--tc-icon-{slug})). The contract
 * layer is absent in ftm-blocks 3.0.0-beta.3, so the fallbacks are
 * load-bearing; keep them until the icon manifest ships.
 *
 * ── Frame verification, 2026-07-30 (docs/reports/footer-verify.md) ────────
 *
 * Measured against all four frames of component set 42864:7816 — Desktop
 * 42864:7813, Tablet 42864:7814, Smartphone 42864:7815, Smartphone/Open
 * 43887:32483. Geometry from the node tree, type/colour from
 * get_variable_defs, strokes from a hairline scan of the 2x exports.
 *
 * THE TYPE BLOCK BELOW IS A SCOPED STAND-IN for the inert theme typeStyles
 * (DECISIONS H2) and is load-bearing. Every text role in this footer was
 * inheriting from an unintended source before this pass: `h2`/`h3` element
 * rules resolving --wp--custom--type-styles--* (never emitted, so weight fell
 * to the design-system 400 and the column headings took the DISPLAY family
 * where the frames say Inter), `:root :where(.wp-element-button, …)
 * { font-weight: inherit }` on the CTA buttons, `font: inherit` on the
 * accordion toggle, and the FLUID title-small preset on the newsletter
 * heading where the frames are flat. Fifth surface to need this; do not
 * "simplify" it away until the theme layer works.
 *
 * FLAGGED DEVIATIONS from the frames (recorded in DECISIONS.md):
 *  - F1 IS CLOSED, 2026-08-06. Filled buttons are back on secondary-600, the
 *    value the frames draw. F1 existed only because white on the OLD
 *    secondary-600 (#0284C7) measured 4.10:1 and failed AA; the designer moved
 *    the token to #057DB9 on 2026-08-06 and white on it measures 4.53:1, which
 *    clears AA for normal text, so the 700 remap has no premise left.
 *    Frame value re-confirmed 2026-07-30 by sampling the fill: the frame's
 *    pixel is #0284C7, which WAS secondary-600 and is now one ADA-driven step
 *    off it. The BINDING is what ships, not the sampled hex.
 *  - F2: RESOLVED 2026-07-30 — --wp--custom--color--white-alpha--200 DOES
 *    exist in this Codespace and emits #ffffff33, exactly the frame's
 *    white-alpha-200. The literal fallback is now belt-and-braces only.
 *  - F6: the declared -2 letter-spacing on Heading/Small and Title/Small does
 *    not reproduce the drawn widths. Ink mass confirms weight 700 on both
 *    roles; at 700 the frames measure as tracking ~0, and applying -2%
 *    overshoots both by 13-15px. Shipped with tracking unset, the same call
 *    the drawer pass made about Label/Large's declared 0.2.
 *  - F7: the desktop frame's bottom padding is 76 where its own top padding,
 *    and both other breakpoints, are 64. Single-frame anomaly; 64 shipped.
 *
 * Social row placement (all three frames agree): the social-links block is
 * the FOURTH cell of the columns grid — tablet 2-up gives Company|Resources /
 * Support|Social, desktop gives 3 nav columns + icons top-aligned at the
 * right content edge, mobile stacks it after the accordion.
 *
 * Elementor coexistence: .elementor-kit-6637 button (0,1,1) styles every
 * bare <button>; the accordion-toggle resets below are load-bearing until
 * Elementor is removed (same trap as the header — build-knowledge.md §5).
 */

.site-footer {
	--tc-footer-cta-fill: var(--wp--custom--color--secondary--600); /* frames' value — F1 closed, see header comment */
	--tc-footer-cta-fill-hover: var(--wp--custom--color--secondary--800);
	--tc-footer-divider: var(--wp--custom--color--white-alpha--200, rgb(255 255 255 / 20%)); /* F2 */

	/* Section rhythm measured from the frames (re-measured 2026-07-30 against
	   all four): the band above the rule is 64 / 64 / 32 top and the band below
	   it 64 / 64 / 40 bottom — the two are NOT the same value on mobile, which
	   the single padding-block this once carried could not express. No spacing
	   token matches either curve (xxxlarge overshoots, xxlarge/64 flat
	   overshoots mobile) — token-gap deviation, DECISIONS F4. Both clamps reach
	   their 64 by the md breakpoint and floor at the mobile frame's value. */
	--tc-footer-pad-start: clamp(2rem, calc(0.571rem + 7.14vw), 4rem); /* 32 -> 64 */
	--tc-footer-pad-end: clamp(2.5rem, calc(1.4286rem + 5.357vw), 4rem); /* 40 -> 64 */

	/* Line boxes per role. Flat-then-drop like the sizes, and NOT expressible as
	   a ratio: the frames give CTA 40/40/28 against sizes 33/33/21 (1.21 vs
	   1.33) and newsletter 28/28/24 against 20/20/18 (1.40 vs 1.33). A single
	   unitless line-height is wrong at one end whichever value is picked. */
	--tc-footer-cta-line: clamp(1.75rem, calc(1.2143rem + 2.679vw), 2.5rem); /* 28 -> 40 */
	--tc-footer-news-line: clamp(1.5rem, calc(1.3214rem + 0.893vw), 1.75rem); /* 24 -> 28 */
	--tc-footer-col-line: 1.25rem; /* 20 — accordion row; 28 at md, below */
	--tc-footer-row-line: 1.75rem; /* 28 — link row box, all four frames */
	--tc-footer-row-gap: 0.75rem; /* 12 — link row gap, all four frames */

	/* Controls: the frames draw every button and field 48 tall at tablet and
	   desktop and 44 at mobile, with a 15/24 label — so the block padding is
	   12 / 10 and the outline button absorbs its own 1px border. */
	--tc-footer-btn-pad: 0.625rem; /* 10 -> 12 at md */
	--tc-footer-btn-pad-outline: 0.5625rem; /* 9 -> 11 at md (border-box 44/48) */
	--tc-footer-control-h: 2.75rem; /* 44 -> 48 at md — GF submit box */
	--tc-footer-btn-line: 1.5rem; /* 24 — Label/Large on both button roles */
	--tc-footer-field-line: 1.25rem; /* 20 — Label/Medium on the field */

	/* The newsletter corner — ONE value, both controls.

	   This was `--tc-footer-submit-radius` and applied to the Subscribe button
	   alone, on the reading that the field took `radius--sm` because "the frames
	   draw the two differently". THAT WAS WRONG, and it was wrong because it was
	   inferred off a 2× PNG instead of read out of the node tree. Read out of the
	   node tree this time: the desktop newsletter row `43887:31139` draws
	   `Input Field` 42227:5267 at `rounded-[2px]` and `Button` 42227:5327 at
	   `rounded-[2px]`, and the smartphone board's own pair — 42230:7675 and
	   42230:7682, under `42230:7670` — draws both at 2px as well. Same corner on
	   both controls, on both boards.

	   No radius token is 2 (sm is 6, md is 16, pill is 1.5em), so this stays a
	   local value with the measurement attached, the same way the control heights
	   above are. Renamed from `--tc-footer-submit-radius`: it is the corner of
	   the whole control pair now, not of the submit alone. */
	--tc-footer-control-radius: 2px;

	/* The CTA corner — 2, matching every other button in the file.

	   ⚠ THIS WAS 4px AND THE 4 CAME FROM A FIGMA READ THAT THE DESIGNER HAS
	   SINCE OVERRULED (2026-09-09). Both halves are true and the ruling wins:

	     - The node tree really does say 4. Read 2026-09-03 on the desktop
	       footer instance `43324:16691` — fill `42227:4872` (157 x 48) and
	       outline `42227:4882` (196 x 48) — and both return `rounded-[4px]`.
	       `footer-verify` F8 and the verify table's frame column agree.
	     - The designer checked the MOCKUPS and ruled 2px, on the grounds that
	       every other button in the file is 2px. The frame instance is the odd
	       one out, and an instance-level override is the likely cause. Flagged
	       back to the designer so the file and the ruling agree; until that
	       lands, a re-read of this node will still return 4 and IS NOT
	       EVIDENCE THIS VALUE IS WRONG.

	   The build follows the designer, not the node. See DECISIONS 2026-09-09.

	   Still a local value and still its own token rather than a reuse of
	   `--tc-footer-control-radius` above: no radius token is 2 (sm is 6, md is
	   16, pill is 1.5em), and the two tokens answer to different node evidence
	   even though they now hold the same number. Collapsing them would make a
	   future divergence look like a regression. This matches how every other
	   2px button in the theme states its corner — `hero-basic`, `hero-overlay`,
	   `hero-split`, `heading-banner`, `media-basic` and `product-detail` all
	   write a component-scoped 2 against theme.json's global 4 (flag G11).

	   It is stated here as a LOCAL PIN rather than left to the cascade because
	   leaving it to the cascade is the whole defect this file is fixing. The 4
	   used to arrive from theme.json's
	   `:root :where(.wp-block-button .wp-block-button__link)` at (0,1,0), which
	   only wins while `global-styles` prints AFTER the design system's
	   `elements.css` — and on a page carrying a core block style variation it
	   does not. See the border comment on the button rule below. */
	--tc-footer-cta-radius: 2px;

	/* Fallback SVGs are mask alpha only — paint colour comes from background-color.
	   Both are Figma component exports, the same path as every other copy of
	   the slug: arrow `fi-rs-arrow-right` 42222:4552, chevron `Arrows / Chevron
	   Down` 542:31243 (2026-09-28, docs/reports/icon-audit.md §7). */
	--tc-icon-arrow-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M23.124 9.87897L18.538 5.29297L17.124 6.70697L21.386 10.97L0 11V13L21.446 12.97L17.123 17.293L18.537 18.707L23.124 14.121C23.6847 13.5575 23.9995 12.7949 23.9995 12C23.9995 11.205 23.6847 10.4425 23.124 9.87897Z'/%3E%3C/svg%3E");
	--tc-icon-chevron-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5.29289 8.29289C5.65338 7.93241 6.22061 7.90468 6.6129 8.2097L6.70711 8.29289L12 13.585L17.2929 8.29289C17.6534 7.93241 18.2206 7.90468 18.6129 8.2097L18.7071 8.29289C19.0676 8.65338 19.0953 9.22061 18.7903 9.6129L18.7071 9.70711L12.7071 15.7071C12.3466 16.0676 11.7794 16.0953 11.3871 15.7903L11.2929 15.7071L5.29289 9.70711C4.90237 9.31658 4.90237 8.68342 5.29289 8.29289Z'/%3E%3C/svg%3E");

	background-color: var(--ftm-scheme-bg);
	color: var(--ftm-scheme-text);
	padding-block: var(--tc-footer-pad-start) var(--tc-footer-pad-end);
}

.site-footer :is(h2, h3) {
	color: var(--ftm-scheme-heading);
	margin-block: 0;
}

/* ── CTA band ─────────────────────────────────────────────────────────── */

/* Frames: 32 between the heading block and the buttons where they stack
   (tablet, mobile). Was `large`/24. At desktop space-between sets the real
   gap and this is only the floor.

   (0,2,0) is load-bearing: the block's own layout-support class
   `.wp-container-core-group-is-layout-*` carries the blockGap at (0,1,0) and is
   emitted in the page's inline style block, i.e. AFTER this file — so a bare
   `.site-footer__cta` ties it and loses. */
.site-footer .site-footer__cta {
	gap: 2rem;
}

.site-footer__cta-heading {
	max-width: 24em;

	/* Measured against the frames (2026-07-22, re-confirmed 2026-07-30): the CTA
	   heading is a flat 33px on desktop AND tablet, dropping to 21px on mobile —
	   heading-small's own fluid bounds, but reached on the wrong curve (the
	   preset gives 25.2 at tablet, 7.8 short). Token-gap deviation, DECISIONS
	   F3; this clamp reaches heading-small's 33px max by the md breakpoint and
	   floors at its 21px mobile value. */
	font-size: clamp(1.3125rem, calc(0.777rem + 2.68vw), 2.0625rem);

	/* Stand-in for the inert typeStyles (H2). Without the weight the `h2`
	   element rule wins at (0,0,1) with the design-system's 400, and at 400 the
	   string is 710px wide against the tablet frame's 688 content box — so the
	   tablet heading WRAPPED TO TWO LINES and moved everything below it down
	   37.95px. At 700 it measures 678 and fits on one line, as all three frames
	   draw it. letter-spacing is stated to document F6, not to change anything. */
	font-weight: 700;
	letter-spacing: normal;
	line-height: var(--tc-footer-cta-line);
}

.site-footer__cta-actions {
	gap: var(--wp--preset--spacing--normal);
}

/* Smartphone frame shows the two CTA buttons full-width and stacked; tablet and
   desktop keep them auto-width side by side. Below breakpoint/md (the footer's
   mobile mode — same boundary the accordion uses) stretch them edge to edge. */
@media (max-width: 47.9375rem) {
	.site-footer__cta-actions,
	.site-footer__cta-actions .wp-block-button,
	.site-footer__cta-actions .wp-block-button__link {
		width: 100%;
	}
}

/* ── Buttons (fill / outline, trailing arrow) ─────────────────────────── */

/* ⚠ BORDER AND RADIUS ARE PINNED HERE, AND THE PIN IS THE FIX (2026-09-03).

   Neither was stated by this file before. Both arrived from theme.json's
   `:root :where(.wp-block-button .wp-block-button__link)` (radius 4) and
   `:root :where(.wp-element-button, .wp-block-button__link)` (border-width 0),
   both at (0,1,0) — the SAME specificity as the design system's
   `.wp-element-button, .wp-block-button__link` in
   `plugins/ftm-blocks/design-system/build/elements.css:16-26`, which asks for
   `border: hairline solid transparent` and `border-radius: radius--md` (16).
   A (0,1,0) tie is settled by source order, and THE SOURCE ORDER IS NOT THE
   SAME ON EVERY PAGE:

     WP core registers `block-style-variation-styles` with
     `deps: array( 'wp-block-library', 'global-styles' )`
     (`wp/wp-includes/block-supports/block-style-variations.php:189`). Any page
     whose content uses a core block style variation — `is-style-outline` on a
     core/button is the one in play here — enqueues that handle, and the
     dependency drags `global-styles` from its usual late position in the head
     (67th style on `/`) up to 24th, AHEAD of `elements.css`. Every (0,1,0) tie
     between theme.json and the design system then flips.

   Measured 2026-09-03: `/services/` is the only page on the site that does this
   today, and its footer CTAs rendered at 16px radius with the fill 50 tall
   (24 line + 24 pad + 2 border) while `/` and `/contact-us/` rendered 4px / 48.
   Nothing is wrong with the patterns on that page — `heading-banner` and
   `media-basic` both scope their own button rules correctly. The variable is
   the stylesheet order, and it is page-content-dependent, so the only stable
   answer is to state the values here at (0,2,0) where no order can reach them.

   `border: 0` is the fill's border; `.site-footer__btn--outline` restates its
   own 1px below at the same (0,2,0), later in the file. */
.site-footer__btn .wp-block-button__link {
	align-items: center;
	border: 0;
	border-radius: var(--tc-footer-cta-radius);
	display: inline-flex;
	justify-content: center;

	/* Sized to the frames (re-measured 2026-07-30): Label/Large 15/24/500 (G01 took it to 600 on 2026-09-14; corrected back to 500 on 2026-09-15, as the frames draw) in a
	   16px inline padding, giving 157 x 48 for "Contact Sales" against the
	   frame's 157 x 48. Was body-small/16 at weight 400 (inherited through
	   `:root :where(.wp-element-button, .wp-block-button__link)`) in a 24px
	   inline padding, which ran 176 wide. */
	font-size: var(--wp--preset--font-size--label-large);
	font-weight: 500; /* G01, corrected to 500 on 2026-09-15 */
	gap: 0.5rem;
	line-height: var(--tc-footer-btn-line);
	padding: var(--tc-footer-btn-pad) 1rem;
}

.site-footer__btn .wp-block-button__link::after {
	background-color: currentcolor;
	content: "";
	display: inline-block;
	flex-shrink: 0;
	height: 1rem;
	-webkit-mask: var(--ftps-icon-arrow-right, var(--tc-icon-arrow-right)) no-repeat center / contain;
	mask: var(--ftps-icon-arrow-right, var(--tc-icon-arrow-right)) no-repeat center / contain;
	width: 1rem;
}

.site-footer__btn--fill .wp-block-button__link {
	background-color: var(--tc-footer-cta-fill);

	/* Explicit white: on the primary scheme --ftm-scheme-accent-text resolves to the
	   navy scheme text, which painted the label navy-on-blue (fails contrast and
	   mismatches the frame's white label). White on secondary-600 #057DB9
	   measures 4.53:1 (F1 closed 2026-08-06). */
	color: var(--wp--custom--color--base--white);
}

.site-footer__btn--fill .wp-block-button__link:hover,
.site-footer__btn--fill .wp-block-button__link:focus-visible {
	background-color: var(--tc-footer-cta-fill-hover);
}

.site-footer__btn--outline .wp-block-button__link {
	background-color: transparent;
	border: 1px solid var(--ftm-scheme-accent); /* accent = white on the primary scheme */
	color: var(--ftm-scheme-accent);

	/* The frames draw both buttons the same 48 (44 at mobile) overall, so the
	   outline variant's border comes OUT of its padding rather than adding to
	   it — otherwise it stands 2px taller than its filled sibling, which is
	   what shipped and what pushed the rule 3px down the band. */
	padding-block: var(--tc-footer-btn-pad-outline);
}

.site-footer__btn--outline .wp-block-button__link:hover,
.site-footer__btn--outline .wp-block-button__link:focus-visible {
	background-color: var(--ftm-scheme-accent);
	color: var(--ftm-scheme-accent-text);
}

/* ── Divider ──────────────────────────────────────────────────────────── */

/* The rule is FULL BLEED in all three frames — 0 to 1920 / 768 / 320, not the
   content width. Found by scanning the exports for the #3B4D7C hairline rather
   than by reading the node tree, which has no separator node at all: the rule
   is drawn as the last pixel row of the CTA band's own frame (build-knowledge
   §16, and the lesson the drawer pass recorded about stroke positions). The
   alignfull on the block does the bleed; this only paints it. */
.site-footer hr.site-footer__divider {
	background-color: var(--tc-footer-divider);
	border: 0;
	height: 1px;
	opacity: 1;

	/* Asymmetric, and it has to be: the frames put 32/64 above the rule and
	   40/64 below it. Same two values as the section padding, which is what the
	   band structure in Figma actually is — a 64/64 CTA frame stacked on a
	   64/76 lower frame with the rule on the seam.

	   The -1px is that seam: the frames draw the rule as the LAST pixel row of
	   the gap above it, not as a 1px box added to it, so gap + rule + gap is 128
	   and not 129. Without it every band below the rule lands 1px low at all
	   three breakpoints. */
	margin-block: calc(var(--tc-footer-pad-start) - 1px) var(--tc-footer-pad-end);
}

/* ── Lower area: base = stacked ───────────────────────────────────────── */

.site-footer__lower {
	display: grid;
	gap: var(--wp--preset--spacing--xlarge);
}

/* ── Newsletter (Gravity Forms 2) ─────────────────────────────────────── */

/* Title/Small is flat 20 at desktop AND tablet and 18 at mobile; the
   title-small preset is FLUID over 320-1600 and lands 18.83 at tablet, so the
   preset is 1.17px short exactly where the frames are flat. Same shape as the
   CTA heading (F3) and shipped the same way. The block's fontSize attribute was
   removed with this rule — a preset class is `!important` and cannot be
   corrected from here (see the report's specificity table).

   h3.<class> is (0,2,1) deliberately: `.site-footer :is(h2, h3)` above is
   (0,1,1) and beat the plain single-class rule this used to be, so the intended
   24px bottom margin computed to 0 and the gap came from WP's
   `:root :where(.is-layout-flow) > *` instead. Frames say 12. */
.site-footer h3.site-footer__newsletter-heading {
	font-size: clamp(1.125rem, calc(1.0357rem + 0.4464vw), 1.25rem); /* 18 -> 20 */
	font-weight: 600; /* G20 (Gary, 2026-09-14) — was 700, the frames' ink-mass read (F6) */
	line-height: var(--tc-footer-news-line);
	margin-block-end: 0.75rem;

	/* All four frames draw this heading capitalised — "Get The Latest Updates And
	   Promotions". Note "And": that is `text-transform: capitalize` over a
	   sentence-cased string, not editorial title case, which would lower it
	   again. The transform is therefore the frames' own mechanism, reproduced as
	   one — the seeded content stays sentence case, and an editor who rewrites
	   the heading in the Site Editor gets the treatment for free rather than
	   having to type the capitals.

	   THE CTA HEADING IS DELIBERATELY NOT GIVEN THIS, though the frames draw it
	   capitalised too. Capitalised, its string measures 691 against the tablet
	   frame's 688 content box: it wraps to two lines and moves the rule and the
	   whole lower band 40px down. That is D1, and the note above the block in
	   footer.php. This heading has no such constraint — it sits in a 437 column
	   at desktop against 349 of ink. The asymmetry is intentional. */
	text-transform: capitalize;
}

/* The other half of that 12px gap, and the reason it was 24 until 2026-09-09.

   `margin-block-end: 0.75rem` above sets the heading's side of the gap and is
   correct. The gap is not the heading's alone: `.site-footer__newsletter` is a
   WordPress FLOW-layout group, so WP emits

     :root :where(.is-layout-flow) > * { margin-block-start: var(--wp--style--block-gap) }

   against its children — which includes the gravityforms block's
   `.gform_wrapper`. That 24 COLLAPSES OVER the 12 above, and a collapsed pair
   takes the LARGER of the two, so the rendered heading-to-form gap was 24 at
   1920, 768 and 320 alike where all four frames draw 12 (desktop 43324:16691:
   heading `;42227:5261` h 28 at y 0, form row `;43887:31139` at y 40).

   This is the SAME collision as `.site-footer__col-body` below, one level deep
   on the other side of the lower grid, and the 2026-07-30 pass wrote the guard
   for the columns side only.

   ⚠ AND THE SPEC WAS LOOKING STRAIGHT AT IT. footer-verify.spec.ts asserted
   `newsHeading.marginEnd === '12px'`, which was TRUE and passing the whole
   time — the losing margin is on the SIBLING, and nothing measured the gap
   between the two boxes. A rendered-gap assertion is added alongside it.

   (0,3,0): WP's selector is (0,1,0) — `:where()` contributes nothing — and its
   global styles load AFTER pattern CSS, so a (0,1,0) tie is lost on order
   (build-knowledge §5a). (0,2,0) would win on specificity; (0,3,0) is the
   brief's floor. The declaration added is `0`; the 12 is the heading's own
   token-derived margin finally being allowed to be the gap. */
.site-footer .site-footer__lower .site-footer__newsletter > * {
	margin-block-start: 0;
}

/* Field + submit — selectors cover GF legacy and Orbital wrappers; scoped
   under .site-footer so the design-system form bridge never outranks them.

   ⚠ `.gform_wrapper` IS WRITTEN TWICE ON PURPOSE. It is a specificity bump and
   nothing else — the doubled class matches exactly the elements the single one
   matched — and it is here because the paragraph that used to stand in this
   spot was WRONG in a way that only showed on some pages. It read:

     "These tie GF's own `.gform_wrapper.gravity-theme input[type=…]` at (0,3,1)
      and win on load order, the pattern CSS being enqueued after the plugin's —
      verified with CSS.getMatchedStylesForNode, not assumed."

   Both halves were true when measured. The tie is real, at (0,3,1) each. And
   the pattern CSS IS enqueued after the plugin's — ON A PAGE WHOSE ONLY FORM IS
   THIS ONE. Measured 2026-09-03 with document.styleSheets, in order:

     /             basic 17, theme-components 18, theme 19 … footer.css 45
     /contact-us/  footer.css 45 … basic 81, theme-components 82, theme 83

   Gravity Forms enqueues its stylesheets LATE when a form is in the CONTENT,
   and late means after the theme's glob-loaded pattern CSS. So on `/` footer.css
   is 45 against GF's 19 and the tie falls our way; on `/contact-us/` and
   `/services/` it is 45 against GF's 83 and the identical tie falls theirs. The
   footer is the same footer on all three pages. **A tie broken by load order is
   not a win, it is a coin toss that happened to land right on the page it was
   measured on** — which is why the verification quoted above did not catch this:
   it was performed on a page with no form in the content.

   WHAT ACTUALLY MOVED, measured at 1920/768/390, `/` versus `/contact-us/`:

     input[text|email]  font-size   14px  ->  15px   (theme.min.css, (0,3,1))
     input[text|email]  padding   0 16px  ->  8px    (theme.min.css, (0,3,1))
     .gform_fields      row-gap     12px  ->  16px   (basic.min.css, (0,3,0))
     .gform_footer      margin-top   0px  ->  6px    (theme.min.css, (0,3,0))
     .gform_footer      padding   12/0px  ->  16px   (theme.min.css, (0,3,0))

   The padding pair is the visible one on the stacked shape: the field's text
   sits 8px in while Subscribe's sits 16px in, so the column reads ragged. The
   `.gform_footer` margin is the visible one on the SINGLE-FIELD row, and it is
   the reported "misaligned email field vs Subscribe button" exactly — measured
   by stripping the extra `.gfield`s in the DOM so the `:has()` branch below
   fires, the button's top sits 0px from the field's on `/` and 6px below it on
   `/contact-us/`.

   ONE EXTRA CLASS IS ENOUGH AND NO `!important` IS NEEDED. Every rule above is
   a tie at (0,3,x), so (0,4,x) settles all five outright, and NONE of the GF
   declarations involved carries `!important` — checked per property, not
   assumed. Nothing here is marked `!important` as a result.

   ⚠ THE BUMP DOUBLES OUR OWN CLASS RATHER THAN BORROWING `.gravity-theme`,
   WHICH WOULD HAVE BEEN THE OBVIOUS MOVE AND IS A TRAP. Adding GF's own
   `.gravity-theme` to the selector would also reach (0,4,x), but that class
   belongs to the LEGACY form theme; a form switched to Orbital renders
   `gform-theme--framework` instead and the selector would stop matching
   altogether — losing every declaration in these rules, not merely the tie.
   Doubling `.gform_wrapper` cannot change what matches, only what wins.

   ⚠ WHAT IS STILL LOST TO GF, DELIBERATELY. `basic.min.css` sets
   `line-height: 2` and `min-height: 32px` on inputs below 641px at (0,6,1) —
   six classes, four of them the `:not()` chain — and that still outranks these
   rules on both pages. Left alone on both counts: `min-height: 32px` is under
   the 44/48 the box is sized to and cannot show, and the line-height is
   invisible because the box height is explicit and `padding-block` is 0, so the
   browser centres a single-line input's text in the content box regardless. It
   is also no longer a page DIFFERENCE, which is what the defect was: it
   computes to 2 × font-size, so pinning the font-size to 14px pins the
   line-height to 28px on every page too. Chasing (0,7,1) to own a number that
   changes nothing was not worth the selector.

   THE BOX HEIGHT IS EXPLICIT, and that is not belt-and-braces. Gravity Forms
   ships, mobile-only and at (0,6,1) — six classes, four of them the `:not()`
   attribute chain —

     @media only screen and (max-width: 641px) {
       .gform_wrapper.gravity-theme
         input:not([type="radio"]):not([type="checkbox"]):not([type="image"]):not([type="file"])
         { line-height: 2 }
     }

   which outranks anything reasonable this file can write and made every field
   28 tall and the submit 30 — 8px over the frames, AT MOBILE ONLY, which is
   why the desktop-era pass never saw it. Sizing the box directly (and zeroing
   the block padding so the UA centres the value) takes layout out of the
   line-height's hands entirely, needs no !important and no specificity climb,
   and states the number the frames actually specify. All four frames draw the
   field 48 tall. */
.site-footer .gform_wrapper.gform_wrapper input:is([type="text"], [type="email"]) {
	background-color: var(--wp--custom--color--base--white);
	block-size: 3rem; /* 48, all four frames */
	border: 1px solid var(--wp--custom--color--base--white);
	border-radius: var(--tc-footer-control-radius);
	color: var(--wp--custom--color--base--black);

	/* Label/Medium 14/20/500. GF's own rule sets 15px. */
	font-size: 0.875rem;
	font-weight: 500;
	line-height: var(--tc-footer-field-line);
	padding-block: 0;
	padding-inline: 1rem;
	width: 100%;
}

.site-footer .gform_wrapper.gform_wrapper input:is([type="text"], [type="email"])::placeholder {
	color: var(--wp--custom--color--neutral--500); /* frame-sampled #6C757D */
}

/* Elementor kit resets are load-bearing on the submit control too. */
.site-footer .gform_wrapper.gform_wrapper :is(input[type="submit"], button[type="submit"]) {
	background-color: var(--tc-footer-cta-fill);
	border: 0;
	border-radius: var(--tc-footer-control-radius);
	color: var(--wp--custom--color--base--white);
	cursor: pointer;

	/* Same Label/Large 15/24/500 (G01, corrected 2026-09-15) as the CTA buttons, in the same 48/44 box. Was
	   inheriting 18px at weight 400 and standing 52.19 tall. Height explicit for
	   the same GF line-height reason as the field above. */
	block-size: var(--tc-footer-control-h);
	font-size: var(--wp--preset--font-size--label-large);
	font-weight: 500; /* G01, corrected to 500 on 2026-09-15 */
	line-height: var(--tc-footer-btn-line);

	/* GF's `.gform_footer input|button { margin-bottom: 8px }` is not a page
	   DIFFERENCE — it applies on every page — but it is 8px of GF's spacing
	   inside a control box the frames pin, so the box is taken outright rather
	   than left half-owned. Zeroed here, and the frame-geometry tests above are
	   what arbitrate it: they measure the band this 8px sits in. */
	margin-block: 0;
	padding-block: 0;
	padding-inline: 1rem;
	text-transform: none;
}

/* ⚠ THE MOBILE LINE-HEIGHT, TAKEN BACK FROM GF AT (0,7,1).

   `basic.min.css` sets `line-height: 2` below 641px on

     .gform_wrapper.gravity-theme
       input:not([type="radio"]):not([type="checkbox"]):not([type="image"]):not([type="file"])

   which is (0,6,1) — two classes plus four `:not()` attribute arguments — and
   outranks the field rule above on EVERY page, not only on form pages. It is
   the one GF declaration the specificity bump did not settle.

   It is invisible: the box height is explicit and `padding-block` is 0, so a
   browser centres a single-line input's text in the content box whatever the
   line-height says. It stopped being a page DIFFERENCE the moment font-size was
   pinned, because it computes to 2 x font-size. **So this rule changes no
   pixel** — it is here because the frames pin Label/Medium 14/20 and the box is
   meant to be wholly the theme's, not 20px of ours and one line-height of GF's.

   The selector MIRRORS GF's own chain inside this file's scope rather than
   stacking more copies of `.gform_wrapper`: three classes plus the same four
   `:not()`s is (0,7,1), one above theirs, and it reads as what it is. Six
   repetitions of a class to reach the same number would not. */
@media (max-width: 641px) {
	/* stylelint-disable selector-not-notation -- the chain IS the specificity; see below. */
	.site-footer
		.gform_wrapper.gform_wrapper
		input:not([type="radio"]):not([type="checkbox"]):not([type="image"]):not([type="file"]) {
		line-height: var(--tc-footer-field-line);
	}
	/* stylelint-enable selector-not-notation */
}

/* ⚠ THE `selector-not-notation` DISABLE ABOVE IS LOAD-BEARING, NOT A STYLE
   PREFERENCE, AND `--fix` WOULD SILENTLY BREAK THE RULE.

   stylelint wants the complex notation, `:not([type="radio"], [type="checkbox"],
   …)`. That is not equivalent here. A comma-separated `:not()` takes the
   specificity of its MOST SPECIFIC ARGUMENT — one attribute selector, (0,1,0) —
   where the chained form contributes all four, (0,4,0). The selector would fall
   from (0,7,1) to (0,4,1), back UNDER GF's (0,6,1), and the declaration would
   stop applying with no error and no visual change to notice it by. The chained
   form is the whole mechanism.

   Anyone tempted to run `stylelint --fix` over this file: it will make that
   edit, and the only thing that catches it is the computed-value assertion in
   e2e/footer-verify.spec.ts. */

.site-footer .gform_wrapper.gform_wrapper :is(input[type="submit"], button[type="submit"]):hover,
.site-footer .gform_wrapper.gform_wrapper :is(input[type="submit"], button[type="submit"]):focus-visible {
	background-color: var(--tc-footer-cta-fill-hover);
}

/* Required-field legend. None of the four frames draws one, and GF emits it
   with literal quote marks around the asterisk — `"*" indicates required
   fields` — which reads as a typo above a four-field signup. Hidden outright
   rather than clipped to the screen-reader layer: the requirement is carried
   programmatically by `aria-required="true"` on each input, which is what
   assistive tech actually announces, so removing the sentence that explains a
   VISUAL convention costs nothing semantically. */
.site-footer .gform_wrapper .gform_required_legend {
	display: none;
}

/* ── Field + submit ───────────────────────────────────────────

   THE FRAMES DRAW ONE INPUT BESIDE SUBSCRIBE — 334 + 12 + 105 across the
   desktop frame's 451 column, which is exactly where the `2fr 3fr` further down
   comes from. The form does not have one input. `Footer Signup` ships name
   (first + last), company, email, a consent checkbox and a captcha, and that
   mismatch is a RECORDED FRAME DEFECT, not a build error —
   docs/design/footer/README.md, "Known frame defects": "The mobile comp draws
   ONE newsletter input; the build renders four plus a consent checkbox and a
   captcha... the footer will never match the comp here."

   It is also not fixed. The form is resolved BY TITLE (footer.php), so its
   field list belongs to whoever edits it in Gravity Forms and can change on any
   environment without a deploy. Hard-coding either shape would be wrong
   somewhere, so the row is driven by what the form actually contains:

     one field   → field and Subscribe in a single row, both 48, aligned —
                   the frames' design exactly;
     more than 1 → the fields stack full width and Subscribe sits beneath them.

   `:has()` is what makes that branch possible from CSS at all. The alternative
   is PHP counting fields and emitting a class, which puts layout back into the
   pattern and re-couples the file to the form. It is already used in
   product-detail.css and product-grid.css, so it is not a new dependency.

   All of it is ABOVE the 48rem stack point. Below that both shapes stack, which
   is what the smartphone frame draws either way. */

/* 12, not 16: the desktop frame's newsletter column is 334 + 12 + 105 = 451.
   This was `normal` (16) and so ran 4px wide — outside the ±3 tolerance
   build-knowledge §16 fixes, which is why it is corrected here rather than
   left alone. */
.site-footer .gform_wrapper.gform_wrapper .gform_fields {
	row-gap: var(--wp--preset--spacing--small);
}

/* Stacked shape. GF's own rule puts 16 above the button and 24 below it; the
   rhythm here is the same 12 the fields are set on. */
.site-footer .gform_wrapper.gform_wrapper .gform_footer {
	margin: 0;
	padding-block: var(--wp--preset--spacing--small) 0;
}

@media (min-width: 48rem) {
	/* Single-field forms only — one `.gform_fields` child that is both first and
	   last. A form that later grows a second field drops back to the stack on its
	   own, with no CSS change and no redeploy. */
	.site-footer .gform_wrapper form:has(.gform_fields > :first-child:last-child) {
		align-items: start;
		display: flex;
		gap: var(--wp--preset--spacing--small);
	}

	.site-footer
		.gform_wrapper
		form:has(.gform_fields > :first-child:last-child)
		:is(.gform_body, .gform-body) {
		flex: 1;
	}

	/* Back to 0 so the two boxes' tops line up: both are 48 here, so aligning the
	   tops aligns the boxes. */
	.site-footer
		.gform_wrapper
		form:has(.gform_fields > :first-child:last-child)
		.gform_footer {
		flex: 0 0 auto;
		padding-block: 0;
	}
}

/* Below the stack point the submit goes full width, as the smartphone frame
   draws it, in the 44 box `--tc-footer-control-h` gives there.

   THIS RULE USED TO BE DEAD ACROSS A 288px BAND, and measurably so — the guess
   that it "blew the button out" is wrong, which is why the number is here. It
   ran to 47.9375rem while the inline row started at 30rem, so from 480 to 767
   BOTH applied; `width: 100%` then resolved against `.gform_footer`, which is
   the flex ITEM and shrinks to its content. Measured with the old pair restored
   over the shipped file, 480 / 600 / 767 all gave a 117-wide submit sitting
   beside the field stack — the desktop treatment, 288px below where the frames
   switch. The two rules now meet at 48rem and the same three widths give
   430.9 / 538 / 687.1, which is the field's own width. */
@media (max-width: 47.9375rem) {
	.site-footer .gform_wrapper.gform_wrapper :is(input[type="submit"], button[type="submit"]) {
		width: 100%;
	}

	/* V-F2 (QA batch D, 2026-09-29): one 12 between every stacked field. Below
	   its own stack point GF gives each Name sub-field `margin-bottom: 8px`, so
	   First -> Last was 8 and Last -> Company 8 + the 12 row gap = 20, against
	   12 everywhere else (and 12 at 768). The frame draws a single input, so
	   the form's own 12 row gap is the rule. */
	.site-footer .gform_wrapper.gform_wrapper .ginput_complex {
		row-gap: var(--wp--preset--spacing--small); /* 12 */
	}

	.site-footer .gform_wrapper.gform_wrapper .ginput_complex > span {
		margin-block-end: 0;
	}
}

/* V-F3 (QA batch D, 2026-09-29): the consent box sits on the label's FIRST
   line, not the middle of a 2-3 line label. Both were GF's `inline-block;
   vertical-align: middle`, which centres the box on the whole label; the
   contact form's consent control, the nearest identical one, already aligns
   to the first line. The box is 13 and the label's line 22.5 (15 × 1.5), so
   4.75 centres it on that line. Every width. */
.site-footer .gform_wrapper.gform_wrapper :is(.gchoice, .ginput_container_consent) > :is(input[type="checkbox"], label) {
	vertical-align: top;
}

.site-footer .gform_wrapper.gform_wrapper :is(.gchoice, .ginput_container_consent) > input[type="checkbox"] {
	margin-block-start: 4.75px; /* (22.5 line - 13 box) / 2 */
}

/* ── Consent checkbox tap target (QA batch A, 2026-09-27) ─────

   The GDPR box is GF's NATIVE checkbox, 13×13 — measured hit 13×14 at
   360-430, against the 44×44 the phone brief requires. The box itself is left
   exactly as it is; a native checkbox cannot be padded larger, and redrawing
   it is a design change nobody asked for.

   Instead the LABEL carries a transparent 44×44 ::before centred on the box.
   The label is `for` the input, so a tap on its pseudo-element is a tap on the
   label, which toggles the checkbox. It paints above the box (later in the
   DOM), so it also takes taps landing on the box.

   Geometry, measured at 390: `.gchoice` is a block, the input sits at its left
   edge. Since V-F3 (QA batch D) it sits on the label's first line, 4.75 down,
   so the target centres at 6.5px across and 11.25px down. It reaches
   15.5px left of the column, which is still inside the 16px+ gutter.

   Keyed on GF's own markup, not a field ID: the form is resolved by title and
   edited per environment (see the field-count note above). Both GF shapes
   are covered — a Checkbox field (`.gchoice`) and a Consent field
   (`.ginput_container_consent`). */
@media (max-width: 47.9375rem) {
	.site-footer .gform_wrapper :is(.gchoice, .ginput_container_consent):has(> input[type="checkbox"]) {
		position: relative;
	}

	.site-footer
		.gform_wrapper
		:is(.gchoice, .ginput_container_consent):has(> input[type="checkbox"])
		> label::before {
		content: "";
		position: absolute;
		inset-block-start: calc(4.75px + 6.5px - 22px); /* centred on the box, which V-F3 moved to the first line */
		inset-inline-start: calc(6.5px - 22px);
		inline-size: 44px;
		block-size: 44px;
	}
}

/* ── Link columns ─────────────────────────────────────────────────────── */

.site-footer__cols {
	display: grid;
	gap: var(--wp--preset--spacing--large);
}

/* Both groups are declared with WordPress's default (flow) layout so they stay
   ordinary editable groups in the Site Editor, and WP therefore emits
   `:root :where(.is-layout-flow) > *  { margin-block-start: <block-gap> }`
   against them. Grid owns spacing here, so that inherited margin would push
   every cell EXCEPT the first down by one block gap — visibly dropping
   Resources, Support and the social icons below the Company heading they are
   meant to top-align with.

   The `.site-footer` prefix is load-bearing, not decoration: WP's selector
   scores (0,1,0) via `:root`, which TIES a bare `.site-footer__cols > *`, and
   its global styles come later in source order so the tie goes to WP. The extra
   class takes this to (0,2,0) and settles it on specificity rather than on
   enqueue order, which is not ours to depend on. */
.site-footer .site-footer__lower > *,
.site-footer .site-footer__cols > * {
	margin-block-start: 0;
}

/* The same WP rule reaches one level deeper than the selector above, which only
   matches the columns themselves: the nav block inside each column is also a
   flow-layout child, so it took WP's 24px block-start margin and put the link
   list 24 below its heading where the frames say 12. Three classes to clear
   (0,1,0) on specificity, and the LOGICAL property because that is the longhand
   WP writes — `margin-top` here loses the physical/logical tie on load order,
   which is how `.site-footer__nav { margin: 0 }` was being beaten. */
.site-footer .site-footer__col .site-footer__col-body {
	margin-block-start: 0;
}

.site-footer__nav {
	/* Frames: a 28px row box with a 12px gap, giving the 40px row pitch every
	   one of the four measures. Was normal/16 against a 24px box — the same 40
	   pitch by accident, but with the ink 2px high in each row and no headroom
	   for the 28 box the frames actually draw. */
	gap: var(--tc-footer-row-gap);
	list-style: none;
	margin: 0;
	padding: 0;
}

.site-footer__nav--fallback {
	display: flex;
	flex-direction: column;
}

.site-footer__nav li,
.site-footer__nav a,
.site-footer__nav span {
	/* Label/Large 15/28/500. The block carries fontSize label-large so the list
	   itself is 15 (a preset class is `!important`, so the size has to come from
	   the markup); this restates it for the unlinked fallback path, which has no
	   preset class, and sets the line box and weight for both. */
	font-size: var(--wp--preset--font-size--label-large);
	font-weight: 500;
	line-height: var(--tc-footer-row-line);
}

.site-footer__nav a,
.site-footer__nav span {
	color: var(--ftm-scheme-text);
	text-decoration: none;
}

.site-footer__nav a:hover,
.site-footer__nav a:focus-visible {
	text-decoration: underline;
}

/* Inter, not the display family — Label/Extra Large 16/28 with Inter confirmed
   by ink mass (weight 500 renders 22.5% light against the frame's glyphs).
   Both the family and the weight were coming from the `h3` element rule's
   --wp--custom--type-styles--heading-medium--*, which is never emitted, so the
   headings rendered Rethink Sans 400. Size is already right from the
   label-x-large preset class and is left to it.

   600, not the 700 the ink-mass read gave: G20 (Gary, 2026-09-14) names these
   three headings and the newsletter heading at 600, and nothing else — the CTA
   heading stays 700. The mobile accordion toggle inherits this through
   `font: inherit`, so "Company" reads 600 in both modes.

   (0,2,1) for the margin, same reason as the newsletter heading above. */
.site-footer h3.site-footer__col-heading {
	font-family: var(--wp--preset--font-family--body);
	font-weight: 600; /* G20 */
	line-height: var(--tc-footer-col-line);
}

/* ── Mobile accordion — below breakpoint/md (48rem) ───────────────────── */

/* footer.js sets `hidden` on the column body to collapse it, but the body is a
   flex-layout navigation block: WP's `.wp-block-navigation-is-layout-flex {
   display: flex }` (0,1,0) overrides the `hidden` attribute's UA `display:none`,
   so the panel would never actually collapse. Restore it at (0,2,0). */
.site-footer__col-body[hidden] {
	display: none;
}

/* Toggle button injected by footer.js; without JS lists stay expanded. */
.site-footer__col-toggle {
	align-items: center;

	/* Elementor kit resets (load-bearing — see file header). */
	background-color: transparent;
	border: 0;
	border-radius: 0;
	color: inherit;
	cursor: pointer;
	display: flex;

	/* `font: inherit` is what makes the toggle take the heading's type rather
	   than the UA's button font — so the col-heading rule above is what sizes
	   this, and the two must be read together. */
	font: inherit;
	gap: 0.5rem;
	justify-content: space-between;
	padding: 0;
	text-align: start;
	text-transform: none;
	width: 100%;
}

/* 24, per the frames' Arrows/Chevron Down instance — was 1.25em (20). The flex
   floor is not decoration: this is an icon in a flex row beside text that the
   marketing team can lengthen at will, and without it a long label shrinks the
   chevron instead of wrapping (the exact failure the drawer's back chip hit). */
.site-footer__col-toggle::after {
	background-color: currentcolor;
	content: "";
	flex-shrink: 0;
	height: 1.5rem;
	-webkit-mask: var(--ftps-icon-chevron-down, var(--tc-icon-chevron-down)) no-repeat center / contain;
	mask: var(--ftps-icon-chevron-down, var(--tc-icon-chevron-down)) no-repeat center / contain;
	min-inline-size: 1.5rem;
	transition: transform 0.2s var(--wp--custom--easing--standard, ease);
	width: 1.5rem;
}

.site-footer__col-toggle[aria-expanded="true"]::after {
	transform: rotate(180deg);
}

/*
 * The frames draw no focus state, so this SUPERSEDES them rather than deviating
 * from them — same standing as the header's designer-approved hover treatment.
 * It is here because the live keyboard pass found the fallback: with nothing
 * declared, the accordion toggle and the social icons take Chromium's UA ring,
 * `outline: auto 1px rgb(16, 16, 16)` — near-black on the #0A205B band, i.e. a
 * focus indicator you cannot see on the only surface it appears on. The nav
 * links were already covered by their underline; these two were not.
 */
.site-footer__col-toggle:focus-visible,
.site-footer__social .wp-block-social-link a:focus-visible {
	outline: 2px solid var(--ftm-scheme-accent);
	outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
	.site-footer__col-toggle::after {
		transition: none;
	}
}

@media (max-width: 47.9375rem) { /* below breakpoint/md 48rem */
	/* The accordion rows are contiguous in the Smartphone frames — each column
	   is 16 padding, a 24 row, 16 padding and then the hairline, with the first
	   column's top padding removed. The 24px grid gap this carried put a gap
	   between the rule and the next row that the frame does not draw. */
	.site-footer.is-accordion .site-footer__cols {
		gap: 0;
	}

	/* The hairline is the LAST pixel row of the 16, not a 1px box added after it
	   — the same seam reading as the band rule. Left as a full 16 the error is
	   only 1px per row, but there are three rows and the social block sits under
	   all of them, so it accumulates into the visible position of the icons. */
	.site-footer.is-accordion .site-footer__col {
		border-block-end: 1px solid var(--tc-footer-divider);
		padding-block: var(--wp--preset--spacing--normal) calc(var(--wp--preset--spacing--normal) - 1px);
	}

	.site-footer.is-accordion .site-footer__col:first-child {
		padding-block-start: 0;
	}

	.site-footer.is-accordion h3.site-footer__col-heading {
		margin-block-end: 0;
	}

	/* Frame: 14 from the row box to the first link box. `xsmall`/8 and
	   `normal`/16 straddle it; 12 lands the ink 1.4 high, inside tolerance. */
	.site-footer.is-accordion .site-footer__col-body:not([hidden]) {
		padding-block-start: 0.75rem;
	}

	/* With the grid gap gone the icons need their own inset — the frames put 24
	   between the last hairline and the glyph row. */
	.site-footer.is-accordion .site-footer__social {
		padding-block-start: var(--wp--preset--spacing--large);
	}
}

/* ── Social links ─────────────────────────────────────────────────────── */

.site-footer__social.wp-block-social-links {
	gap: var(--wp--preset--spacing--large);
}

/* The frame shows monochrome white glyphs, not brand colours. is-style-logos-only
   otherwise paints each icon its brand colour by setting `color` on the
   per-service `.wp-social-link-{service}` (the svg fill is currentColor). WP
   scores that at (0,3,0); the wrapper + style class here take the override to
   (0,4,0) so it wins on specificity, not enqueue order. */
.wp-block-social-links.site-footer__social.is-style-logos-only .wp-social-link {
	color: var(--ftm-scheme-text);
}

.site-footer__social .wp-block-social-link a {
	color: var(--ftm-scheme-text);
}

/* ── breakpoint/md 48rem — accordion off, 2-up columns (tablet frame:
      Company | Resources / Support | Social) ──────────────────────────── */

@media (min-width: 48rem) {
	.site-footer {
		--tc-footer-col-line: 1.75rem; /* 28 — heading is its own row again */
		--tc-footer-btn-pad: 0.75rem; /* 12 -> 48-tall controls */
		--tc-footer-btn-pad-outline: 0.6875rem; /* 11 */
		--tc-footer-control-h: 3rem; /* 48 */
	}

	.site-footer__cols {
		align-items: start;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		row-gap: var(--wp--preset--spacing--xlarge);
	}

	/* Frames: 12 from the heading box to the first link box, the same gap as
	   between two links, so heading and links share one 40px pitch. */
	.site-footer h3.site-footer__col-heading {
		margin-block-end: var(--tc-footer-row-gap);
	}
}

/* ── breakpoint/lg 64rem — desktop: newsletter left, 3 nav columns +
      social as the right-most cell, top-aligned with the headings ─────── */

@media (min-width: 64rem) {
	.site-footer__lower {
		align-items: start;

		/* The desktop frame's lower row is 451 | 77 | 872 across a 1400 content
		   box — the newsletter column is exactly its own content (input 334 + 12
		   + button 105) and the columns block takes the rest. `2fr 3fr` with a 64
		   gap gave 534 | 64 | 802, which put the three nav columns 70px right of
		   where the frame draws them. The ratio is carried in fr so it degrades
		   proportionally between 64rem and the 1920 the frame specifies; the
		   comp-derived 77 is a one-off with no matching token. */
		column-gap: 77px;
		grid-template-columns: 451fr 872fr;
		row-gap: var(--wp--preset--spacing--xlarge);
	}

	.site-footer__cols {
		grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
	}

	.site-footer__social {
		justify-self: end;
	}
}

/* ── Phone tap targets (QA batch A, 2026-09-27) ─────────────────────────

   Measured at 360-430: social icons 24×24, accordion toggles full × 24,
   against the 44×44 the phone brief requires. Both get a transparent hit box
   on a pseudo-element, so nothing drawn moves and footer-verify's box
   assertions (icon 24 / pitch 48; toggle h 24) still describe the drawing.

   - Social icons: `a::after` 10px out on every side = 44×44. The pitch is
     48, so neighbouring targets stay 4px apart.
   - Toggles: `::before` (the chevron owns ::after), 10px above and below =
     full × 44. Rows are 16 + 24 + 15 + 1px rule, so it stays inside its own
     row's padding. */
@media (max-width: 47.9375rem) {
	.site-footer__social .wp-block-social-link a,
	.site-footer__col-toggle {
		position: relative;
	}

	.site-footer__social .wp-block-social-link a::after {
		content: "";
		position: absolute;
		inset: -10px;
	}

	.site-footer__col-toggle::before {
		content: "";
		position: absolute;
		inset-block: -10px;
		inset-inline: 0;
	}
}
