/**
 * css/components/footer.css — Website 2.0 global chrome (#53)
 *
 * Dark (ink) footer band: logo · full primary nav · legal line.
 * Reference: docs/Common Good website 2.0/ui_kits/website/media.html `.foot`.
 *
 * `.cg-footer__social` has no reference-page equivalent — the design's
 * footer omits social icons entirely — but is added here to preserve the
 * data/functionality previously spliced into the legacy nav_3 menu
 * (docs/design/03-website-2.0-build-plan.md §4). Kept visually quiet
 * (small, low-emphasis) so it doesn't compete with the reference layout.
 *
 * Tokens only — no raw hex, no @layer, no !important.
 */

.cg-footer {
	background: var( --surface-dark );
	color: var( --cg-cream );
}

.cg-footer__bar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 24px;
	min-height: 206px;
	padding: 44px var( --gutter-outer );
}

.cg-footer__nav {
	display: flex;
}

.cg-footer__links {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 32px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.cg-footer__links a {
	font-family: var( --font-sans );
	font-weight: 700;
	font-size: 10px;
	letter-spacing: 0.22em;
	text-transform: uppercase;
	color: var( --cg-cream );
	text-decoration: none;
	opacity: 0.85;
}

.cg-footer__links a:hover {
	opacity: 1;
	color: var( --accent );
}

.cg-footer__links .current-menu-item a,
.cg-footer__links .current_page_item a {
	opacity: 1;
	color: var( --accent );
}

/* Social icons — quiet addition, not in the reference design (see file header). */
.cg-footer__social {
	display: flex;
	align-items: center;
	gap: 18px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.cg-footer__social a {
	display: flex;
	align-items: center;
	font-size: 14px;
	color: var( --cg-cream );
	opacity: 0.7;
	text-decoration: none;
	transition: opacity 0.2s, color 0.2s;
}

.cg-footer__social a:hover {
	opacity: 1;
	color: var( --accent );
}

.cg-footer__legal {
	font-family: var( --font-sans );
	font-weight: 700;
	font-size: 10px;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var( --text-on-dark-muted );
}

.cg-footer__legal-link {
	color: inherit;
	text-decoration: none;
	transition: color var( --fade-out ) var( --fade-ease );
}

/*
 * The separator between the copyright sentence and this link is WHITESPACE
 * ONLY (#449) — the `·` bullet this rule used to print was removed at the
 * owner's request.
 *
 * The gap has to be produced here rather than left to the markup's own
 * newline: `.cg-footer__legal` is `text-transform: uppercase` with
 * `letter-spacing: 0.18em`, and footer.php emits the anchor on its own line
 * after a PHP block, so the collapsed inter-element whitespace is a single
 * space that reads as a word break rather than a separation. `margin-left`
 * on the inline anchor adds the same 0.6em the bullet's own margins used to
 * contribute on that side, so the line does not close up.
 */
.cg-footer__legal-link {
	margin-left: 0.6em;
}

.cg-footer__legal-link:hover {
	color: var( --cg-cream );
	text-decoration: underline;
}

/* ─── Subscribe band (DECISION 4 + #157 2-col) ───────────────────────────
 * Kept from the legacy footer and relocated directly above the chrome
 * footer. Retagged from `bg-violet-dark` to the 2.0 ink band so the two
 * darks no longer clash; the `.bar-form` hook is preserved, so theme.css
 * keeps owning the Gravity Forms LAYOUT and only colour is set here.
 *
 * #157: heading left / form right, via the shared `.cg-split` grid
 * (css/components/split.css) applied directly in footer.php markup —
 * `.cg-subscribe__inner` only supplies the centered content frame;
 * `.cg-split` supplies the 2-col grid + the <=1024px 1-col stack.
 * ──────────────────────────────────────────────────────────────────────── */

.cg-subscribe__inner {
	/*
	 * `.cg-split` aligns its two columns to `start`, which is right for the
	 * eyebrow-plus-statement heads it was built for and wrong here: the two
	 * halves of this band are a two-line heading and a form of two or three
	 * rows, and topped-out they read as two separate blocks that happen to
	 * share a band. Centred, the form sits against the middle of the heading
	 * whatever height either one takes — which matters because the form's
	 * height now changes with the column count (two rows at 1440, four
	 * stacked at 1025, plus a row whenever a validation message appears).
	 *
	 * Overridden here rather than in split.css: every other consumer of that
	 * grid wants `start`.
	 */
	align-items: center;

	max-width: var( --content-w );
	margin-inline: auto;
}

/*
 * A PHANTOM TOP MARGIN, AND IT VARIED BY PAGE TEMPLATE.
 *
 * `.cg-statement` carries `margin: var( --eyebrow-gap ) 0 0` — the gap
 * between an eyebrow and the statement under it (css/components/type.css:32)
 * — which this heading has no use for: there is no eyebrow above it. A bare
 * `.cg-subscribe__title { margin: 0 }` was (0,1,0) and lost to type.css:50,
 * `.page-template-template-home .cg-statement` (0,2,0), so the band's heading
 * carried 38px of dead space on home, services and tech-ai and 34px
 * everywhere else — the same band, sitting differently on different pages.
 *
 * Invisible while the columns were topped out. Not invisible once they are
 * centred: the grid centres MARGIN boxes, so 38px of phantom margin pushed
 * the visible heading 19px below the form it is meant to line up with.
 * Measured on home at 1440: heading mid 553, form mid 534.
 *
 * Three classes, so this wins on specificity rather than on which stylesheet
 * the enqueue order happens to put last. No `!important`.
 */
.cg-band.cg-subscribe .cg-subscribe__title {
	margin: 0;
}

/* ────────────────────────────────────────────────────────────────────────
 * Subscribe band: the HubSpot embed (#438).
 *
 * Everything from here down replaces ~150 lines of Gravity Forms rules —
 * `.cg-subscribe .bar-form .gform_wrapper …` — that selected nothing the
 * moment footer.php stopped rendering Gravity Form 1. They are deleted
 * rather than left as dead weight; git has them if the swap is ever undone.
 *
 * COLOUR IS NOT REPEATED HERE. The embed carries `.cg-hsform`, the shared
 * light-on-dark skin (css/components/contact-hubspot.css) the Contact page
 * and the popup already use: cream text, on-dark hairline underlines,
 * transparent inputs, the cream outline button, the accent underline on a
 * required field. All three surfaces sit on `--cg-ink`, which is why one
 * skin serves them. What this band needs on top of that is LAYOUT — and
 * the arming of the mask clock, at the bottom of the file.
 * ──────────────────────────────────────────────────────────────────────── */

/* The mask cover, painted in ink rather than the page surface: this panel is
   ON the ink band, so a cover in `--surface` (the shared default, correct on
   the cream Contact page) would flash a cream block across the band. Ink on
   ink makes the band look present from the first frame and wipes only the
   form in. Same reasoning, and same override, as the popup's. */
.cg-subscribe__form {
	--cg-hsform-mask: var( --cg-ink );
}

/*
 * THE PORTAL'S OWN INTRO COPY, HIDDEN.
 *
 * The live form carries a rich-text block reading "For the latest news from
 * Common Good, sign up below:" — quote marks included, they are in the
 * portal's configured value — which is the `subscribe_form_title` heading
 * this band already prints one column to the left, in display type.
 *
 * js/cg-contact-hubspot.js has an opt-in for exactly this
 * (`data-cg-hsform-dedupe-intro`) and it does NOT apply here: it works by
 * finding the rich-text block that carries the "* indicates required fields"
 * line and hiding that block's OTHER paragraphs, and this form has no such
 * line. So the dedupe is done in CSS, where it needs no script at all — and
 * therefore still holds in the window before the skinner runs.
 *
 * `display: none` and not `.visually-hidden`, because this is duplication:
 * a screen reader has already met this sentence as the band's own <h2>.
 *
 * SCOPED TO `.hsfc-Form`, WHICH IS NOT PEDANTRY. HubSpot replaces the whole
 * form with a `.hsfc-PostSubmit` block after a successful submit, and the
 * thank-you message inside it is ALSO a `.hsfc-RichText`. An unscoped hide
 * caught it: measured on a real submission, the POST returned 200 and the
 * band then rendered 571x0 — nothing at all where the confirmation should be.
 * A signup form that silently empties itself is worse than one that never
 * loaded, because the reader cannot tell whether it worked. Every layout rule
 * below is scoped the same way and for the same reason.
 *
 * THE LIMIT, STATED: this hides the whole rich-text module of the FORM step,
 * so genuinely NEW copy added to it in the portal would be hidden too. There
 * is no way to tell "duplicate" from "new" from content alone — the same real
 * limit the skinner's own dedupe documents. Copy for this band belongs in the
 * `subscribe_form_title` Theme Option.
 */
.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-RichText {
	display: none;
}

/*
 * ONE GRID FOR THE WHOLE FORM.
 *
 * HubSpot renders `.hsfc-Step__Content > .hsfc-Row`, one row per field group,
 * plus a `.hsfc-NavigationRow` holding the submit — a tall stack, which is
 * right for the contact form and wrong for a signup band that the CD asked to
 * be a thin horizontal module (the Gravity Form it replaces was 320px tall at
 * 1440 with its fields and button on one line).
 *
 * `display: contents` on the rows promotes the FIELDS themselves into this
 * grid, so first/last/email and the submit are genuine grid items instead of
 * four stacked full-width rows. Placement is left to auto-flow rather than
 * pinned with `grid-area`: in source order that gives
 *
 *     [ First Name ] [ Last Name ]
 *     [ Email      ] [ SUBMIT    ]
 *
 * and — the reason it is auto and not pinned — a field added to the form in
 * the portal lands in the next cell instead of on top of one of these.
 *
 * The hidden `opt_in` row and the live-region node are already
 * `display: none` / 1px in HubSpot's own markup, so unlike the Gravity Forms
 * layout this replaces there is no honeypot-in-column-1 trap to place around.
 *
 * SPECIFICITY, MEASURED NOT ASSUMED: HubSpot's own rules are
 * `[data-hsfc-id="Renderer"] .hsfc-Row` etc. — (0,2,0) — and their stylesheet
 * is injected into <head> at runtime, i.e. after every enqueued sheet, so a
 * (0,2,0) selector of ours ties and LOSES on source order. Including their
 * `[data-hsfc-id="Renderer"]` hook takes these to (0,3,0), which wins
 * outright. No `!important`, per the 2.0 cascade rules.
 */
/*
 * THE TRACKS ARE SIZED AGAINST THE CONTAINER, NOT THE VIEWPORT, AND THAT IS
 * THE WHOLE POINT.
 *
 * The first version of this rule was `grid-template-columns: 1fr 1fr` with a
 * viewport media query to switch shapes, and it shipped a form nobody between
 * 1025px and ~1150px could use. Two compounding reasons, both measured:
 *
 *   1. A `1fr` track's automatic minimum is its item's MIN-CONTENT, and the
 *      submit button is a fixed 240px (`--hsf-button__width`, from the shared
 *      skin). So column 2 pinned at 240px and column 1 got whatever was left.
 *   2. What is left is the `.cg-split` RIGHT COLUMN, which is `1fr` beside a
 *      fixed 600px — 571px at 1440, but only ~185px at 1025. A viewport media
 *      query bounded at `max-width: 1024px` treated everything above 1024 as
 *      one regime, and only its widest end was ever measured.
 *
 * Measured at 1025 before the fix: tracks `0px 240px`, First Name and Email
 * both 0px wide, `elementFromPoint` over the email field returning the grid
 * container instead of the input, and the band overflowing its own container
 * by 79px. Not "cramped" — a subscribe band with no way to enter an email
 * address, on every page of the site, at every width an iPad Pro holds in
 * landscape.
 *
 * `repeat(auto-fit, minmax(…, 1fr))` asks the CONTAINER how many columns fit,
 * which is the question that was actually being answered wrongly. It also
 * replaces the hand-written 901-1024 media query, since "four controls fit on
 * one row when the band is stacked and wide" falls out of the same maths.
 *
 * `min(100%, 190px)` rather than a bare `190px`: when the container is
 * narrower than the floor, a bare value makes the track overflow it, which is
 * how a fix for a collapse becomes a horizontal scrollbar.
 *
 * 190px is the floor because of what it buys at the two ends. It keeps 1280 —
 * an ordinary laptop, and the width `scripts/visual-qa/shoot.mjs` renders at —
 * on TWO columns (its right column is 422px; two 190px tracks plus the gap
 * need 404). And it keeps 1440 on two rather than three (three would need
 * 618px against 572), which is the shape this band was designed as. A 220px
 * floor loses 1280; a 160px floor gains nothing and starts to crowd.
 *
 * Measured after, container width -> columns: 1920 609 -> 2 · 1440 572 -> 2 ·
 * 1280 422 -> 2 · 1194 342 -> 1 · 1025 185 -> 1 · 1024 stacked 922 -> 4 (one
 * row) · 768 720 -> 3 · 390 342 -> 1. Every field usable and hittable at
 * every width, no container overflow, no page scrollbar.
 */
.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-Step__Content {
	display: grid;
	grid-template-columns: repeat( auto-fit, minmax( min( 100%, 190px ), 1fr ) );
	align-items: end;
	gap: 24px;
}

.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-Row {
	display: contents;
}

/* The navigation row stays a single grid item — `display: contents` here
   would promote its empty alerts container as well and hand it a cell.

   `min-width: 0` is load-bearing, not hygiene: without it the 240px button
   inside sets this grid item's min-content, and an `auto`-minimum track
   refuses to shrink below it — which is exactly how the 1025px collapse
   above happened. The track may now be narrower than the button wants;
   the button gives way instead of the fields (see `.hsfc-Button` below). */
.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-NavigationRow {
	display: block;
	/*
	 * PINNED TO THE LAST COLUMN, whatever the last column turns out to be.
	 *
	 * With auto-placement the submit simply took the next free cell, which is
	 * right when it lands beside the email field and wrong when it starts a
	 * row of its own: at 768 (three columns) it sat alone under First Name, at
	 * the far left, with two empty cells to its right — the button furthest
	 * from the field you fill last.
	 *
	 * `-2 / -1` is the last column line pair, so auto-placement then puts this
	 * in the first row whose last column is free. That resolves to the shape
	 * the design wants at every column count without naming any of them:
	 * 4 columns -> one row, button last · 3 -> button right, second row ·
	 * 2 -> beside the email field · 1 -> bottom of the stack.
	 */
	grid-column: -2 / -1;
	justify-self: end;
	align-self: end;
	width: 100%;
	min-width: 0;
}

.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-NavigationRow__Buttons {
	justify-content: flex-end;
}

/*
 * HubSpot's own vertical rhythm around the submit, removed — this is what
 * actually made the band tall. Measured before this rule: `.hsfc-NavigationRow`
 * carries `margin-top: 56px` and its alerts container a `margin-bottom: 28px`
 * even while empty, which as a grid item made row 2 139px tall and left a
 * ~160px void between the name fields and the email field. Both are correct in
 * the contact form's tall single column and wrong in a two-row band; the grid's
 * own 24px gap is the spacing here.
 *
 * The alerts container keeps a gap when it actually holds a validation message,
 * so an error never renders flush against the button.
 */
.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-NavigationRow {
	margin-top: 0;
}

.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-NavigationRow__Alerts {
	margin-bottom: 0;
}

.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-NavigationRow__Alerts:not( :empty ) {
	margin-bottom: 12px;
}

/*
 * THE BUTTON GIVES WAY, THE FIELDS DO NOT.
 *
 * The shared skin sets `--hsf-button__width: var( --btn-min-width )` — a flat
 * 240px, right on the Contact page's wide panel. In this band the available
 * width runs from 922px (stacked) down to ~185px (the split's right column at
 * 1025), so a fixed width here is a floor that pushes the collapse onto the
 * fields, and `max-width: 100%` alone cannot help: `100%` resolves against the
 * very track the button just sized.
 *
 * Overriding the variable is what actually works, and it also gives the
 * button the width it should have had all along: THE SAME AS THE FIELD ABOVE
 * IT. A 240px button under a 274px field left a 34px ragged edge down the
 * right of the form; filling the cell makes the column line up, at every
 * column count, without naming a single width.
 *
 * No `max-width` cap. An earlier version capped this at `--btn-min-width` so
 * the button could never exceed 240px, which reintroduced the ragged edge
 * everywhere the cell was wider — and the cap was never what stopped the
 * collapse. `min-width: 0` is.
 */
.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-NavigationRow__Buttons .hsfc-Button {
	--hsf-button__width: 100%;

	min-width: 0;
}

/* Below ~600px, two fields side by side get too narrow to type into — the
   same threshold and the same reason as the Gravity Forms layout this
   replaces. One column, four stacked controls. */
@media ( max-width: 600px ) {
	.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-Step__Content {
		/* `minmax( 0, 1fr )`, never a bare `1fr` — see the collapse note on the
		   base rule. The auto-fit track above would resolve to one column here
		   anyway; this states it, and states it in a form that cannot be
		   floored by the button's intrinsic width. */
		grid-template-columns: minmax( 0, 1fr );
		gap: 20px;
	}

	.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-NavigationRow {
		justify-self: stretch;
	}

	.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-Form .hsfc-NavigationRow__Buttons {
		justify-content: flex-start;
	}
}

/* ─── The CSS last-resort unmask needs a REQUEST-relative clock ──────────
 *
 * css/components/contact-hubspot.css ends with a `cg-hsform-unmask`
 * animation — a 1ms opacity fade after a 15s delay — as the final fail-open
 * for the mask, the one that survives the reveal script never running at
 * all. Its clock runs from PAGE LOAD, which is right on the Contact page:
 * panel and form both start there.
 *
 * IN THIS BAND THE SAME CLOCK IS A BUG, with a longer fuse than the popup's.
 * The form is lazy (js/cg-hsform-lazy.js — the band is on every page and the
 * embed is ~430KB), so on a page where the reader spends more than fifteen
 * seconds before scrolling to the bottom, the cover would have already faded
 * to nothing by the time the form was even asked for — and HubSpot's raw
 * unstyled defaults would then paint in the open. No slow network needed,
 * only an ordinary reader.
 *
 * So: no animation until the scripts are actually requested, and the delay
 * starts when `is-requested` lands (an animation begins when its
 * `animation-name` starts applying). js/cg-hsform-lazy.js adds that class at
 * the moment it injects — or immediately, if it finds the loader already
 * present because the Contact page enqueued it or the popup was opened
 * first. Three classes against the theme rule's two, so these win on
 * specificity rather than on enqueue order. Exactly the fix the popup
 * carries in wp-content/plugins/gff-contact/assets/css/gff-contact-popup.css,
 * for exactly the same reason. */
.cg-subscribe .cg-hsform-panel.is-loading::after,
.cg-subscribe .cg-hsform-panel.is-loading::before {
	animation: none;
}

.cg-subscribe .cg-hsform-panel.is-requested.is-loading::after,
.cg-subscribe .cg-hsform-panel.is-requested.is-loading::before {
	animation: cg-hsform-unmask 1ms linear 15s forwards;
}

/*
 * THE POST-SUBMIT CONFIRMATION.
 *
 * HubSpot swaps the form for a `.hsfc-PostSubmit` block holding whatever the
 * portal has configured as the thank-you message. It is deliberately OUTSIDE
 * every rule above — it is not a form and must not be laid out like one — but
 * it does need the band's own type and colour, and it needs to hold the
 * band's height so the footer does not jump upward the moment someone
 * subscribes.
 */
.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-PostSubmit {
	/* Through HubSpot's own property contract, the way the shared skin does
	   it — the message is a `.hsfc-RichText`, which the skin dims to
	   `--cg-grey` at 14px because there it is a footnote under the fields.
	   Here it is the entire content of the band and the reader's only
	   confirmation that the submit worked, so it reads as body copy. */
	--hsf-richtext__color: var( --cg-cream );
	--hsf-richtext__font-size: 18px;

	display: flex;
	align-items: center;
	min-height: 104px;
}

/*
 * The portal's configured message ends with a whitespace-only paragraph — a
 * stray blank line in the rich-text editor, not something this end can fix.
 * It is a real line box, so with the panel centred against the heading it
 * pushed the visible sentence 21px above the heading it lines up with
 * (measured: panel mid 567 = heading mid 567, sentence mid 546).
 *
 * Zeroing the paragraph margins recovers 20px of that. The remaining ~11px is
 * the blank line's own line box, and it stays: removing it would mean hiding
 * the last paragraph of a block the portal owns, which would silently swallow
 * a second sentence the day someone writes one. A stray blank line is worth
 * deleting in HubSpot, not worth guessing about in CSS.
 */
.cg-hsform--subscribe [data-hsfc-id="Renderer"] .hsfc-PostSubmit p {
	margin: 0;
}
