/**
 * Components.
 *
 * ---------------------------------------------------------------------------
 * 🔴 CHROME PADDING AND RADII ARE IN `px`, DELIBERATELY. DO NOT "MODERNISE"
 * THEM TO `rem`.
 * ---------------------------------------------------------------------------
 *
 * Type is in `rem`/`clamp()` and must stay that way — text has to scale when a
 * reader enlarges it. The padding, gaps and corner radii of cards, buttons and
 * chips are in `px`, which is also how the handoff writes every one of them:
 * "padding: 18px 20px", "border-radius: 16px", "gap 16–20px".
 *
 * ⚠️ I CONVERTED THESE TO `rem` ON MY OWN INITIATIVE AND IT CAUSED A MEASURED
 * REGRESSION. `rem` padding scales with text and compounds through nesting, so
 * at 200% text a `1.25rem` pad renders at 40px per side. The fact cards went
 * from no padding at all to 40px each side, and `/contact/` went from 369px to
 * 411px of horizontal overflow in a 320px viewport — I made an existing
 * accessibility defect worse while believing I was following the packet more
 * closely.
 *
 * Padding does not have to scale to satisfy WCAG; TEXT does, and it still
 * does. So `px` here is both what the packet specifies and what avoids the
 * overflow, and there is no tension between the two to resolve.
 */

/*
 * ---------- Buttons ----------
 *
 * The handoff's figures: pill radius, 700 weight, 15.5px, 13px/24px padding,
 * `min-height: 48px`, `white-space: nowrap`. Every prototype button carries
 * all six.
 *
 * `--ih-touch` (44px) is the floor underneath the packet's 48px, not an
 * alternative to it. 48px satisfies the floor with room to spare, so this is
 * one of the rare cases where the design and the accessibility minimum agree
 * and the design is the stricter of the two.
 */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--ih-space-2);
	min-height: 48px;
	padding: 13px 24px;

	/*
	 * ⚠️ A BUTTON MUST BE ABLE TO SHRINK, and `white-space: normal` alone
	 * does not let it. Measured at 200% text in a 320px viewport: "Get
	 * directions now" rendered 358px wide with wrapping already enabled and
	 * the padding already in px, because a flex item defaults to
	 * `min-width: auto` and therefore refuses to go below its longest word.
	 * `.cta-group` wraps correctly and it did not help — the group was
	 * stacked and one button still overhung the page by 61px.
	 *
	 * `max-width: 100%` lets it shrink to its container; `overflow-wrap:
	 * anywhere` is what makes the shrinking possible, and the value matters.
	 * `break-word` does NOT count the broken form toward min-content, so the
	 * box still refuses to narrow; only `anywhere` does. That distinction is
	 * the El Mirage session's, from the pass that took them to zero
	 * overflowing pages.
	 *
	 * Breaking a word mid-label is ugly. A horizontal scrollbar on every
	 * page for anyone using large text is worse, and this only engages at
	 * widths where the alternative is overflow.
	 */
	max-width: 100%;
	overflow-wrap: anywhere;
	border: 2px solid transparent;
	border-radius: var(--ih-radius-pill);
	font-family: var(--ih-font-sans);
	font-size: 0.96875rem; /* 15.5px */
	font-weight: var(--ih-weight-bold);
	line-height: 1;
	text-decoration: none;
	cursor: pointer;

	/*
	 * 🔴 THE PACKET'S `white-space: nowrap` IS CONDITIONAL, in the query
	 * below. Measured at 200% text in a 320px frame on staging:
	 *
	 *   "Call <the main number>"  360px  — right edge 444 in a 320px viewport
	 *   "Get Directions"          293px  — right edge 377
	 *   "Patient Portal"          289px  — right edge 321
	 *
	 * ⚠️ I GOT THIS WRONG ONCE BY SAMPLING ONE PAGE. The previous release
	 * deleted this guard and its commit message stated that the widest button
	 * fits either way. That was measured on a single interior page, where the
	 * widest visible button is "Patient Portal" and the claim happens to
	 * hold. It does not hold on an article, whose disclaimer CTA spells out a
	 * phone number — and a phone number is the one label that must not break
	 * mid-string, so it is simultaneously the widest and the least wrappable
	 * thing on the site.
	 *
	 * A button label is variable-length CONTENT. One page's widest button
	 * says nothing about another's, and the only honest test is every page.
	 *
	 * `rem` IS THE MECHANISM: a `px` query asks only about the viewport; a
	 * `rem` query asks about the viewport measured in the reader's own text
	 * size. At 200% text 30rem is 960px, so a phone does not match and the
	 * labels wrap. At default text it is 480px, every phone matches, and the
	 * packet's nowrap is what ships.
	 */
	white-space: normal;
	transition: background-color var(--ih-duration) var(--ih-ease),
		color var(--ih-duration) var(--ih-ease),
		border-color var(--ih-duration) var(--ih-ease);
}

@media (min-width: 30rem) {
	.btn {
		white-space: nowrap;
	}
}

/*
 * The lift the handoff gives the primary action — "Primary CTA shadow: 0 10px
 * 24px rgba(190,30,45,0.28)", which is exactly `--ih-shadow-cta`.
 *
 * That token was added with the re-theme and then referenced by nothing, so
 * every primary button on the site rendered flat while the stylesheet read as
 * though it did not. A defined-but-unused custom property is the quietest way
 * for a spec line to go unimplemented: it reads as done in tokens.css,
 * `check-css` sees a legitimate declaration, and no gate asks whether
 * anything consumes it. Found by diffing the rendered site against the
 * reference prototype rather than by reading either file.
 *
 * The same shape as the three components core shipped that nothing called,
 * and the `healthpass` config key that sat unused for weeks: a declared thing
 * with no call site reads as shipped and stays invisible until somebody greps.
 */
.btn--primary {
	background: var(--ih-brand);
	border-color: var(--ih-brand);
	color: var(--ih-white);
	box-shadow: var(--ih-shadow-cta);
}

.btn--primary:hover,
.btn--primary:focus-visible {
	background: var(--ih-brand-deep);
	border-color: var(--ih-brand-deep);
	color: var(--ih-white);
}

/*
 * 🔴 `--ih-brand-deep`, NOT `--ih-brand`, BECAUSE A GHOST BUTTON IS NOT ALWAYS
 * ON WHITE.
 *
 * Measured on the homepage: "How billing works" inside `aside.notice` rendered
 * brand red on `--ih-brand-tint` at **4.45:1** — a miss by 0.05 against the
 * 4.5 requirement. On white the same button is 6.0:1 and fine, which is why it
 * survived: the colour is correct in the place it was designed and wrong in
 * five other places it is used. **Five containers in this file set
 * `--ih-brand-tint` as a background.**
 *
 * ⚠️ FIXED ON THE BUTTON, NOT ON THE CONTAINERS, and that choice is the whole
 * point. The obvious fix is `.notice .btn--ghost { … }` — and I have now
 * shipped the container-specific version of this mistake twice tonight, in the
 * footer and in the header, each time patching the place instead of the thing.
 * A list of tinted containers is a list somebody has to keep, and the next
 * tinted container rediscovers the bug.
 *
 * `--ih-brand-deep` passes on both: 9.1:1 on white, 6.8:1 on the tint. The
 * hover state is untouched and still clearly distinct — a deep-red outline
 * becomes a solid brand-red fill with white text — so nothing is lost by
 * making the resting state darker.
 */
.btn--ghost {
	background: transparent;
	border-color: currentColor;
	color: var(--ih-brand-deep);
}

/*
 * The NEUTRAL outline pill — the packet's Patient Portal control in the
 * navigation: "border 1.5px #d9d2cf → red on hover".
 *
 * Distinct from `.btn--ghost`, which borders in `currentColor` and therefore
 * in brand red. Two red controls side by side in the nav would give equal
 * weight to the portal and the phone number; the packet deliberately makes
 * one quiet so the other is the obvious action. Grey at rest, brand on
 * hover, so it still announces itself as interactive.
 *
 * 🔴 `--ih-grey-400` (#d9d2cf), THE PACKET'S OWN VALUE. This shipped as
 * `--ih-grey-300` (#efeae8) with a note reasoning that the scale had no
 * #d9d2cf step and adding one for a single border would be drift. Fair
 * reasoning, wrong conclusion twice over: the value is used for two things in
 * the handoff, not one — this border and the grey top rule on the CMS
 * comparison stat card — and #efeae8 is the DIVIDER grey, which is nearly
 * invisible as an outline on white. That is right for a rule between two rows
 * and wrong for the edge of a control, which is exactly why the packet names
 * a darker value for this job.
 *
 * The note also said "if it reads too light beside the red pill, that is the
 * value to revisit". It does, and the client's instruction is to render the
 * packet exactly, so it is revisited rather than left as a known deviation
 * with a comment attached.
 *
 * 1.5px, also the packet's, against `.btn`'s 2px default.
 */
.btn--outline {
	background: var(--ih-white);
	border-width: 1.5px;
	border-color: var(--ih-grey-400);
	color: var(--ih-ink);
}

.btn--outline:hover,
.btn--outline:focus-visible {
	border-color: var(--ih-brand);
	color: var(--ih-brand);
}

.btn--ghost:hover,
.btn--ghost:focus-visible {
	background: var(--ih-brand);
	border-color: var(--ih-brand);
	color: var(--ih-white);
}

/* For use on a dark or photographic background */
.btn--inverse {
	background: var(--ih-white);
	border-color: var(--ih-white);
	color: var(--ih-brand);
}

.cta-group {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ih-space-3);
}

/* ---------- Utility bar ---------- */

/*
 * REBUILT 2026-09-13, from near-black to brand red.
 *
 * The client put his live site's header beside the staging one: "there are no
 * real navigation bar on the staging site either." The old bar was a dark
 * strip carrying one phone number and an address in running text.
 *
 * Red is not decoration here. This band holds the two things a person in
 * trouble needs before they have read anything — a number to call and
 * confirmation the place is open — so it should read as the most deliberate
 * element on the page rather than the quietest.
 */
.utility-bar {
	background: var(--ih-brand);
	color: var(--ih-white);
	font-size: var(--ih-text-sm);
}

.utility-bar__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--ih-space-3) var(--ih-space-5);
	min-height: 48px;
	padding-block: var(--ih-space-2);
}

.utility-bar a {
	color: var(--ih-white);
	text-decoration: none;
}

.utility-bar a:hover,
.utility-bar a:focus-visible {
	color: var(--ih-white);
	text-decoration: underline;
}

.utility-bar__phones,
/*
 * Phones to the right, which is the packet's `margin-left: auto`. The status
 * and the address lead; the numbers end the line.
 *
 * `auto` on the inline-start margin rather than `justify-content: flex-end`
 * on the parent, because the parent is a wrapping flex row: at narrow widths
 * the phones drop onto their own line, and a flex-end parent would also push
 * the status and address across, which the packet does not do.
 */
.utility-bar__phones {
	margin-inline-start: auto;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--ih-space-2) var(--ih-space-4);
}

/*
 * The packet's tel: links: label and number as one nowrap string, weight
 * 600, the secondary lines at 0.9 opacity so the main number leads without
 * the others looking disabled.
 *
 * `min-height: var(--ih-touch)` is not in the drawing and stays anyway —
 * 44px is the WCAG floor for a tap target and these are tappable on a phone.
 * A design that styles for desktop does not license shipping a 20px target.
 */
.utility-bar__tel {
	display: inline-flex;
	align-items: center;
	min-height: var(--ih-touch);
	color: var(--ih-white);
	font-weight: var(--ih-weight-semibold);
	text-decoration: none;

	/*
	 * ⚠️ NOWRAP ONLY WHERE IT FITS, and I shipped it unconditionally. The
	 * packet draws `white-space: nowrap` on these links and that is right at
	 * the width it draws them for — but a LABEL PLUS A NUMBER IS
	 * VARIABLE-LENGTH CONTENT, which is the exact trap the El Mirage session
	 * warned about after clearing the same question on `.btn` from a
	 * one-page sample and having to revert a release.
	 *
	 * Measured, not assumed: on the multi-facility site a two-word service
	 * label plus its number renders 367px at 200% text in a 320px viewport,
	 * and put a horizontal scrollbar on fourteen of sixteen pages. The
	 * single-facility sites never saw it, having no third line and no label
	 * that long — the family's longest label belongs to the site that is two
	 * facilities at one address.
	 *
	 * (The number itself is deliberately left out. `check-phones` fails the
	 * build on a client's number appearing in shared core and is right to:
	 * this file rolls to every site in the family. That gate has now caught
	 * this three times in one day across two sessions, every time while
	 * somebody quoted a genuine measurement into a comment.)
	 *
	 * A phone number SHOULD resist breaking mid-number, so the flag is kept
	 * above 30rem where there is room for it. Same mechanism as `.btn`.
	 */
	white-space: normal;
}

@media (min-width: 30rem) {
	.utility-bar__tel {
		white-space: nowrap;
	}
}

.utility-bar__tel--secondary {
	opacity: 0.9;
}

.utility-bar__tel:hover,
.utility-bar__tel:focus-visible {
	text-decoration: underline;
	color: var(--ih-white);
	opacity: 1;
}

/*
 * The white status dot. The packet leads the bar with it rather than with an
 * icon: at 8px it reads as a live indicator — the shape a service-status
 * light has — where a clock glyph reads as "opening hours" and invites the
 * reader to go looking for them.
 *
 * `aria-hidden` in the markup and no text alternative, deliberately: the
 * words beside it already say "Open now", so announcing the dot would repeat
 * the sentence it decorates.
 */
.utility-bar__dot {
	inline-size: 8px;
	block-size: 8px;
	border-radius: 50%;
	background: var(--ih-white);
	flex: none;
}

/*
 * Scoped to the three text items rather than to `.utility-bar svg`, which
 * would have collided with `.social-links svg` at identical specificity and
 * been settled by source order — a rule that works by accident of position is
 * a rule that breaks when somebody reorders the file.
 */
.utility-bar__where svg,
.utility-bar__open svg {
	width: 1em;
	height: 1em;
	flex: none;
}

/* On the red band, a red hover state would be invisible. */
.utility-bar .social-links {
	list-style: none;
	margin: 0;
	padding: 0;
}

.utility-bar .social-links a {
	width: 2.25rem;
	height: 2.25rem;
	border-color: rgba(255, 255, 255, 0.45);
}

.utility-bar .social-links a:hover,
.utility-bar .social-links a:focus-visible {
	background: var(--ih-white);
	border-color: var(--ih-white);
	color: var(--ih-brand);
}

.utility-bar__where,
.utility-bar__open {
	display: inline-flex;
	align-items: center;
	gap: var(--ih-space-2);
	margin: 0;
}

/*
 * ---------- The utility bar's phone links ----------
 *
 * ⚠️ THE PILLS ARE GONE, AND THEY WERE NEVER IN THE HANDOFF. This block used
 * to style `.phone-pill` — a bordered, padded chip invented by this theme's
 * 2026-09-13 header rebuild. The packet draws plain `tel:` links, a label and
 * number in one string ("Main …", "Billing …"), weight 600, secondary at 0.9
 * opacity.
 *
 * (The numbers themselves are deliberately not written here. `check-phones`
 * fails the build on a client's number appearing in shared core, and it is
 * right to: this file rolls to every site in the family.)
 *
 * It was not only a fidelity gap. On the multi-facility site three chips plus
 * the status line and the address do not fit 1180px, so the packet's single
 * bar wrapped to two rows. The invented component was also the reason a
 * previous session had to add a `white-space` media query here: a labelled
 * chip measured 294px at 200% text in a 250px content area and pushed a
 * horizontal scrollbar onto every page. Text links do not have that problem,
 * so that workaround retires with the component it was propping up.
 *
 * The replacement rules are `.utility-bar__tel` above, and they keep
 * `min-height: var(--ih-touch)` — 44px is the WCAG floor whatever the drawing
 * shows.
 */

@media (max-width: 30em) {
	/*
	 * On the narrowest handsets the LABEL is dropped, never the number. Two
	 * pills each showing a different number remain distinguishable; two
	 * reading "Main" and "Billing" with no number do not, and the number is
	 * the thing being reached for.
	 *
	 * ⚠️ THE EXAMPLE NUMBERS ARE GONE FROM THIS COMMENT ON PURPOSE. It used to
	 * illustrate the point with El Mirage's actual main and billing lines, and
	 * `check-phones` reported both as unknown numbers here — correctly, because
	 * canonical has no site config to declare them against.
	 *
	 * It is a small leak and a real one: **this stylesheet ships to all eight
	 * sites**, so a visitor to any sister facility was downloading a CSS file
	 * containing El Mirage's billing number. A comment is not a rendered page,
	 * but a CSS file is served verbatim.
	 *
	 * Pre-existing rather than newly introduced — the finding only surfaced
	 * when the gate started blanking SVG geometry in every file rather than
	 * only in `.svg`, which is when this repo's own phone audit began being run
	 * at all.
	 */
	/*
	 * The label-hiding rule that used to live here went with `.phone-pill`.
	 * It dropped "Main"/"Billing" on the narrowest handsets so two chips
	 * stayed distinguishable by their numbers. The text links carry label and
	 * number as one string and wrap normally, so there is nothing to hide.
	 */

	/* The address is the one item a phone can spare — it is on /contact/. */
	.utility-bar__where {
		display: none;
	}
}

/* ---------- Header ---------- */

.site-header {
	position: sticky;
	top: 0;
	z-index: 100;
	background: var(--ih-white);
	border-bottom: 1px solid var(--ih-border);
	box-shadow: var(--ih-shadow-sm);
}

.site-header__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--ih-space-4);
	min-height: 72px;
	padding-block: var(--ih-space-3);
}

/*
 * The lockup is a 3:1 wordmark, so height governs it, not width.
 *
 * 52px at desktop. The first attempt was 44 and it was measured too small: at
 * 132 × 44 the third line of the lockup — "An Instinctive Healthcare Solutions
 * Company" — is present and illegible, which is worse than absent. 36px on a
 * handset keeps the logo and the menu button on one row.
 */
.site-branding img,
.site-branding .custom-logo {
	max-height: 52px;
	width: auto;
	height: auto;
}

@media (max-width: 48em) {
	.site-branding img,
	.site-branding .custom-logo {
		max-height: 36px;
	}
}

.site-branding__text {
	font-family: var(--ih-font-display);
	font-size: var(--ih-text-lg);
	font-weight: var(--ih-weight-bold);
	color: var(--ih-ink);
	text-decoration: none;
}

/* ---------- Header actions: search and the partner CTA ---------- */

.primary-nav__actions {
	display: flex;
	align-items: center;
	gap: var(--ih-space-3);
	margin-left: auto;
}

.search-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: var(--ih-touch);
	height: var(--ih-touch);
	padding: 0;
	background: var(--ih-brand);
	border: 2px solid var(--ih-brand);
	border-radius: 50%;
	color: var(--ih-white);
	cursor: pointer;
	transition: background-color var(--ih-duration) var(--ih-ease);
}

.search-toggle:hover,
.search-toggle:focus-visible {
	background: var(--ih-brand-deep);
	border-color: var(--ih-brand-deep);
}

.search-toggle svg {
	width: 18px;
	height: 18px;
}

.btn--pill {
	padding-inline: var(--ih-space-5);
}

/*
 * The outbound arrow on the HealthPass button.
 *
 * HealthPass is a separate company. The footer marks that with a text link
 * where the facility's own tools get buttons — but in the header it has to be
 * a button to be seen at all, so the disclosure moves to the arrow plus the
 * screen-reader text saying a partner site opens in a new tab. The visual
 * difference still exists; it is just carried differently.
 */
.header-cta {
	gap: var(--ih-space-2);
}

.header-cta__out {
	font-size: 0.85em;
	line-height: 1;
}

/* ---------- Search panel ---------- */

.site-search {
	border-top: 1px solid var(--ih-border);
	background: var(--ih-surface-alt);
}

.site-search > .container {
	padding-block: var(--ih-space-4);
}

/*
 * ⚠️ COLLAPSED BY THE CLASS, NOT BY DEFAULT. `navigation.js` adds
 * `is-collapsed` and unhides the toggle button. With JavaScript off the panel
 * stays open and the button stays hidden, so a visitor gets a working search
 * field rather than a button that does nothing.
 */
.site-search.is-collapsed {
	display: none;
}

.site-search .search-form {
	display: flex;
	gap: var(--ih-space-3);
	align-items: center;
}

.site-search .search-field {
	flex: 1 1 auto;
	min-height: var(--ih-touch);
	padding: var(--ih-space-2) var(--ih-space-4);
	border: 2px solid var(--ih-border);
	border-radius: var(--ih-radius-pill);
	font-family: inherit;
	font-size: var(--ih-text-base);
}

.site-search .search-field:focus-visible {
	outline: var(--ih-focus-width) solid var(--ih-focus);
	outline-offset: 2px;
}

.site-search .search-submit {
	min-height: var(--ih-touch);
	padding: var(--ih-space-2) var(--ih-space-5);
	background: var(--ih-brand);
	border: 2px solid var(--ih-brand);
	border-radius: var(--ih-radius-pill);
	color: var(--ih-white);
	font-family: inherit;
	font-weight: var(--ih-weight-bold);
	cursor: pointer;
}

/* ---------- The menu button ---------- */

/*
 * Three bars drawn in CSS rather than the `&#9776;` character the old button
 * used. That glyph renders at wildly different weights across platforms and is
 * announced by some screen readers as "trigram for heaven", which is why the
 * label beside it is `screen-reader-text` rather than an aria-label on a
 * character.
 */
.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
	display: block;
	width: 22px;
	height: 2px;
	background: currentColor;
	border-radius: 2px;
	content: "";
}

.nav-toggle__bars::before {
	transform: translateY(-7px);
}

.nav-toggle__bars::after {
	transform: translateY(5px);
}

/* ---------- Primary navigation ---------- */

/*
 * ⚠️ `.primary-nav` HAD NO DISPLAY AT DESKTOP, so it fell back to `block` and
 * the menu list and the action group stacked. With the actions added in 1.10.0
 * the masthead grew to 157px tall in three rows: links, then a row of orphaned
 * submenu carets, then the search button and the CTA.
 *
 * It was invisible before, because a nav containing only a list has nothing to
 * stack against. Adding a second child is what surfaced it — the layout was
 * always wrong and had never been asked to hold two things.
 */
/*
 * `flex-wrap: wrap` here too, so the actions group can drop BELOW the menu
 * rather than overflow beside it. Without it the list wraps internally and the
 * search button and CTA still run off the edge, which is half a fix. See the
 * resize-text note on `.primary-nav__list`.
 */
.primary-nav {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	flex-wrap: wrap;
	flex: 1 1 auto;
	gap: var(--ih-space-5);
}

.primary-nav__list {
	display: flex;
	/*
	 * 🔴 `wrap`, AND THE `nowrap` THIS REPLACES FAILED WCAG 1.4.4 (RESIZE TEXT).
	 *
	 * The old comment read: *"`nowrap` on purpose. A wrapping primary nav on a
	 * desktop masthead makes the header change height as the menu grows, and
	 * this menu is five items with three dropdowns — it fits."*
	 *
	 * **It fits at 100% text and not at 200%.** Measured by doubling the root
	 * font size on the rendered homepage: the document scroll width went from
	 * 1369 to 1411 against a 1384 viewport, and `.primary-nav`,
	 * `.primary-nav__actions` and the `Join HealthPass` button all pushed past
	 * the right edge. So at the text size a person with low vision actually
	 * uses, **the header's call to action goes off the screen.**
	 *
	 * ⚠️ A MEDIA QUERY CANNOT SAVE THIS, which is why it hid. The drawer
	 * breakpoint is `@media (min-width: 64.0625em)`, and `em` and `rem` in a
	 * media query both resolve against the INITIAL font size, never the root —
	 * so doubling text does not narrow the breakpoint and the desktop nav
	 * stays, at twice the size, in the same space.
	 *
	 * Wrapping is the right answer and the old objection still holds at 100%:
	 * at normal size the row fits, so it does not wrap and the masthead stays
	 * one row — the 157px three-row header is not coming back, and that is
	 * verified after this change rather than assumed. Wrap engages only when
	 * the content genuinely does not fit, which is the case the old rule
	 * refused to handle.
	 *
	 * Below 1024px the mobile drawer takes over and stacks vertically, which is
	 * still the right answer there.
	 */
	flex-wrap: wrap;
	align-items: center;
	gap: var(--ih-space-4);
	margin: 0;
	padding: 0;
	list-style: none;
}

.primary-nav__list li {
	margin: 0;
	position: relative;
}

/*
 * The parent link and its caret share a row.
 *
 * `navigation.js` injects the toggle as a SIBLING of the link, and both are
 * block-level — the link is `display: flex` — so they stacked, which is where
 * the row of orphaned carets under the menu came from. The list item has to be
 * the flex container; neither child can fix it alone.
 */
.primary-nav__list > li.menu-item-has-children {
	display: flex;
	align-items: center;
}

/*
 * 🔴 `:not(.btn)` IS LOAD-BEARING, AND WITHOUT IT THE HEADER'S MAIN CALL TO
 * ACTION FAILED CONTRAST ON EVERY PAGE.
 *
 * `Join HealthPass` sits inside `.primary-nav`, so `.primary-nav a` at (0,1,1)
 * beat `.btn--primary`'s own `color: var(--ih-white)` at (0,1,0). The button
 * rendered **near-black ink on brand red: 3.38:1, against a 4.5 requirement**,
 * measured on the rendered homepage. It looked like a deliberate dark-on-red
 * treatment, which is why nobody questioned it.
 *
 * ⚠️ THIS IS THE SECOND TIME THIS EXACT ACCIDENT HAS SHIPPED HERE, and the
 * first fix is forty lines from being the reason. `.site-footer a` — also
 * (0,1,1) — beat `.btn--inverse` and rendered Patient Portal and Pay Your Bill
 * as pale grey on white. I fixed that one and wrote that it was scoped to
 * `.btn` rather than to `.btn--inverse` "so any future variant placed in the
 * footer inherits the fix instead of rediscovering the bug."
 *
 * **Right about variants, wrong about places.** The bug is not about the
 * footer or about which modifier; it is that **any container which colours its
 * descendant anchors silently outranks every button inside it.** I generalised
 * across the wrong axis and left the identical defect in the header, on a
 * bigger button, for a day.
 *
 * So the rule is stated where it can be reused: **a button is not a link for
 * colour purposes.** Any future container that colours anchors gets the same
 * `:not(.btn)`, and `check-theme` cannot catch the next one — both rules are
 * valid, both match real elements, and the failure only exists once the
 * cascade resolves.
 */
.primary-nav a:not(.btn) {
	display: flex;
	align-items: center;
	min-height: var(--ih-touch);
	color: var(--ih-ink);
	font-weight: var(--ih-weight-medium);
	text-decoration: none;
	letter-spacing: 0.01em;
}

.primary-nav a:not(.btn):hover,
.primary-nav a:not(.btn):focus-visible,
.primary-nav .current-menu-item > a:not(.btn) {
	color: var(--ih-brand);
}

.primary-nav .current-menu-item > a {
	box-shadow: inset 0 -2px 0 var(--ih-brand);
}

/* Submenus: hidden by default, shown on hover and on focus-within for keyboards */
.primary-nav .sub-menu {
	position: absolute;
	top: 100%;
	left: 0;
	z-index: 10;
	min-width: 240px;
	margin: 0;
	padding: var(--ih-space-2) 0;
	list-style: none;
	background: var(--ih-white);
	border: 1px solid var(--ih-border);
	border-radius: var(--ih-radius);
	box-shadow: var(--ih-shadow);
	opacity: 0;
	visibility: hidden;
	transform: translateY(-4px);
	transition: opacity var(--ih-duration) var(--ih-ease),
		transform var(--ih-duration) var(--ih-ease),
		visibility var(--ih-duration);
}

.primary-nav li:hover > .sub-menu,
.primary-nav li:focus-within > .sub-menu,
.primary-nav .sub-menu.is-open {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

.primary-nav .sub-menu a {
	padding: var(--ih-space-2) var(--ih-space-4);
}

/*
 * 🔴 THE LAST TWO DROPDOWNS OPEN LEFTWARD, found by the 200%-text re-sweep
 * after the full-width rebuild: the About submenu's hidden box crossed the
 * right edge by 12px on EVERY page — `visibility: hidden` keeps layout, so a
 * closed dropdown still widens `scrollWidth` — and an opened one would have
 * clipped its own links against the viewport. At 100% it fit by luck of
 * label length, which is exactly how a doubled font finds these.
 *
 * `nth-last-child(-n+2)` rather than `last-child` because the rightmost item
 * (Patient Portal) carries no submenu — the offender is second from the end,
 * and the next menu edit could make it last. Right-aligning menus near the
 * right edge is ordinary dropdown etiquette; the left-opening transform is
 * unchanged.
 *
 * ⚠️ `.primary-nav__list > li`, NOT `.primary-nav > li`. The first shipped
 * version used the latter, matched ZERO elements, and re-measured +12px as if
 * nothing had deployed — the items are children of the inner `__list` UL, not
 * of the nav. Verified this selector matches exactly one submenu on the live
 * DOM before this second deploy, because a rule with no element behind it is
 * the failure this stylesheet keeps writing warnings about, and no gate sees
 * it.
 */
.primary-nav__list > li:nth-last-child(-n+2) .sub-menu {
	left: auto;
	right: 0;
}

.nav-toggle {
	display: none;
	align-items: center;
	gap: var(--ih-space-2);
	min-height: var(--ih-touch);
	min-width: var(--ih-touch);
	padding: var(--ih-space-2) var(--ih-space-3);
	background: transparent;
	border: 2px solid var(--ih-border);
	border-radius: var(--ih-radius);
	color: var(--ih-ink);
	font-weight: var(--ih-weight-bold);
	cursor: pointer;
}

@media (max-width: 1024px) {
	.nav-toggle {
		display: inline-flex;
	}

	.primary-nav {
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		display: none;
		padding: var(--ih-space-4) var(--ih-gutter) var(--ih-space-6);
		background: var(--ih-white);
		border-bottom: 1px solid var(--ih-border);
		box-shadow: var(--ih-shadow-lg);
		max-height: calc(100vh - 72px);
		overflow-y: auto;
	}

	.primary-nav.is-open {
		display: block;
	}

	.primary-nav__list {
		flex-direction: column;
		gap: 0;
	}

	.primary-nav__list > li {
		border-bottom: 1px solid var(--ih-border);
	}

	.primary-nav a {
		padding-block: var(--ih-space-3);
	}

	/* Submenus stack inline on small screens rather than overlaying */
	.primary-nav .sub-menu {
		position: static;
		display: none;
		opacity: 1;
		visibility: visible;
		transform: none;
		box-shadow: none;
		border: 0;
		padding-inline-start: var(--ih-space-4);
	}

	.primary-nav .sub-menu.is-open {
		display: block;
	}
}

/* ---------- Hero ---------- */

.hero {
	position: relative;
	padding-block: var(--ih-space-9);
	background: var(--ih-surface-alt);
	overflow: hidden;
}

.hero__inner {
	position: relative;
	z-index: 2;
	max-width: 46rem;
}

/*
 * 🔴 THE HERO EYEBROW IS THE PAGE KICKER. One component, and it had two
 * definitions that disagreed — spotted by the Mercy Grace session, which put
 * it exactly right: "`.hero__eyebrow` is `.page-kicker` under another name,
 * half a pixel different".
 *
 * Measured before merging them: 14px against the packet's 13.5px, and
 * 4px/12px padding against 7px/16px. Two tint pills on one site, one of them
 * a step smaller and tighter than the drawing, for no reason anybody chose —
 * the hero version simply predated the kicker and nobody reconciled them.
 *
 * ⚠️ The rule now lives ONCE, on `.page-kicker` further down this file, with
 * `.hero__eyebrow` in its selector list. Its one real difference — a 22px
 * bottom margin against an interior page's 20px — is set immediately after
 * that rule rather than here, because the shared declaration uses the
 * `margin` SHORTHAND and would silently overwrite an override placed above it
 * at equal specificity.
 */

.hero__title {
	margin-bottom: var(--ih-space-4);
}

/*
 * The handoff's red clause inside the headline — "not an urgent care." on El
 * Mirage. `--ih-brand` on white is 6.15:1, and this is display-size text, so
 * the lighter brand red belongs here where body copy would need
 * `--ih-brand-deep`.
 *
 * Colour carries no meaning a reader would otherwise miss: the sentence says
 * the same thing read flat. That is what keeps it inside WCAG 1.4.1 rather
 * than making it a use of colour as information.
 */
.hero__title-em {
	color: var(--ih-brand);
}

.hero__lede {
	font-size: var(--ih-text-lg);
	color: var(--ih-text-muted);
	margin-bottom: var(--ih-space-6);
}

/*
 * ---------- The hero photograph, and the split hero ----------
 *
 * 🔴 CORE'S HERO HAD NO MEDIA SLOT, so El Mirage put a photograph in a child
 * `front-page.php` override — which is most of why that override exists, and
 * its own docblock lists the cost: core's homepage improvements stop reaching
 * that site. This closes the gap rather than working around it.
 *
 * 🔴 AND THE STACKED HERO MEASURED 1,544px TALL. A 736px text column centred
 * in a 1,263px section — so roughly 260 pixels of empty tint on *both* sides
 * of the most important text on the site, reading as a floating island — and
 * then a full-bleed 3:2 photograph 842 pixels tall as a separate band beneath
 * it. The client's word for his old site was "fluid", and a headline island
 * stacked on a photograph band is the opposite of that.
 *
 * `.hero__text` wraps the copy so `.hero__inner` can become the grid. It is
 * one wrapper div and it buys the whole layout, because `.hero__inner` is
 * already the `.container` — so the text's left edge lands exactly on the page
 * grid with no percentage arithmetic, and the photograph's right edge lands on
 * the container's, consistent with every other section on the page.
 *
 * ⚠️ CONTAINED RATHER THAN HALF-BLEED, having tried the arithmetic for the
 * bleed first. A right-bleeding photograph wants the media absolutely
 * positioned to full section height — and this photograph is a wide building
 * shot, so a full-height column crops it to portrait and throws away the
 * building. The thing the picture is for is recognition: *someone driving to
 * an emergency room at three in the morning is looking for a door they can
 * recognise.* A crop that loses the door is a worse failure than a layout
 * that does not bleed.
 */
.hero__text {
	min-width: 0;
}

.hero__media {
	margin: var(--ih-space-6) 0 0;
	padding: 0;

	/* Positioning context for .hero__badge; inert when there is no badge. */
	position: relative;
}

/*
 * ---------- The hero badge: one fact, on the photograph ----------
 *
 * An opaque card sitting ON the image, never type painted over it. The reason
 * is in `ih_hero_media()`'s docblock and is worth repeating where the rule is
 * implemented: text over a photograph carries no contrast guarantee, because
 * the pixels behind it change with the crop, the viewport and the site. Here
 * the background is `--ih-surface`, so the guarantee holds everywhere.
 *
 * Renders only when a site sets `hero.badge.title`, so this whole block is
 * inert on sites that have not opted in.
 */
.hero__badge {
	position: absolute;
	inset-inline-start: var(--ih-space-4);
	inset-block-end: var(--ih-space-4);

	/* Never wider than the image it sits on, minus its own two insets. */
	max-width: calc(100% - (var(--ih-space-4) * 2));

	display: flex;
	align-items: center;
	gap: var(--ih-space-3);

	padding: var(--ih-space-3) var(--ih-space-4);
	background: var(--ih-surface);

	/*
	 * ⚠️ NOT `--ih-radius` (8px) AND NOT `--ih-shadow-lg`. This is the
	 * handoff's floating "Open 24/7" chip, and the reference prototype gives
	 * it `border-radius: 16px; box-shadow: 0 12px 32px rgba(32,30,29,0.18)`.
	 *
	 * 8px made a card-shaped element read as an input. The shadow matters
	 * more: `--ih-shadow-lg` is the 30%-alpha POPUP elevation, and at this
	 * size on a photograph it looked like a dialog had landed on the hero
	 * rather than a label resting on it.
	 *
	 * 🔴 16px LITERAL, NOT `--ih-radius-lg` (20px). The FHMC session reached
	 * for the 20px token here on the argument that it is the card step and
	 * falls inside the packet's stated 16–24px card range. That is a sound
	 * systems argument and it loses to a specific instruction: the drawing
	 * says 16px, and the client's words were "render it exactly as it
	 * instructs". A range in the prose does not license overriding a figure
	 * in the prototype.
	 */
	border-radius: 16px;
	box-shadow: var(--ih-shadow-float);
}

.hero__badge-icon {
	flex: none;
	display: grid;
	place-items: center;
	inline-size: 42px;
	block-size: 42px;

	/*
	 * The chip radius, like every other icon chip in the system. This one was
	 * missed when `--ih-radius-chip` was introduced — `.icon-badge` was
	 * converted and this was not, so two 42px tint squares rendered at
	 * different radii on the same page.
	 */
	border-radius: var(--ih-radius-chip);
	background: var(--ih-brand-tint);
	color: var(--ih-brand);
}

.hero__badge-icon svg {
	inline-size: 22px;
	block-size: 22px;
}

.hero__badge-title {
	display: block;
	font-family: var(--ih-font-display);
	font-size: var(--ih-text-base);
	line-height: var(--ih-leading-snug);
}

.hero__badge-note {
	display: block;
	font-size: var(--ih-text-sm);
	color: var(--ih-text-muted);
	line-height: var(--ih-leading-snug);
}

/*
 * ⚠️ HIDDEN ON A PHONE, DELIBERATELY. Below 600px the photograph is already
 * shortened to 16:9 so the emergency notice stays above the fold (the rule
 * directly below), and a card floated over it would cover the building at
 * exactly the width where least of the building is visible. The badge repeats
 * a fact the hero lede states in full, so nothing is lost by dropping it —
 * which is the test for whether an element may be hidden at a breakpoint at
 * all. If it ever carries information found nowhere else, this rule is wrong.
 */
@media (max-width: 600px) {
	.hero__badge {
		display: none;
	}
}

.hero__media-img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 2;
	object-fit: cover;

	/*
	 * Bottom corners only in the stacked layout: the photograph sits flush
	 * against the section it ends, so rounding the top would leave two slivers
	 * of tinted background above a full-bleed image.
	 */
	border-end-start-radius: var(--ih-radius);
	border-end-end-radius: var(--ih-radius);
}

/*
 * Shorter on a phone. A 3:2 image at mobile width eats the whole viewport and
 * pushes the emergency notice below the fold; 16:9 keeps the building
 * recognisable and leaves the notice visible.
 */
@media (max-width: 600px) {
	.hero__media-img {
		aspect-ratio: 16 / 9;
	}
}

@media (min-width: 1024px) {
	.hero--split .hero__inner {
		display: grid;
		grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
		column-gap: var(--ih-space-7);
		align-items: center;

		/*
		 * The full container, not the 46rem reading measure. That cap is right
		 * for a hero whose text spans the section — here the grid column is
		 * the measure, and leaving 46rem on would squeeze both columns into
		 * the middle third of the page.
		 */
		max-width: var(--ih-container);
	}

	.hero--split .hero__media {
		margin: 0;
	}

	/* All four corners now, since the image no longer sits flush to an edge. */
	.hero--split .hero__media-img {
		border-radius: var(--ih-radius);
	}
}

/*
 * ---------- Search: the no-results state, and searching again ----------
 *
 * Bordered and tinted rather than a bare paragraph, because it is replacing
 * "No articles have been published yet." — a sentence that told visitors this
 * site was empty. The panel has to read as a deliberate answer to a question,
 * not as the absence of one.
 */
.search-empty {
	max-width: var(--ih-container-narrow);
	padding: var(--ih-space-5);
	border: 1px solid var(--ih-border);
	border-radius: var(--ih-radius);
	background: var(--ih-surface-alt);
}

.search-empty__reassure {
	font-size: var(--ih-text-lg);
}

/*
 * The 911 line, in brand red and not in muted grey.
 *
 * Same rule as the footer's: the one sentence on a page that somebody might
 * need in a hurry does not get reduced contrast. It is last because it is the
 * escalation, not the first thing to read.
 */
.search-empty__urgent {
	margin-bottom: 0;
	color: var(--ih-brand-deep);
	font-weight: var(--ih-weight-bold);
}

.search-again {
	margin-top: var(--ih-space-8);
	padding-top: var(--ih-space-5);
	border-top: 1px solid var(--ih-border);
	max-width: var(--ih-container-narrow);
}

/*
 * ---------- Icons ----------
 *
 * The client's standing rule: no section should be words alone. See
 * `ih_icon()` for why these are inline SVG rather than a font, a sprite or a
 * CDN.
 *
 * `1em` so an icon scales with the text beside it and never needs a size per
 * call site. `currentColor` so it inherits, which is what makes one path
 * usable on white, on the tint and inside a red disc.
 *
 * `flex-shrink: 0` because an icon in a flex row is the one thing that must
 * not compress — a squashed glyph reads as a rendering fault, and these sit
 * next to headings that wrap.
 */
/*
 * ⚠️ `.ih-icon` IS KEPT FOR A CALLER THAT PASSES IT EXPLICITLY, AND NOTHING
 * CURRENTLY DOES.
 *
 * The icon files carry no class of their own — see the badge rule below for
 * how that was found. This class is the opt-in handle for a template that
 * wants a bare icon sized to its text without a disc around it, which is what
 * the inner-page work will need.
 *
 * Recorded rather than deleted, because a class with no call site is exactly
 * the defect this project has now found four times. It has a call site coming;
 * if the inner-page pass does not use it, it should be deleted rather than
 * left sitting here looking used.
 */
.ih-icon {
	width: 1em;
	height: 1em;
	flex-shrink: 0;
	color: currentColor;
}

/*
 * The disc. The client's reference images are white line work inside a solid
 * brand-red circle.
 *
 * Sized in `em` rather than pixels so a badge beside a larger heading grows
 * with it. 2.75em against a 1em glyph gives the ring of space his examples
 * have.
 *
 * ⚠️ `--ih-white` on `--ih-brand` is 6.0:1, which passes AA — but this is
 * GRAPHICS, not text, so the bar is 3:1 under WCAG 1.4.11 and it clears that
 * comfortably. Worth stating because the earlier contrast work in this file
 * established that brand red fails at 4.45:1 against the tint: that is a
 * limit on brand red as TEXT, and a white stroke on a red disc is a different
 * measurement with a different threshold.
 */
/*
 * ⚠️ `flex-shrink: 0` ON THE DISC, AND I PUT IT ON THE GLYPH FIRST.
 *
 * Measured on the deployed page: the quiet badges in `.reason-list` rendered
 * at **30, 31, 34 and 36 pixels** where all four should be 36. A disc is a
 * flex item inside `.reason-list li`, `flex-shrink` defaults to 1, and each
 * one was being compressed by a different amount depending on how long its
 * sentence was.
 *
 * Four circles at four sizes down one short list, which reads as sloppiness
 * rather than as a bug — the same failure mode as the two right-hand edges.
 *
 * The irony is recorded because it is instructive: the comment on `.ih-icon`
 * already said *"an icon in a flex row is the one thing that must not
 * compress — a squashed glyph reads as a rendering fault"*. I wrote the right
 * rule and attached it to the inner element, which was never the flex item.
 * **Knowing the hazard is not the same as knowing where it applies.**
 */
/*
 * 🔴 A TINT-FILLED ROUNDED SQUARE, NOT A SOLID RED DISC, since 2026-09-14 —
 * the handoff specifies it, and the client has made the handoff the source of
 * truth for branding calls.
 *
 * A solid `--ih-brand` disc with a white glyph became a `--ih-brand-tint`
 * square with a brand-red glyph. The old silhouette carried more weight than
 * a decorative element needs: four solid red discs down a list out-shouted
 * the sentences beside them, which is the entire reason `--quiet` had to
 * exist. The new base is very nearly that quiet variant promoted — fair
 * evidence the quiet variant was right about the problem and only ever a
 * local exception to a default that should have changed.
 *
 * Contrast: brand red on the tint measures 5.30:1. WCAG 1.4.11 asks 3:1 of a
 * non-text graphic, so there is real headroom — and no glyph here is the sole
 * carrier of meaning, since every badge sits beside the text it illustrates.
 */
.icon-badge {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	width: 2.75em;
	height: 2.75em;
	border-radius: var(--ih-radius-chip);
	background: var(--ih-brand-tint);
	color: var(--ih-brand);
	font-size: 1rem;
}

/*
 * ⚠️ `svg`, NOT `.ih-icon`, AND THE CLASS VERSION SILENTLY DID NOTHING.
 *
 * Measured on the deployed page: the glyph rendered at **44px inside a 44px
 * disc** — filling it edge to edge with no ring of space at all — because
 * `.icon-badge .ih-icon` matched nothing.
 *
 * The icons are FILES, and none of the twenty-six carries a `class`
 * attribute: the twelve that already existed rely on contextual CSS
 * (`.social-links svg`, and so on) and the fourteen I added followed their
 * shape. `ih_icon()` passes the file through `wp_kses` and preserves a class
 * if one is there, but there is none to preserve.
 *
 * So the badge sizes its child by element. That also means an icon dropped in
 * by a child theme works without knowing about a class convention — which is
 * the whole point of the files living per-site.
 */
.icon-badge svg {
	width: 1.35em;
	height: 1.35em;
	flex-shrink: 0;
}

/*
 * The soft variant, for use ON a red field. Its reason has CHANGED and it is
 * now needed more than before, not less.
 *
 * It used to exist because a solid red disc is invisible on a red field. The
 * base badge is now a pale TINT square with a red glyph — which on a red
 * field is worse than invisible: the chip itself shows as a light patch while
 * the glyph inside it disappears into the background it is nearly the colour
 * of. So a translucent white wash with a white glyph remains the only thing
 * that works there.
 *
 * `rgba` rather than a token because it has to work over any red in the
 * palette, and a fixed tint would only match one of them.
 */
.icon-badge--soft {
	background: rgba(255, 255, 255, 0.16);
	color: var(--ih-white);
}

/*
 * The quiet variant: now purely a SIZE and a darker glyph, not a different
 * treatment.
 *
 * ⚠️ ITS ORIGINAL PURPOSE IS GONE, and that is worth recording rather than
 * quietly keeping the class. It existed because "a row of red discs would
 * shout louder than the text" — but the base badge is no longer a red disc,
 * so every badge is now quiet in that sense. What remains useful is the
 * smaller footprint for dense lists, and brand-deep rather than brand on the
 * tint, which the tokens table records at 8.37:1 against the base's 5.30.
 *
 * Kept rather than deleted because `front-page.php` uses it on the
 * reason-list, where 2.25em against 2.75em genuinely reads better beside a
 * single line of text. If a future pass finds it doing nothing the base does
 * not, it should go.
 */
.icon-badge--quiet {
	background: var(--ih-brand-tint);
	color: var(--ih-brand-deep);
	width: 2.25em;
	height: 2.25em;
}

/*
 * A reasoned list: an icon, then the sentence it belongs to.
 *
 * `align-items: flex-start` so the badge sits level with the FIRST line of a
 * sentence that wraps, rather than centring itself against a two-line block
 * and floating in the middle of it.
 *
 * `list-style: none` with the indent removed, because the badge is the marker
 * now — keeping a bullet as well would give every row two.
 */
.reason-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;

	/* See the note on `.symptom-grid`. */
	grid-template-columns: minmax(0, 1fr);
	gap: var(--ih-space-4);
}

.reason-list li {
	display: flex;
	align-items: flex-start;
	gap: var(--ih-space-3);
	margin: 0;
}

/*
 * A card's icon sits above its title, which is the shape of the client's
 * reference images. `margin-bottom` rather than the card's own gap so it can
 * be tighter to the heading it labels than the heading is to its paragraph.
 */
.card__body > .icon-badge {
	margin-bottom: var(--ih-space-1);
}

/*
 * The closing line of a section. FULL WIDTH, and deliberately not set to a
 * reading measure.
 *
 * ⚠️ I WROTE `max-width: 70ch` HERE FIRST AND IT CONTRADICTED THE FIX. The
 * client asked for this sentence on one line; a 70ch measure is about 630px
 * and the sentence needs roughly 1050px, so the measure would have wrapped it
 * straight back to two lines — undoing the shortening in the same commit that
 * made it.
 *
 * **The trade-off is real and it is his to make.** A 125-character line is
 * long for reading; a two-line closer left two words stranded, which is what
 * he objected to. He asked for one line, so it runs the container, and the
 * trade is flagged to him rather than decided quietly by a rule I preferred.
 *
 * `margin-bottom: 0` because it is the last thing in the section and the
 * section already owns the space below it.
 */
.building-close {
	margin-bottom: 0;
}

/* ---------- Cards ---------- */

.card {
	display: flex;
	flex-direction: column;
	height: 100%;
	background: var(--ih-white);
	border: 1px solid var(--ih-border);
	border-radius: var(--ih-radius-lg);
	overflow: hidden;

	/*
	 * A resting shadow, from the handoff ("card shadow: 0 6px 18px
	 * rgba(32,30,29,0.05)" — exactly `--ih-shadow`).
	 *
	 * Cards were flat at rest and lifted only on hover. The mercy-grace
	 * session asked whether that was deliberate, calling it the one spec line
	 * they could not tell apart from an oversight. Fair description: the token
	 * already held the right value and only the resting state was missing.
	 *
	 * ⚠️ A HOVER-ONLY SHADOW IS ALSO A TOUCH-DEVICE PROBLEM, which is the
	 * better argument for changing it. There is no hover on a phone, so the
	 * whole elevation of every card grid existed for mouse users only — and on
	 * the device most patients arrive on, the cards had no separation from the
	 * page beyond a 1px border.
	 */
	box-shadow: var(--ih-shadow);

	/* transform included: the packet's base transition is the three properties
	 * its hover state changes, and a transform left out of this list lifts
	 * instantly while the shadow eases in behind it. */
	transition: transform var(--ih-duration) var(--ih-ease),
		border-color var(--ih-duration) var(--ih-ease),
		box-shadow var(--ih-duration) var(--ih-ease);
}

/* Hover now LIFTS from the resting shadow rather than introducing one. */
/*
 * ---------- The hovered card ----------
 *
 * THE HANDOFF'S HOVER LIFT, added to the family packet 2026-09-14. The FHMC
 * copy states it in prose; El Mirage's states it only in the drawings, where
 * it appears on 149 elements. Quoted from the prose copy because it is the
 * clearest statement of the rule:
 *
 *   "Every card floats on hover: base transition
 *    transform/box-shadow/border-color 0.18s ease; hover transform:
 *    translateY(-4px) + box-shadow: 0 16px 34px rgba(32,30,29,0.13) (card
 *    links also turn their border brand red). Apply to every card pattern."
 *
 * The shadow was `--ih-shadow-lg` — the 30%-alpha POPUP elevation — with no
 * lift at all. Six times the alpha, and missing the movement that makes it
 * read as floating rather than as a layer appearing underneath.
 * `--ih-duration` is already 180ms, matching the packet's 0.18s.
 *
 * "Apply to every card pattern" is meant literally: the selector list is
 * every component in this file carrying `box-shadow: var(--ih-shadow)`, which
 * is the same test the drawings use. `.is-liftable` is the opt-in for a child
 * theme with a card of its own.
 *
 * ⚠️ THE LIFT IS SUPPRESSED UNDER `prefers-reduced-motion`, AND ZEROING
 * `--ih-duration` IS NOT ENOUGH. base.css forces `transition-duration` to
 * 0.01ms there, which makes the movement INSTANT rather than absent — the
 * card still teleports 4px the moment a pointer touches it, which is the jump
 * the preference exists to prevent, delivered faster. Colour and shadow are
 * not motion and stay; only the translation is dropped.
 */
.card:hover,
.card:focus-within,
.compare-col:hover,
.compare-col:focus-within,
.stat:hover,
.stat:focus-within,
.faq-item:hover,
.faq-item:focus-within,
.symptom-group:hover,
.symptom-group:focus-within,
.fact-strip li:hover,
.fact-strip li:focus-within,
.is-liftable:hover,
.is-liftable:focus-within {
	transform: translateY(var(--ih-lift));
	box-shadow: var(--ih-shadow-hover);
}

/*
 * "card links also turn their border brand red" — the packet scopes the
 * border change to cards, not to every lifting surface, so a stat tile and an
 * FAQ row lift without recolouring.
 */
.card:hover,
.card:focus-within,
.is-liftable:hover,
.is-liftable:focus-within {
	border-color: var(--ih-brand);
}

@media (prefers-reduced-motion: reduce) {
	.card:hover,
	.card:focus-within,
	.compare-col:hover,
	.compare-col:focus-within,
	.stat:hover,
	.stat:focus-within,
	.faq-item:hover,
	.faq-item:focus-within,
	.symptom-group:hover,
	.symptom-group:focus-within,
	.fact-strip li:hover,
	.fact-strip li:focus-within,
	.is-liftable:hover,
	.is-liftable:focus-within {
		transform: none;
	}
}

/*
 * 🔴 THIS COMMENT PREVIOUSLY CONTAINED TWO WRONG NUMBERS, AND BOTH MADE AN
 * INSUFFICIENT FIX LOOK SUFFICIENT. The client reported the same defect twice
 * because of it.
 *
 * The ratio was `10 / 7` and sliced the title cards. It became `3 / 2`, and
 * the comment justifying that said:
 *
 *   1. "it narrows the title-card crop from 25% of the width to about 5%"
 *      — **the crop went from 25% to 21%.** A 1.905 image in a 1.5 box loses
 *      (1 - 1.5/1.905) = 21.3%. Wrong by a factor of four, and 5% is small
 *      enough to ignore while 21% removes characters.
 *   2. "most cards now carry a 3:2 photograph — 32 of 33 posts"
 *      — **fourteen of thirty-two carry a 1.905 title card.** The eighteen
 *      photographic ones are 1.488, which crops 0.8% and is genuinely
 *      invisible. That contrast is why the defect looked random.
 *
 * Neither number was measured. Both pointed the same way: fix complete, move
 * on. The client's second screenshot — "liday Heart", "oisoning", "ack Pain" —
 * is what a 21% crop does to centred text.
 *
 * `3 / 2` stays, because it is right for the photographs and the grid needs one
 * shape. What changes is that **an image whose own ratio disagrees with the box
 * is no longer cropped at all** — see `card.php`, which measures the
 * attachment and adds `card__media--poster` above 1.7.
 */
.card__media img {
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
}

/*
 * A poster — a generated title card, or any image far wider than the box.
 *
 * `contain` rather than `cover`, which is the opposite of the right choice for
 * a photograph and the only correct choice here. Cropping a hillside loses
 * nothing; cropping a poster removes the words, because on a poster every
 * pixel is deliberate and the content IS text.
 *
 * The earlier objection to `contain` was that it "letterboxes a photograph
 * against the card background, which looks like a loading error" — true, and
 * the reason this is scoped to posters by measurement rather than applied to
 * every card. The title cards carry their own dark background, so the letterbox
 * reads as the edge of a designed object rather than as a gap.
 *
 * The band is `--ih-ink` to match those cards' own field, so the join is
 * invisible on them and deliberate on anything else.
 */
.card__media--poster img {
	object-fit: contain;
	background: var(--ih-ink);
}

.card__body {
	display: flex;
	flex-direction: column;
	flex: 1;
	gap: var(--ih-space-2);
	padding: var(--ih-space-5);
}

.card__title {
	margin: 0;
	font-size: var(--ih-text-lg);
}

.card__title a {
	color: inherit;
	text-decoration: none;
}

.card__meta {
	color: var(--ih-muted);
	font-size: var(--ih-text-sm);
}

/*
 * Card copy is its own size, not inherited body copy. The handoff sets all
 * three separately — "base 17px/28px; card body 15px/25px; small 13–14.5px" —
 * and this rule declared no size at all, so every excerpt rendered at full
 * body size. Cards read heavier and ran longer than the design, which is the
 * kind of difference that looks like "our content is wordier" rather than
 * like a missing declaration.
 */
.card__excerpt {
	margin: 0;
	font-size: var(--ih-text-card);
	line-height: var(--ih-leading-card);
	color: var(--ih-text-muted);
}

/* Pushes the read-more link to the bottom so cards in a row align */
.card__footer {
	margin-top: auto;
	padding-top: var(--ih-space-3);
}

/* ---------- Provider card ---------- */

.provider-card__media img {
	aspect-ratio: 4 / 5;
	object-fit: cover;
	width: 100%;
}

/*
 * The initial tile, for a provider with no photograph.
 *
 * Same 4:5 box as the photograph it stands in for, so a grid mixing the two
 * does not step. On sites with no provider photography this is not a
 * fallback — it is the grid, because this family forbids generating images of
 * providers and the alternative was no media block at all.
 *
 * --ih-brand-deep on the tint is 8.37:1. It only has to clear 3:1 as a
 * non-text graphic — the initials are aria-hidden and the full name sits in
 * the heading immediately below — but there is no reason to spend the margin.
 */
.provider-card__media--initials {
	aspect-ratio: 4 / 5;
	display: grid;
	place-items: center;
	background: var(--ih-brand-tint);
}

.provider-card__initials {
	font-family: var(--ih-font-display);
	font-weight: var(--ih-weight-display);

	/*
	 * Sized to the tile rather than to the type scale: `cqi` would be ideal
	 * but the card is not a container, so a clamp against the viewport keeps
	 * two letters comfortably inside a column that can be 240px or 380px wide.
	 */
	font-size: clamp(2.5rem, 6vw, 4rem);
	line-height: 1;
	letter-spacing: -0.02em;
	color: var(--ih-brand-deep);
}

.provider-card__credentials {
	color: var(--ih-brand-deep);
	font-weight: var(--ih-weight-bold);
	font-size: var(--ih-text-sm);
	letter-spacing: 0.02em;
	text-transform: uppercase;
}

/* ---------- Entry / article ---------- */

.entry-header {
	padding-block: var(--ih-space-7) var(--ih-space-5);
}

.entry-byline {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ih-space-3);
	color: var(--ih-muted);
	font-size: var(--ih-text-sm);
}

.entry-byline__reviewer {
	padding-inline-start: var(--ih-space-3);
	border-inline-start: 1px solid var(--ih-border);
	font-weight: var(--ih-weight-medium);
}

.entry-content > * + * {
	margin-top: var(--ih-space-4);
}

.entry-content h2 {
	margin-top: var(--ih-space-7);
}

.entry-content h3 {
	margin-top: var(--ih-space-6);
}

/*
 * 🔴 EVERY ARTICLE AND PAGE HERO WAS 80px NARROWER THAN ITS OWN TEXT, and the
 * cause is a browser default nobody had reset.
 *
 * `<figure>` carries a UA stylesheet `margin: 1em 40px`. Nothing in this theme
 * touched it, so `.entry-featured` sat inset 40 pixels on each side of the
 * prose beneath it. Measured on `/blog/scorpion-stings-in-arizona-what-to-do/`:
 *
 *   .entry-content   left 345  right 1025   680 wide
 *   .entry-featured  left 385  right  985   600 wide
 *
 * The `width: 100%` below was doing its job perfectly — filling a figure that
 * was itself the wrong width. So the image looked deliberate, sat centred, and
 * simply refused to line up with anything, on 32 articles and 8 pages.
 *
 * ⚠️ THIS IS THE THIRD INSTANCE OF ONE PATTERN ON THIS SITE and the client
 * reported the first two as "misaligned and kinda disorganized": the reading
 * measure that capped paragraphs but not headings, the paragraph measure
 * inside a narrower container, and now a figure's UA margin. **None of them
 * broke anything. All three produced two right-hand edges where there should
 * have been one**, which is the failure that reads as carelessness rather than
 * as a bug, because there is nothing to point at.
 *
 * `margin-inline: 0` is the whole fix. The vertical margin is named rather
 * than inherited from `1em` so it follows the spacing scale.
 */
.entry-featured {
	margin-block: var(--ih-space-6);
	margin-inline: 0;
}

/*
 * ⚠️ `max-width` NOT `width`, so a picture smaller than the column is not
 * upscaled into a soft mess — it centres at its own size instead. Every hero
 * in use today is wider than the 680px measure and so fills it exactly; this
 * is about the one somebody adds later.
 *
 * An upscaled photograph on a medical homepage reads as a cheap site, which is
 * the specific impression this rebuild exists to remove.
 */
.entry-featured img {
	max-width: 100%;
	margin-inline: auto;
	border-radius: var(--ih-radius-lg);
}

/*
 * 🔴 A WIDESCREEN CROP ONCE THE FIGURE SPANS THE FULL CONTAINER, added with
 * the 2026-09-13 container change. The maths forced a decision: every hero in
 * the library is 3:2, and 3:2 at 1120px is a 747px-tall image — a photograph
 * taller than most laptop viewports, before a single word of the page.
 *
 * 12/5 (1120 × 467) is chosen against the client's two reference sites, whose
 * heroes run roughly 2.2:1–2.6:1. `object-fit: cover` centre-crops the 3:2
 * source to reach it, keeping the middle ~62% of the frame's height.
 *
 * ⚠️ THIS IS A HARD CROP AND CROPS HAVE BURNT THIS SITE TWICE — the blog
 * cards sliced article titles off ("liday Heart"), and the hero once
 * double-cropped a 16:9 into a 3:2 box. It is safe HERE for a reason that
 * must stay true: every featured image on pages and articles is a PHOTOGRAPH
 * whose subject sits in the middle band — buildings, rooms, still-life art.
 * The poster/title-card class that made cropping dangerous was retired from
 * featured slots. If title cards ever return as featured images, this rule is
 * the one that will decapitate their text, and `card__media--poster` is the
 * precedent for how to exempt them: classify by measured ratio, never by
 * filename.
 *
 * Applied only above 720px: on a phone the figure is barely wider than the
 * prose, the squeeze complaint does not exist, and a taller image is better
 * than a letterboxed sliver.
 *
 * ⚠️ `width: 100%` HERE OVERRIDES THE NO-UPSCALE GUARD ABOVE, and the cost
 * was measured before being accepted rather than discovered later: the 29
 * generated-art heroes are 1024px sources rendering at 1120 — a ~9% stretch,
 * checked by eye on the soft editorial style and invisible; the facility
 * photographs serve 1536px crops and do not stretch at all. The alternative —
 * letting narrow sources sit inset — gives the site two different hero widths
 * that alternate by article, which a reader sees and this does not. If the
 * art is ever regenerated, produce it at 1200+ and this note retires; if a
 * hero ever looks soft, this trade is where to look first.
 */
@media (min-width: 720px) {
	.entry-featured img {
		width: 100%;
		aspect-ratio: 12 / 5;
		object-fit: cover;
	}
}

/* ---------- Breadcrumbs ---------- */

.breadcrumbs {
	padding-block: var(--ih-space-3);
	font-size: var(--ih-text-sm);
	color: var(--ih-muted);
}

.breadcrumbs a {
	color: var(--ih-text-muted);
}

/* ---------- Footer ---------- */

.site-footer {
	padding-block: var(--ih-space-8) var(--ih-space-5);
	background: var(--ih-ink);
	color: var(--ih-grey-100);
}

.site-footer a {
	color: var(--ih-grey-100);
	text-decoration: none;
}

.site-footer a:hover,
.site-footer a:focus-visible {
	color: var(--ih-white);
	text-decoration: underline;
}

/*
 * A button in the footer keeps its OWN colour pair.
 *
 * ⚠️ THIS WAS AN UNREADABLE BUTTON, and it is a pure specificity accident.
 * `.site-footer a` is (0,1,1) — one class plus one element — while
 * `.btn--inverse` is only (0,1,0). So the generic footer link colour above
 * beat the button's own `color: var(--ih-brand)`, and "Patient Portal" and
 * "Pay Your Bill" rendered as pale grey text on a white pill. Effectively
 * invisible, on the two controls a patient is most likely to be looking for.
 *
 * Found on El Mirage's staging site, 2026-09-13, by looking at it. Nothing
 * static could have caught this: both rules are valid, both selectors match
 * real elements, and the contrast failure only exists once the cascade
 * resolves. `check-theme` verifies that every class HAS styling — not that
 * the styling that wins is the one intended.
 *
 * Scoped to `.btn` rather than to `.btn--inverse` so any future variant
 * placed in the footer inherits the fix instead of rediscovering the bug.
 * The underline is dropped too: on a filled pill it reads as a rendering
 * fault rather than as affordance.
 */
.site-footer a.btn,
.site-footer a.btn:hover,
.site-footer a.btn:focus-visible {
	text-decoration: none;
}

.site-footer a.btn--inverse,
.site-footer a.btn--inverse:hover,
.site-footer a.btn--inverse:focus-visible {
	color: var(--ih-brand);
}

/*
 * ---------- The partner block (HealthPass) ----------
 *
 * The client: "healthpass is written as an afterthought and hidden at the
 * bottom of the page and the footer, not as an exciting product that is there
 * is help our patients with one of the biggest concern in healthcare - cost."
 *
 * So it gets a bordered panel of its own rather than a line of text in a list.
 *
 * ⚠️ IT IS STILL DELIBERATELY NOT `btn--inverse`. Patient Portal and Pay Your
 * Bill are the facility's own tools and use that button; HealthPass is a
 * separate company. The disclosure used to be carried by making the link
 * plainer — now it is carried in WORDS ("In partnership with", "A separate
 * company. Not insurance."), which is stronger, and the panel is marked out by
 * a border rather than by a filled button so the two still do not look like
 * the same kind of thing.
 */
.footer-partner {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--ih-space-2);
	margin-top: var(--ih-space-4);
	padding: var(--ih-space-4);
	border: 1px solid rgba(255, 255, 255, 0.22);
	border-radius: var(--ih-radius);
	background: rgba(255, 255, 255, 0.04);
}

.footer-partner__eyebrow {
	margin: 0;
	font-size: var(--ih-text-sm);
	letter-spacing: 0.04em;
	text-transform: uppercase;
	opacity: 0.7;
}

.footer-partner__name {
	margin: 0;
	font-family: var(--ih-font-display);
	font-size: var(--ih-text-xl);
	font-weight: var(--ih-weight-bold);
	line-height: 1.1;
}

.footer-partner__pitch {
	margin: 0;
	font-size: var(--ih-text-sm);
	line-height: var(--ih-leading-normal);
}

/*
 * ⚠️ `flex-wrap` AND `max-width` ARE THE REFLOW FIX, not tidying. Found
 * 2026-09-14, same measuring pass as `.phone-pill`.
 *
 * A row flex container does not shrink below the sum of its items'
 * min-content widths, so at 200% text this pill was 265px inside a 235px
 * parent and hung 16px off the right edge of a 320px screen — the widest
 * overflow on the page and the one setting the scrollbar. Letting the items
 * wrap, and capping the pill at its parent, keeps the label and the ↗
 * together when there is room and stacks them when there is not.
 */
.footer-partner__cta {
	display: inline-flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--ih-space-2);
	max-width: 100%;
	min-height: var(--ih-touch);
	margin-top: var(--ih-space-1);
	padding: var(--ih-space-2) var(--ih-space-4);
	border: 2px solid var(--ih-white);
	border-radius: var(--ih-radius-pill);
	font-weight: var(--ih-weight-bold);
}

/* (0,2,1) beats `.site-footer a:hover` at (0,1,1). */
.site-footer .footer-partner__cta:hover,
.site-footer .footer-partner__cta:focus-visible {
	background: var(--ih-white);
	color: var(--ih-brand);
	text-decoration: none;
}

.footer-partner__note {
	margin: 0;
	font-size: var(--ih-text-sm);
	opacity: 0.7;
}

.site-footer a.btn--primary,
.site-footer a.btn--primary:hover,
.site-footer a.btn--primary:focus-visible {
	color: var(--ih-white);
}

.site-footer h2,
.site-footer h3 {
	color: var(--ih-white);
	font-size: var(--ih-text-base);
	letter-spacing: 0.04em;
	text-transform: uppercase;
}

.site-footer ul {
	margin: 0;
	padding: 0;
	list-style: none;
}

.footer-bottom {
	margin-top: var(--ih-space-7);
	padding-top: var(--ih-space-4);
	border-top: 1px solid rgba(243, 243, 243, 0.15);
	font-size: var(--ih-text-sm);
	display: flex;
	flex-wrap: wrap;
	gap: var(--ih-space-4);
	justify-content: space-between;
}

.facility-address {
	font-style: normal;
}

.facility-address span {
	display: block;
}

/**
 * Department phone list.
 *
 * Sites in the family publish different numbers of lines — an aesthetics line,
 * a billing line, a clinic line separate from the ER — so this is a list rather
 * than a fixed set of fields.
 */
.phone-list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.phone-list li {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ih-space-2);
	margin-top: var(--ih-space-1);
}

/*
 * ⚠️ `min-width: 6.5rem` REMOVED, and it left a canyon.
 *
 * Measured in El Mirage's footer: the label box was 104px wide, the word
 * "Billing" inside it about 42, and the number began at 112px into a 262px
 * column. So the rendered line was "Billing", sixty pixels of nothing, then a
 * phone number — two items that read as unrelated rather than as one labelled
 * fact.
 *
 * The fixed width was there to align numbers down the column on a site that
 * publishes several — aesthetics, billing, a clinic line separate from the ER.
 * That is a real case, but it is the wrong trade: **the pairing is the
 * information here, not the column.** A reader is matching a department to a
 * number, not scanning a price list, and there are at most three rows to
 * scan. Sitting the number beside its own label wins.
 *
 * It was also a hardcoded guess at the widest label any of eight sites might
 * ever use, which is the kind of number that is wrong on the site nobody
 * checked.
 */
.phone-list__label {
	opacity: 0.75;
}

.footer-phone {
	display: inline-block;
	font-size: var(--ih-text-lg);
	font-weight: var(--ih-weight-bold);
}

/*
 * ⚠️ NO `text-wrap` HERE ON PURPOSE, AND BOTH VALUES WERE TRIED ON THE WIRE.
 *
 * This string needs two lines in a 262px footer column, and neither mode picks
 * the right break: `pretty` leaves "week" alone on line two, `balance` gives
 * two even lines by splitting "a day" across them. `balance` was deployed and
 * measured before that was known — I had predicted it would break at the
 * comma. It optimises for equal line lengths, which is a different thing.
 *
 * The break belongs at the comma and no CSS property can ask for that, so it
 * is done in the markup instead: `ih_always_open_text()` binds each phrase
 * with non-breaking spaces, which leaves exactly one legal break point. See
 * that function for why it lives there rather than here.
 *
 * An earlier draft of the `balance` rule sat on the `strong` and would have
 * done nothing at all — `text-wrap` applies to a block container and `strong`
 * is inline. Worth recording: a rule with no element behind it looks exactly
 * like a fix, and no gate catches it. `check-theme` finds classes with no
 * rules, not rules that cannot apply.
 */
.facility-hours--always strong {
	color: var(--ih-white);
}

.facility-hours {
	margin: 0;
}

.facility-hours dt {
	font-weight: var(--ih-weight-bold);
}

.facility-hours dd {
	margin: 0 0 var(--ih-space-2);
}

/*
 * ---------- The availability notes ----------
 *
 * Tighter than `.stack` on purpose. These are three short facts about one
 * subject, not three sections: at `--ih-space-4` apart they read as a list of
 * unrelated announcements, and the point of the column is that they answer the
 * same question together.
 *
 * `list-style: none` is inherited from `.site-footer ul` above. The indent is
 * not, so it is removed here — `ul` carries a padding-inline-start from
 * base.css, and without this the notes hang two spaces to the right of the
 * hours line directly above them. A five-pixel misalignment inside one column
 * is exactly the kind of thing that reads as carelessness without ever being
 * identifiable as a fault, which is what the interior-page measure did.
 */
.availability-notes {
	margin: var(--ih-space-2) 0 0;
	padding-inline-start: 0;
	font-size: var(--ih-text-sm);
	line-height: var(--ih-leading-normal);
}

.availability-notes li + li {
	margin-top: var(--ih-space-2);
}

/*
 * The two assurances, set apart by one rule rather than by colour.
 *
 * ⚠️ NEITHER MAY BE DIMMED. The obvious treatment for small print at the foot
 * of a column is `opacity: 0.7` — what `.footer-partner__note` uses two hundred
 * lines up, and what the 911 rule originally copied from it. Correct for a
 * partner disclosure, wrong for these two: one is the sentence somebody may
 * need to read in a hurry, in the dark, on a phone, while frightened, and the
 * other is a promise about money that a person is deciding whether to believe.
 * Reduced contrast is the last thing either can afford.
 *
 * The border moved from the 911 line onto this wrapper when the access promise
 * joined it. They are different kinds of statement — what we promise, and what
 * to do if you are worse than you thought — but two hairlines in a five-line
 * column reads as a form, so they are told apart by size and weight instead.
 */
.availability-assurance {
	margin-top: var(--ih-space-3);
	padding-top: var(--ih-space-3);
	border-top: 1px solid rgba(243, 243, 243, 0.15);
}

.availability-assurance__promise {
	margin: 0;
	font-size: var(--ih-text-base);
	font-weight: var(--ih-weight-bold);
	line-height: var(--ih-leading-normal);
	color: var(--ih-white);
}

.availability-notes__urgent {
	margin: var(--ih-space-2) 0 0;
	font-size: var(--ih-text-sm);
	font-weight: var(--ih-weight-bold);
	color: var(--ih-white);
}

/*
 * The 911 link keeps the line's own white and carries a permanent underline.
 *
 * `.site-footer a` sets `--ih-grey-100` and no underline, which would make the
 * one tappable thing in this line *dimmer* than the words around it and give
 * no sign it can be tapped. (0,2,1) beats that (0,1,1).
 *
 * The underline is not a hover affordance here — it is the only indication on
 * a touch screen, where there is no hover at all.
 */
.site-footer .availability-notes__urgent a {
	color: var(--ih-white);
	text-decoration: underline;
	text-decoration-thickness: 2px;
}

/*
 * `:first-child` so the 911 line keeps its own spacing when it is alone.
 *
 * With no `access_promise` set the wrapper holds only this paragraph, and a
 * `margin-top` under the wrapper's own padding would double the gap — the
 * layout a site that has NOT made this promise gets, which is most of them.
 */
.availability-notes__urgent:first-child {
	margin-top: 0;
}

/*
 * 🔴 `align-items: center` — WITHOUT IT THE SOCIAL ICONS SAT ON TWO DIFFERENT
 * BASELINES.
 *
 * The client's first report of the batch: *"the social media bubbles at the
 * top are misaligned"*. Measured in the utility bar: the five links returned
 * **two distinct top edges, 40 and 48** — an 8-pixel stagger across a row of
 * five circles.
 *
 * 8 is exactly 44 minus 36: the row is 44px tall and each circle is 36px. With
 * no `align-items` the flex default is `normal`, which resolves to `stretch`
 * for the `li` elements and then leaves each 36px `inline-flex` anchor to find
 * its own position inside a 44px line box — and they did not all find the
 * same one, because each anchor also contains a clipped
 * `.screen-reader-text` span that participates in baseline calculation.
 *
 * The sizes were already right and identical: every circle 36x36, every glyph
 * 18x18. **Only the vertical alignment was wrong, which is why it read as
 * "misaligned" rather than as broken** — the same shape as the two right-hand
 * edges and the four different disc sizes. Nothing was malformed; things that
 * should have shared a line did not.
 *
 * One declaration. The row is a row, so say so rather than letting baseline
 * alignment decide.
 */
.social-links {
	display: flex;
	align-items: center;
	gap: var(--ih-space-2);
	flex-wrap: wrap;
}

/*
 * EVERY LIST LAID OUT AS A ROW, IN ONE PLACE.
 *
 * base.css gives `li + li` an 8px top margin for prose, and a flex row still
 * matches it — so items two onwards sit lower than the first. See that rule
 * for the full account; it is what the client saw as misaligned social icons.
 *
 * ⚠️ AND `align-items: center` ALONE DID NOT FIX IT, which is why this rule
 * exists rather than just that one. Centring halved the stagger from 8px to
 * 4px and I very nearly shipped that as done — the measurement is the only
 * reason I did not: five links, two distinct tops, 44 and 48. **Centring
 * treats the symptom; the margin is the cause**, and a symptom halved still
 * reads as misaligned to the person who reported it.
 *
 * Listed together rather than fixed where each defect appears. That is the
 * third time tonight the same lesson has come round — the footer button, the
 * header button, the ghost button on tint — and `gap` on each of these
 * containers already owns the spacing, so the margin has nothing to
 * contribute anywhere on this list.
 */
.social-links li,
.cluster li {
	margin: 0;
}

/*
 * ⚠️ `.compare-list` IS DELIBERATELY NOT IN THAT LIST, and I had it there for a
 * minute.
 *
 * It looks like a candidate — its `li` carries `display: flex` — but the FLEX
 * IS ON THE ITEM, not on the list: each row is an icon beside a sentence, and
 * the rows stack vertically. It wants the margin, and sets
 * `margin-top: var(--ih-space-2)` explicitly two hundred lines below.
 *
 * So including it would have been overridden anyway by source order, and the
 * harm would have been the comment rather than the CSS: a reader would take it
 * for a row list that needed resetting. **The test is whether the LIST is a
 * row, not whether an `li` happens to use flex.**
 */

/*
 * ---------- Fact strip ----------
 *
 * A row of icon facts inside page content, from the `[ih_facts]` shortcode.
 *
 * `auto-fit` with a 15rem minimum rather than a fixed column count, because
 * the strips differ: some pages want three facts and some want five, and the
 * shortcode should not need to know how many fit.
 *
 * ⚠️ IT BREAKS OUT OF THE READING MEASURE ON PURPOSE. `.entry-content` is
 * capped at 70ch so prose is readable, and a fact strip is not prose — three
 * columns inside a 70ch column would be about 200px each. `margin-inline` with
 * a negative pull and a matching `max-width` widens it back to the container
 * without needing a wrapper element in the markup, which a markdown file
 * cannot easily provide.
 *
 * Clamped so it never exceeds the container on a narrow screen: at widths
 * where 70ch is already the full width, the negative margin resolves to zero.
 */
.fact-strip {
	list-style: none;
	margin: var(--ih-space-6) 0;
	padding: 0;
	display: grid;
	gap: var(--ih-space-5);
	grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
}

/*
 * 🔴 EACH FACT IS A CARD, CORRECTED 2026-09-14. These were a bare icon-and-text
 * row on a plain background; the packet draws every one of them as a white
 * card — 1px border, 18px radius, 18px/20px padding, the resting shadow and
 * the hover lift — in six of its page files. Same class of miss as the FAQ
 * rows: I read the component as a list because it holds list semantics, and
 * the packet had drawn it as a grid of cards.
 *
 * `align-items: center` is the packet's, not `flex-start`. With a card around
 * it the icon chip and a one-line title read as misaligned when the chip is
 * top-anchored inside padding.
 */
.fact-strip li {
	display: flex;
	align-items: center;
	gap: 12px;
	margin: 0;

	/*
	 * ⚠️ `min-width: 0` BECAUSE A GRID ITEM DEFAULTS TO `min-width: auto` AND
	 * THEREFORE REFUSES TO SHRINK BELOW ITS OWN MIN-CONTENT.
	 *
	 * `.fact-strip` is a grid whose TRACK already collapses correctly —
	 * `minmax(min(15rem, 100%), 1fr)` yields a 280px track on a 320px screen.
	 * The ITEM overflowed it anyway: measured at 367px inside that 280px
	 * track at 200% text, because its min-content is the icon chip plus the
	 * longest unbreakable word in the title, and `auto` let that win.
	 *
	 * `.fact__text` already carried this one level down for the same reason.
	 * The Mercy Grace session hit the identical trap in their accordion and
	 * named the sibling case worth knowing: `1fr` is shorthand for
	 * `minmax(auto, 1fr)`, so a track written that way has the fault too.
	 */
	min-width: 0;
	padding: 18px 20px;
	background: var(--ih-white);
	border: 1px solid var(--ih-border);
	border-radius: 18px;
	box-shadow: var(--ih-shadow);

	/* The handoff's card lift — see `.card:hover` for the shared rule. */
	transition: transform var(--ih-duration) var(--ih-ease),
		box-shadow var(--ih-duration) var(--ih-ease);
}

/*
 * 🔴 THE ORPHANED LAST FACT. The client's homepage complaint, for the third
 * time in one night, in a third component.
 *
 * `15rem` is 240px, so inside the 680px content box this grid resolves to two
 * 328px columns — and a three-fact strip lays out 2 + 1 with the third sitting
 * alone. Measured on /our-team/ as `perRow: [2, 1]`. **Most strips on this
 * site carry three facts**, so it was nearly all of them.
 *
 * ⚠️ MY FIRST FIX WAS `grid-column: 1 / -1` ON THE LAST FACT, AND IT PASSED
 * MY OWN MEASUREMENT WHILE CHANGING NOTHING A READER WOULD SEE.
 *
 * Spanning works for the symptom groups because a symptom group's content
 * fills its box. **A fact does not.** It is a flex row of a 44px badge and a
 * short line of text, left-aligned, so widening its box from 328px to 680px
 * leaves the visible content sitting in exactly the same place with more empty
 * space to the right of it. My probe reported `spanned: true` with the last
 * row at full container width — correct, and irrelevant. The screenshot was
 * identical to the broken one.
 *
 * **That is the same mistake as counting badges: a true measurement of the
 * wrong property.** Only the screenshot settled it.
 *
 * So an odd-count strip goes to ONE column and all its facts render full
 * width. Three consistent rows with a red badge down the left edge read as a
 * deliberate list; 2 + 1 reads as a mistake. Three columns was the other
 * option and is wrong here — at 211px a fact would have about 155px of measure
 * beside its badge and break a short sentence into five lines. The card grid
 * can go that narrow because a card stacks; a fact cannot because it does not.
 *
 * ⚠️ `:nth-child(odd)` ON `:last-child` IS THE ENTIRE GUARD. It means "the
 * total count is odd", which in a two-column grid is exactly when the last
 * item ends up alone. Four facts keep their 2 + 2 and are untouched — which is
 * why this is not simply `.fact-strip { grid-template-columns: 1fr }`, and why
 * it is not `:last-child` alone.
 */
.fact-strip:has(.fact:last-child:nth-child(odd)) {
	grid-template-columns: 1fr;
}

.fact__text {
	min-width: 0;

	/*
	 * A last resort for a word that cannot fit at all. `anywhere` rather than
	 * `break-word` so the browser also counts the broken form when sizing
	 * min-content, which is the half that actually lets the card shrink.
	 * Only bites when there is no legal break point — ordinary prose is
	 * untouched.
	 */
	overflow-wrap: anywhere;
}

.fact__title {
	margin: 0;
	font-weight: var(--ih-weight-bold);
	color: var(--ih-ink);
	line-height: var(--ih-leading-tight);
}

.fact__copy {
	margin: var(--ih-space-1) 0 0;
	font-size: var(--ih-text-sm);
	color: var(--ih-text-muted);
}

/*
 * ⚠️ NO BREAKOUT FROM THE READING MEASURE, AND I WROTE ONE FIRST.
 *
 * The draft widened the strip past `.entry-content`'s 70ch cap with a negative
 * margin, so three facts could sit side by side. It referenced
 * `var(--ih-container)` — 1200px — and **page content lives in
 * `.container--narrow`, which is 760px.** The pull would have been 285px each
 * side out of a 760px box: a 1200px strip inside a 760px container, which is
 * the overflow defect this stylesheet has been chasing all night, introduced
 * deliberately by a clever rule.
 *
 * Deleted rather than corrected to the right width, because the requirement
 * dissolves once measured: `minmax(min(15rem, 100%), 1fr)` inside the ~630px
 * measure gives **two columns**, and two columns of facts is fine. The
 * breakout existed to get three, which nothing asked for.
 *
 * A negative margin sized from a container the element is not in is a bug
 * waiting for a different page template.
 */

/*
 * ---------- Where we are: detail beside a map ----------
 *
 * The address and the directions button on one side, the map on the other, so
 * the two things a driver needs are in one glance.
 *
 * One column below 800px and the map goes SECOND, which is the important half:
 * on a phone the address and the call button must come before a 300px map, not
 * after it. Source order already puts the detail first, so a single-column
 * grid gets this right for free — stated because it is the kind of thing a
 * later `order` declaration could silently reverse.
 */
.where {
	display: grid;

	/* See the note on `.symptom-grid`. */
	grid-template-columns: minmax(0, 1fr);
	gap: var(--ih-space-6);
}

@media (min-width: 50em) {
	.where {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
		align-items: center;
	}
}

/*
 * `min-width: 0` on the text column, and `check-theme` is why this rule exists
 * rather than the class being deleted.
 *
 * I wrapped the address and buttons in `.where__detail` and gave it no rule,
 * leaning on `.stack` for the spacing — and the gate refused it, correctly: a
 * class with no rule is either dead or missing one.
 *
 * It is missing one. A grid child defaults to `min-width: auto`, which means it
 * refuses to shrink below its widest unbreakable content — and this column
 * holds an address and two buttons, one of which is a full telephone number.
 * Without this, a narrow column blows the grid out rather than wrapping, which
 * is the same failure as the buttons that could not shrink below their pill
 * padding.
 */
.where__detail {
	min-width: 0;
}

/*
 * The map itself.
 *
 * `aspect-ratio` rather than a fixed height so it scales with the column, and
 * it is the reason no layout shift happens when the lazy iframe arrives: the
 * box is reserved before the frame loads. On a page whose next section carries
 * the 911 line, content jumping down as a map loads is worse than cosmetic.
 *
 * `border: 0` because a UA stylesheet gives an iframe a 2px inset border,
 * which reads as a broken panel around a photograph-like element.
 */
.facility-map {
	border-radius: var(--ih-radius);
	overflow: hidden;
	background: var(--ih-surface-alt);
}

.facility-map__frame {
	display: block;
	width: 100%;
	aspect-ratio: 4 / 3;
	border: 0;
}

@media (min-width: 50em) {
	.facility-map__frame {
		aspect-ratio: 3 / 2;
	}
}

/* ---------- Social links ---------- */

.social-links a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: var(--ih-touch);
	height: var(--ih-touch);
	border: 1px solid rgba(243, 243, 243, 0.25);
	border-radius: 50%;
}

.social-links a:hover,
.social-links a:focus-visible {
	background: var(--ih-brand);
	border-color: var(--ih-brand);
}

.social-links svg {
	width: 18px;
	height: 18px;
}

/* ---------- Pagination ---------- */

.pagination {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ih-space-2);
	justify-content: center;
	padding-block: var(--ih-space-7);
}

.pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: var(--ih-touch);
	min-height: var(--ih-touch);
	padding-inline: var(--ih-space-3);
	border: 1px solid var(--ih-border);
	border-radius: var(--ih-radius);
	text-decoration: none;
}

.pagination .page-numbers.current {
	background: var(--ih-brand);
	border-color: var(--ih-brand);
	color: var(--ih-white);
}

/* ---------- Notice ---------- */

.notice {
	padding: var(--ih-space-4) var(--ih-space-5);
	border-inline-start: 4px solid var(--ih-brand);
	border-radius: var(--ih-radius);
	background: var(--ih-brand-tint);
	color: var(--ih-ink);
}

/* ---------- Emergency / after-hours callout ---------- */

/*
 * The "Come in now" panel. The handoff's 2026-09-14 revision drew this as its
 * own section for the first time — previously the same two sentences sat as
 * small paragraphs inside the hero. This build already had it as a standalone
 * panel in the same position, so the revision only moved the packet's
 * figures: 24px radius and a fluid pad rather than a flat 24px.
 *
 * ⚠️ NO CARD LIFT HERE, though it is a white panel with a border. It is not a
 * card — nothing about it is hoverable, it links nowhere, and a 4px jump under
 * the pointer on the one panel telling somebody to call 911 would be motion
 * for its own sake.
 */
.emergency-notice {
	padding: clamp(26px, 4vw, 42px);
	border: 2px solid var(--ih-brand);
	border-radius: 24px;
	background: var(--ih-white);
}

/*
 * --ih-brand-alt (#a31a27), the packet's colour, measuring 7.68:1 on white —
 * still past AAA for body text. It was --ih-brand-deep, which is darker than
 * the packet asks for.
 */
.emergency-notice strong {
	color: var(--ih-brand-alt);
}

/**
 * Facility block.
 *
 * Used when one address houses more than one facility, so a 24/7 emergency
 * room and a clinic with limited hours are visibly separate schedules rather
 * than one ambiguous list.
 */
.facility-block + .facility-block {
	margin-top: var(--ih-space-4);
	padding-top: var(--ih-space-4);
	border-top: 1px solid rgba(243, 243, 243, 0.15);
}

.facility-block__name {
	margin: 0 0 var(--ih-space-2);
	font-family: var(--ih-font-sans);
	font-size: var(--ih-text-sm);
	font-weight: var(--ih-weight-bold);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ih-white);
}

/* ---------- Contact form (ih-forms plugin) ---------- */

.ih-form {
	display: grid;
	gap: var(--ih-space-4);
	grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
	align-items: start;
}

.ih-form__field--full,
.ih-form__notice {
	grid-column: 1 / -1;
}

.ih-form__field {
	display: flex;
	flex-direction: column;
	gap: var(--ih-space-2);
}

.ih-form label {
	font-weight: var(--ih-weight-medium);
}

.ih-form__required {
	color: var(--ih-brand-deep);
}

.ih-form input,
.ih-form select,
.ih-form textarea {
	min-height: var(--ih-touch);
	padding: var(--ih-space-3);
	border: 2px solid var(--ih-border);
	border-radius: var(--ih-radius);
	background: var(--ih-white);
	color: var(--ih-text);
	font-family: inherit;
	font-size: var(--ih-text-base);
}

.ih-form textarea {
	min-height: 8rem;
	resize: vertical;
}

.ih-form input:focus-visible,
.ih-form select:focus-visible,
.ih-form textarea:focus-visible {
	border-color: var(--ih-brand);
}

/**
 * Honeypot.
 *
 * Positioned off-screen rather than display:none, because bots check for
 * display:none and skip the field — which defeats the entire trap.
 * aria-hidden and tabindex="-1" in the markup keep it away from assistive
 * technology and the tab order, so no real person can reach it by accident.
 */
.ih-form__honeypot {
	position: absolute !important;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.ih-form__notice {
	padding: var(--ih-space-3) var(--ih-space-4);
	border-inline-start: 4px solid var(--ih-brand);
	border-radius: var(--ih-radius);
	background: var(--ih-brand-tint);
	color: var(--ih-ink);
	font-size: var(--ih-text-sm);
}

.form-notice {
	padding: var(--ih-space-4);
	border-radius: var(--ih-radius);
	font-weight: var(--ih-weight-medium);
}

.form-notice--ok {
	background: var(--ih-grey-100);
	border-inline-start: 4px solid var(--ih-brand);
}

.form-notice--error {
	background: var(--ih-brand-tint);
	border-inline-start: 4px solid var(--ih-brand-deep);
}

/* ---------- Service router (ih_compare) ---------- */

.compare {
	display: grid;
	gap: var(--ih-space-5);
	grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
	align-items: stretch;
}

.compare-col {
	display: flex;
	flex-direction: column;
	background: var(--ih-white);
	border: 1px solid var(--ih-border);
	border-radius: var(--ih-radius-lg);
	overflow: hidden;

	/* The handoff's card lift — see `.card:hover` for the shared rule. */
	transition: transform var(--ih-duration) var(--ih-ease),
		box-shadow var(--ih-duration) var(--ih-ease);
}

/**
 * The asymmetry is deliberate: in an emergency the eye should land on the
 * emergency option first. Keyed to the facility's schema_type rather than to
 * a facility name, so this renders correctly for any two-facility site.
 */
.compare-col--urgent {
	border-color: var(--ih-brand);
	box-shadow: var(--ih-shadow);
}

.compare-col--routine {
	box-shadow: var(--ih-shadow-sm);
}

.compare-head {
	padding: var(--ih-space-5);
	color: var(--ih-white);
}

.compare-col--urgent .compare-head {
	background: var(--ih-brand);
}

.compare-col--routine .compare-head {
	background: var(--ih-ink);
}

.compare-head h3 {
	margin: 0;
	color: var(--ih-white);
}

.compare-sub {
	margin: var(--ih-space-1) 0 0;
	font-size: var(--ih-text-sm);
	opacity: 0.85;
}

.compare-body {
	display: flex;
	flex: 1;
	flex-direction: column;
	gap: var(--ih-space-4);
	padding: var(--ih-space-5);
}

.go-if {
	margin: 0;
	font-weight: var(--ih-weight-bold);
}

.compare-list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.compare-list li {
	display: flex;
	gap: var(--ih-space-2);
	align-items: start;
	margin-top: var(--ih-space-2);
}

.compare-list svg {
	flex: 0 0 auto;
	width: 18px;
	height: 18px;
	margin-top: 0.2em;
	color: var(--ih-brand);
}

/* Billing honesty, not a feature list — see ih_compare(). */
.compare-facts {
	display: grid;

	/* See the note on `.symptom-grid`. */
	grid-template-columns: minmax(0, 1fr);
	gap: var(--ih-space-2);
	padding: var(--ih-space-4);
	border-radius: var(--ih-radius);
	background: var(--ih-surface-alt);
	font-size: var(--ih-text-sm);
}

.compare-facts strong {
	display: block;
	color: var(--ih-brand-deep);
}

.compare-body .btn {
	margin-top: auto;
	align-self: start;
}

.compare-note {
	margin-top: var(--ih-space-5);
	padding: var(--ih-space-4) var(--ih-space-5);
	border-inline-start: 4px solid var(--ih-brand);
	border-radius: var(--ih-radius);
	background: var(--ih-brand-tint);
	font-weight: var(--ih-weight-medium);
}

/* ---------- Emergency symptom grid (ih_symptom_grid) ---------- */

.symptom-grid {
	display: grid;
	gap: var(--ih-space-4);
	/*
	 * ⚠️ `minmax(0, 1fr)`, NEVER A BARE `1fr` OR AN UNDECLARED TRACK. Both
	 * resolve to `minmax(auto, 1fr)`, and an `auto` minimum is floored at the
	 * content's min-content width — so the track grows PAST its own container
	 * rather than making its contents wrap, and any `max-width: 100%` inside
	 * then resolves against a box that is already too wide.
	 *
	 * Reported by the FHMC session, which measured a 429px track inside a
	 * 305px container. The dangerous version is the one with no
	 * `grid-template-columns` at all, because there is no `1fr` to grep for.
	 */
	grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 40rem) {
	.symptom-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (min-width: 62rem) {
	.symptom-grid {
		grid-template-columns: repeat(3, 1fr);
	}
}

/*
 * ---------- Grouped symptom list (ih_symptom_groups) ----------
 *
 * The client on the flat grid: "that plain text is bland and does not work for
 * me. Also does it all need to be listed line by line like that?"
 *
 * Nothing was cut. Fifteen presentations stay, grouped under themes with a
 * photograph each, because the list's own rule is that the failure mode to
 * design against is the person who reads it, does not see themselves, and
 * stays home. Grouping gives a frightened reader a coarse target before a fine
 * one: "Arizona and the desert" is found faster than the twelfth card down.
 *
 * `align-items: start` so a group with three entries does not stretch to match
 * a group with four — stretched cards are what made the flat grid feel like a
 * spreadsheet.
 */
/*
 * ---------- Reviews (ih_reviews) ----------
 *
 * The embed is a third-party iframe, so its internal height is not ours to
 * know. A fixed `height` would clip the last review at one breakpoint and
 * leave a gap at another, and there is no way to measure inside it without
 * giving the vendor a script in our origin — which is the exact thing the
 * iframe exists to avoid.
 *
 * So: a generous min-height that fits the slider at every width, and the
 * frame fills it. Slightly too much space beneath a short widget is a better
 * failure than a review cut in half.
 */
.reviews__embed {
	border: 1px solid var(--ih-border);
	border-radius: var(--ih-radius-lg);
	background: var(--ih-white);
	overflow: hidden;
}

.reviews__frame {
	display: block;
	width: 100%;
	min-height: 420px;
	border: 0;
}

@media (min-width: 48em) {
	.reviews__frame {
		min-height: 340px;
	}
}

.symptom-groups {
	display: grid;
	gap: var(--ih-space-6);

	/* See the note on `.symptom-grid`. */
	grid-template-columns: minmax(0, 1fr);
	align-items: start;
}

@media (min-width: 62rem) {
	.symptom-groups {
		grid-template-columns: repeat(2, 1fr);
	}

	/*
	 * 🔴 THE LAST GROUP SPANS BOTH COLUMNS, BECAUSE FIVE CARDS IN TWO COLUMNS
	 * LEFT IT STRANDED.
	 *
	 * The client: *"i do not like the placement. i think you can arrange those
	 * better."* Measured on the rendered homepage: two columns, five groups,
	 * rows of [1,2] [3,4] [5] — the fifth alone on its own row.
	 *
	 * ⚠️ AND IT IS THE WORST OF THE FIVE TO STRAND, for the second time on this
	 * page. The fifth group is **"When you are not sure, or not safe"** — the
	 * catch-all written for exactly the reader the section exists to reach.
	 * Core's own symptom-grid docblock states the rule: *"the failure mode to
	 * design against is the person who reads it, does not see themselves, and
	 * stays home."* Leaving that group as a lone card below four neat ones made
	 * it look like a leftover.
	 *
	 * Spanning it removes the orphan arithmetically — 4 fill a 2x2, 1 spans —
	 * and turns the accident into the intent: the list ends full width with
	 * *come anyway*, which is the most important thing on it.
	 *
	 * `:last-child` rather than `:nth-child(5)` so a site with four groups or
	 * six is handled without editing this rule. With an even count the last
	 * card spans a row of its own, which is still a deliberate closer rather
	 * than a gap.
	 */
	.symptom-group:last-child {
		grid-column: 1 / -1;
	}

	/*
	 * The spanning card goes horizontal: image beside the text rather than
	 * above it.
	 *
	 * Full width with the image on top would be a very tall block and a
	 * 1100px-wide photograph of a phone on a table — the emphasis would land
	 * on the picture instead of on the sentence. Side by side keeps the card
	 * the height of its own content.
	 */
	/*
	 * ⚠️ `align-items: center` AND THE IMAGE KEEPS A DEFINITE ASPECT RATIO.
	 * The first version used `align-items: stretch` with
	 * `height: 100%; aspect-ratio: auto` on the image, and it rendered the card
	 * **1502px tall with 301px of content in it.**
	 *
	 * Measured: body 655x1500, its two children 37 + 264. Nothing was tall —
	 * the height was invented. `height: 100%` resolves against an indefinite
	 * parent height, the parent's height comes from the child, and the image is
	 * **lazy-loaded**, so at layout time it has no intrinsic size to break the
	 * circularity with. `naturalWidth` was 0. The browser picked a number.
	 *
	 * 🔴 AND THE RULE I OVERRODE HAD A COMMENT SAYING WHY IT EXISTED. Twenty
	 * lines up: *"`aspect-ratio` plus `object-fit: cover` rather than a fixed
	 * height. A fixed height crops differently at every breakpoint and is how
	 * the blog cards ended up with their titles sliced off."* I replaced that
	 * `aspect-ratio` with `auto` to make a side-by-side layout work, which
	 * removed the box reservation the comment was protecting. **Third time
	 * tonight I have written past a note explaining the thing I was about to
	 * break.**
	 *
	 * So: no percentage heights anywhere. Each child sizes itself from its own
	 * content — the image from a declared ratio, the text from its text — and
	 * the card is as tall as the taller one. Deterministic before the image
	 * loads, which is the whole point of declaring a ratio.
	 */
	.symptom-group:last-child {
		flex-direction: row;
		align-items: center;
	}

	.symptom-group:last-child .symptom-group__media {
		flex: 0 0 40%;
	}

	.symptom-group:last-child .symptom-group__img {
		aspect-ratio: 4 / 3;
	}

	.symptom-group:last-child .symptom-group__body {
		flex: 1 1 auto;
		min-width: 0;
		padding-top: var(--ih-space-5);
	}
}

.symptom-group {
	display: flex;
	flex-direction: column;
	gap: var(--ih-space-4);
	overflow: hidden;
	border: 1px solid var(--ih-border);
	border-radius: var(--ih-radius-lg);
	background: var(--ih-white);

	/*
	 * `--ih-shadow`, not `--ih-shadow-sm`. The packet gives these the same
	 * resting card shadow as every other white card; ours was a third of the
	 * blur on a card the width of a third of the homepage, which read as flat
	 * beside the cards next to it.
	 */
	box-shadow: var(--ih-shadow);

	/* The handoff's card lift — see `.card:hover` for the shared rule. */
	transition: transform var(--ih-duration) var(--ih-ease),
		box-shadow var(--ih-duration) var(--ih-ease);
}

.symptom-group__media {
	margin: 0;
	background: var(--ih-surface-sunk);
}

/*
 * `aspect-ratio` plus `object-fit: cover` rather than a fixed height. A fixed
 * height crops differently at every breakpoint and is how the blog cards ended
 * up with their titles sliced off.
 */
.symptom-group__img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
}

.symptom-group__body {
	display: flex;
	flex-direction: column;
	gap: var(--ih-space-4);
	padding: 0 var(--ih-space-5) var(--ih-space-5);
}

.symptom-group__title {
	margin: 0;
	font-size: var(--ih-text-xl);
	line-height: var(--ih-leading-snug);
}

/*
 * ⚠️ `overflow-wrap: anywhere` HERE, MEASURED, NOT GLOBALLY.
 *
 * `.symptom-group` sets `overflow: hidden` for its rounded corners, so text
 * that cannot wrap is CLIPPED rather than overflowing — content loss with no
 * scrollbar to reveal it. base.css sets `overflow-wrap: break-word` globally
 * and its comment explains why it stopped short of `anywhere`; that decision
 * stands and is not changed here.
 *
 * But it is not theoretical on every site. Measured on FHMC at 200% text in
 * a 320px viewport, with REAL content and nothing injected: **43px clipped**,
 * on the homepage and the emergency-room page. El Mirage measures clean under
 * the same global because its symptom terms are shorter — the site with an
 * "&" and three words in a single term is the one that hits it.
 *
 * This is an emergency room's symptom list. A reader deciding whether to come
 * in should not lose the end of a line to a rounded corner, and they get no
 * scrollbar telling them something is missing. So `anywhere` is applied to the
 * one component that is measured to need it, which is the same rule the rest
 * of this file follows.
 */
.symptom-group__list,
.symptom-group__title,
.symptom-group__list li {
	overflow-wrap: anywhere;
}

.symptom-group__list {
	display: grid;

	/*
	 * Declared, and floored at 0. This was an undeclared single-column
	 * grid, so its track was `auto` and floored at min-content: measured
	 * at 291.9px inside a 143px container at 200% text, which is how a
	 * symptom card came to hang off the side of the homepage.
	 * See `.symptom-grid`.
	 */
	grid-template-columns: minmax(0, 1fr);
	gap: var(--ih-space-3);
	margin: 0;
	padding: 0;
	list-style: none;
}

/**
 * Left border rather than colour alone, so the list still reads as urgent
 * without depending on colour perception.
 */
.symptom {
	display: flex;
	gap: var(--ih-space-3);
	align-items: start;
	padding: var(--ih-space-4);
	border-inline-start: 4px solid var(--ih-brand);
	border-radius: var(--ih-radius);
	background: var(--ih-surface-alt);
}

.symptom svg {
	flex: 0 0 auto;
	width: 22px;
	height: 22px;
	color: var(--ih-brand);
}

.symptom strong {
	display: block;
	color: var(--ih-ink);
}

.symptom span {
	display: block;
	margin-top: var(--ih-space-1);
	color: var(--ih-text-muted);
	font-size: var(--ih-text-sm);
}

/* ---------- Provider role line (ih_provider_role) ---------- */

.provider-role {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ih-space-2);
	align-items: baseline;
	margin: 0 0 var(--ih-space-3);
}

.provider-role__credentials {
	color: var(--ih-brand-deep);
	font-size: var(--ih-text-sm);
	font-weight: var(--ih-weight-bold);
	letter-spacing: 0.04em;
	text-transform: uppercase;
}

.provider-role__title {
	color: var(--ih-text-muted);
}

/* ----------------------------------------------- mobile submenu toggle */

/*
 * `navigation.js` injects `<button class="submenu-toggle">` into every parent
 * menu item, and NOTHING styled it. Specced by the Fountain Hills session,
 * which measured what it actually rendered as before their session ended:
 *
 *   background  rgb(240,240,240)  — the OS default grey
 *   border      2px outset        — the 3D bevel
 *   font        Arial 13.3px      — not Rethink Sans
 *   cursor      default           — does not read as clickable
 *   target      27 × 22px         — against a 44px floor
 *
 * sitting beside nav links in Rethink Sans 16.1px.
 *
 * ⚠️ THE TOUCH TARGET IS THE PART THAT MATTERS. 22px on the mobile navigation
 * of an emergency room's website, while the parent link next to it was
 * correctly 51px. `--ih-touch` exists and this button ignored it.
 *
 * `color` and `font` inherit rather than naming tokens, so the toggle tracks
 * whatever the nav link beside it uses instead of drifting from it the next
 * time type changes.
 */
.submenu-toggle {
	display: grid;
	place-items: center;
	min-width: var(--ih-touch);
	min-height: var(--ih-touch);
	padding: 0;
	border: 0;
	background: none;
	color: inherit;
	font: inherit;
	line-height: 1;
	cursor: pointer;
}

/*
 * ⚠️ THE 44px TOUCH TARGET IS FOR TOUCH, and above 1024px the drawer is gone
 * and submenus already open on `:hover` and `:focus-within`.
 *
 * Three dropdowns at 44px wide were taking 132px out of the masthead — enough
 * to push a five-item menu onto a second line, which is what made the header
 * 157px tall. The caret is now a small inline affordance beside its link, and
 * it remains a real focusable button, so keyboard and screen-reader users keep
 * the explicit control.
 *
 * `--ih-touch` still applies below 1024px, where the drawer is tapped.
 *
 * 🔴 BUT 1.25rem WAS 20px, AND THAT FAILS WCAG 2.2 AA. Success criterion
 * 2.5.8 Target Size (Minimum) sets a **24 x 24 CSS pixel** floor for pointer
 * targets — not the 44px touch guideline this comment was reasoning about, a
 * separate and lower bar that applies to *every* pointer including a mouse.
 * Measured at 20 x 20 by an audit of the rendered page, on all three parent
 * items.
 *
 * I had written the 44px exemption carefully and correctly and then landed
 * below the other limit, which I had not considered at all. **Relaxing a
 * strict rule is where you find out whether you knew the lenient one.**
 *
 * 1.5rem is 24px: it satisfies 2.5.8, and it costs 12px across three carets
 * rather than the 132px that broke the masthead. The header stays one row —
 * verified after the change, not assumed.
 */
@media (min-width: 64.0625em) {
	.submenu-toggle {
		min-width: 1.5rem;
		min-height: 1.5rem;
		margin-left: calc(var(--ih-space-1) * -1);
		font-size: 0.7em;
		opacity: 0.75;
	}

	.submenu-toggle:hover,
	.submenu-toggle:focus-visible {
		opacity: 1;
	}
}

/*
 * A keyboard control injected into a nav needs a visible focus ring. It had
 * none, and it had `cursor: default`, so it signalled nothing in either
 * direction — neither to a mouse user nor to a keyboard user.
 */
.submenu-toggle:focus-visible {
	outline: var(--ih-focus-width) solid var(--ih-focus);
	outline-offset: 2px;
}

/*
 * The caret turns to point up when the submenu is open. `aria-expanded`
 * already carries this for assistive technology; this is the sighted
 * equivalent, and it costs one rule.
 */
.submenu-toggle[aria-expanded='true'] > [aria-hidden='true'] {
	transform: rotate(180deg);
}

/* ------------------------------------------------- surprise-billing notice */

/*
 * A native `<dialog>`, which buys the focus trap, the `Escape` key and the
 * backdrop for free — all three of which a hand-rolled modal gets wrong, and
 * the focus trap is the one that matters for a screen-reader user who would
 * otherwise be reading the page behind it.
 *
 * Capped at `min(30rem, …)` so it never fills a phone screen. A dialog a
 * worried person cannot see past is the failure this replaces.
 */
/*
 * 🔴 A CORNER CARD, NOT A CENTRED MODAL, since 2026-09-14. The handoff asks
 * for it, and it is the right call here for a reason beyond appearance.
 *
 * This used to open with `showModal()` behind a 55% backdrop. The comment
 * defending that backdrop argued it was "deliberately light" because "a
 * near-black backdrop on an emergency room's site reads as an alarm" —
 * correct as far as it went, and it never asked the prior question: whether a
 * billing reassurance should be covering the page at all. Behind it sat the
 * 911 line, both phone numbers and the directions link, every one of them
 * made inert by the modal.
 *
 * A billing note is the least urgent thing on any page in this family, and it
 * was the only element capable of blocking the most urgent ones. It now sits
 * in the corner, the page stays live, and dismissing it is one button.
 *
 * The `::backdrop` rule is deleted rather than restyled: a non-modal dialog
 * never paints one, so keeping it would leave a rule that can no longer match
 * anything — the kind of dead CSS `check-theme` exists to find.
 */
.billing-notice {
	position: fixed;
	inset: auto auto var(--ih-space-5) var(--ih-space-5);
	z-index: 60;

	width: min(26.25rem, calc(100vw - 2 * var(--ih-space-5)));

	/*
	 * Never taller than the viewport it floats over. Three paragraphs on a
	 * short phone in landscape would otherwise run off both ends of the
	 * screen, carrying the dismiss button with them — the one control that
	 * makes an uninvited panel tolerable.
	 */
	max-height: calc(100dvh - 2 * var(--ih-space-5));
	overflow-y: auto;

	padding: var(--ih-space-5);
	border: 1px solid var(--ih-border);
	border-radius: var(--ih-radius-lg);
	background: var(--ih-surface);
	color: var(--ih-text);
	box-shadow: var(--ih-shadow-lg);
}

.billing-notice > * + * {
	margin-block-start: var(--ih-space-3);
}

.billing-notice h2 {
	margin: 0;
	font-size: var(--ih-text-xl);
	line-height: 1.2;
}

/*
 * Buttons stack on a narrow screen rather than shrinking. "Got it" must stay
 * comfortably tappable at the smallest width this site supports.
 */
@media (max-width: 26rem) {
	.billing-notice .cta-group {
		flex-direction: column;
		align-items: stretch;
	}
}

/*
 * ---------- Statistic cards ----------
 *
 * A number, its unit, and the sentence that qualifies it. From the Modern
 * handoff, which uses them for wait times on the homepage and the ER page.
 *
 * The top rule is the component's whole job: it makes a card that is a
 * BENCHMARK visually distinct from a card that is OUR figure, so a reader
 * skimming three big red numerals does not read a cited national average as
 * a boast. See ih_stats_shortcode()'s docblock for why the register cares.
 */
.stat-row {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
	gap: var(--ih-space-4);
	margin-block: var(--ih-space-6) 0;
}

.stat {
	padding: var(--ih-space-5);
	background: var(--ih-surface);
	border: 1px solid var(--ih-border);
	border-radius: var(--ih-radius-lg);
	box-shadow: var(--ih-shadow);

	/*
	 * `border-block-start` rather than `border-top`: the rest of this
	 * stylesheet is logical-property-first, and a right-to-left rendering of
	 * these sites would still want the rule above the number.
	 */
	border-block-start: 6px solid var(--ih-brand);

	/* The handoff's card lift — see `.card:hover` for the shared rule. */
	transition: transform var(--ih-duration) var(--ih-ease),
		box-shadow var(--ih-duration) var(--ih-ease);
}

/*
 * A cited benchmark, not one of ours. Grey rule, and the numeral drops to the
 * body ink so it reads as reference rather than achievement.
 */
.stat--muted {
	border-block-start-color: var(--ih-grey-300);
}

.stat--muted .stat__figure {
	color: var(--ih-text-muted);
}

.stat__figure {
	margin: 0;
	font-family: var(--ih-font-display);
	font-weight: var(--ih-weight-display);

	/*
	 * Larger than any heading on the page, on purpose — the numeral IS the
	 * content here. Clamped so it never outgrows a 260px card column.
	 */
	font-size: clamp(2.75rem, 4vw, 3.625rem);
	line-height: 1;
	letter-spacing: -0.02em;
	color: var(--ih-brand);
}

.stat__unit {
	margin-inline-start: var(--ih-space-2);
	font-size: var(--ih-text-xl);
}

.stat__copy {
	margin: var(--ih-space-3) 0 0;
	font-size: var(--ih-text-sm);
	line-height: var(--ih-leading-normal);
	color: var(--ih-text-muted);
}

/*
 * ---------- The closing band ----------
 *
 * A full-bleed brand panel at the foot of a page, from the Modern handoff.
 * Gradient rather than flat so it reads as a deliberate close rather than as
 * an oversized button.
 */
.closing-band {
	background: linear-gradient(135deg, var(--ih-brand), var(--ih-brand-deep));
	color: var(--ih-white);
	padding-block: clamp(var(--ih-space-7), 7vw, var(--ih-space-9));
	margin-block-start: var(--ih-space-8);
}

.closing-band__title {
	margin: 0;

	/*
	 * White on the gradient, not --ih-ink. Core's `h1..h4` rule sets
	 * `color: var(--ih-ink)`, which on a dark red panel is the invisible-text
	 * failure the fhmc session reported for .emergency-notice — a heading
	 * inheriting a dark colour onto a dark background. Set explicitly here
	 * rather than relying on the section's `color` being inherited, because
	 * that rule would win.
	 */
	color: var(--ih-white);
}

.closing-band__copy {
	max-width: var(--ih-measure);
	margin-block: var(--ih-space-4) 0;

	/*
	 * Slightly held back from pure white so the headline still leads, but only
	 * slightly: measured at 92% this is 12.1:1 on the lighter end of the
	 * gradient, comfortably past AA. Going further would start trading
	 * legibility for hierarchy on the one panel that asks someone to come in.
	 */
	color: rgb(255 255 255 / 92%);
}

.closing-band__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ih-space-3);
	margin-block-start: var(--ih-space-5);
}

/*
 * Buttons for use ON the brand colour. The standard .btn--primary is brand red
 * on white; inside this band that would be red on red.
 */
.btn--on-brand {
	background: var(--ih-white);
	color: var(--ih-brand-deep);
	border: 1.5px solid var(--ih-white);
}

.btn--on-brand:hover,
.btn--on-brand:focus-visible {
	background: var(--ih-brand-tint);
	color: var(--ih-brand-deep);
}

.btn--outline-on-brand {
	background: transparent;
	color: var(--ih-white);
	border: 1.5px solid rgb(255 255 255 / 75%);
}

.btn--outline-on-brand:hover,
.btn--outline-on-brand:focus-visible {
	border-color: var(--ih-white);
	background: rgb(255 255 255 / 12%);
	color: var(--ih-white);
}

/*
 * ⚠️ The focus ring is --ih-focus, a blue that measures 1.3:1 against the
 * brand red this band is painted in. `:focus-visible` in base.css draws it
 * with `outline-offset: 2px`, which puts it on the page background everywhere
 * else — but here the background IS the brand colour, so the offset does not
 * save it. A white ring is the only one visible on this panel.
 */
.closing-band :focus-visible {
	outline-color: var(--ih-white);
}

/*
 * ---------- The dark band ----------
 *
 * A full-bleed ink panel for a section that needs to stand apart from the
 * pages either side of it. The handoff uses it five times across the site,
 * always for the same job: the passage a reader most needs to stop at —
 * "is this bad enough to come in", "why there is no single price", the
 * 24-hour observation explanation.
 *
 * ⚠️ THREE THINGS MUST BE SET EXPLICITLY ON A DARK PANEL, and two of them
 * would otherwise be silently wrong rather than visibly broken. This is the
 * same list the closing band needed; it is written out again because the next
 * dark surface will need it too and the failures are invisible.
 */
.section--dark {
	background: var(--ih-ink);
	color: var(--ih-white);
	padding-block: clamp(var(--ih-space-6), 5vw, var(--ih-space-8));
}

/*
 * 1. Headings. Core's `h1..h4` rule sets `color: var(--ih-ink)` — a specific
 *    declaration that beats the section's inherited white, so a heading here
 *    renders ink-on-ink. This is exactly the defect the fhmc session reported
 *    on .emergency-notice, where two templates painted --ih-ink behind text
 *    that had no colour of its own.
 */
.section--dark h1,
.section--dark h2,
.section--dark h3,
.section--dark h4 {
	color: var(--ih-white);
}

/*
 * 2. Links. --ih-brand on ink measures 2.33:1 and fails AA outright; --ih-brand-tint is
 *    12.34:1 and still reads as brand. Underlined as well
 *    because on a dark field colour alone is a weaker signal, and 1.4.1
 *    asks that colour never be the only means of conveying information.
 */
.section--dark a:not(.btn) {
	color: var(--ih-brand-tint);
	text-decoration-thickness: from-font;
}

/*
 * 3. The focus ring. --ih-focus is a blue at 1.79:1 against --ih-ink. The
 *    `outline-offset: 2px` in base.css saves it on light pages by drawing it
 *    on the page background — here the page background IS the dark panel, so
 *    the offset does not help and the ring has to change.
 */
.section--dark :focus-visible {
	outline-color: var(--ih-white);
}

/*
 * ---------- Pull quote ----------
 *
 * A passage set apart by a brand rule rather than by quotation marks. Drawn
 * once in the handoff: the closing argument on the ER-versus-urgent-care page,
 * just below the comparison table.
 *
 * 🔴 NOT "A QUOTATION", though the name says quote and the drawing looks like
 * one. `ih_pull_shortcode()` emits a `<div>` on purpose; read the note there.
 * The passage the handoff puts in here is the SITE's argument, two sentences
 * after it cites the National Library of Medicine — so a treatment that reads
 * as attribution would be attributing our sales case to them.
 *
 * ⚠️ `check-quotations` governs what may go in one of these. It fails the
 * build on a quotation carrying an A.D.A.M./Ebix encyclopedia URL, which is a
 * licensing exposure rather than a style preference — that gate exists because
 * four passages were being reproduced on that exact page. A styled container
 * makes quoting feel more legitimate, so the rule matters more here than in
 * body prose, not less.
 *
 * `cite` is styled below for the day a genuinely quotable source turns up.
 */
.pull-quote {
	margin-block: var(--ih-space-5);
	padding-inline-start: var(--ih-space-5);
	border-inline-start: 4px solid var(--ih-brand);

	/*
	 * 15.5px/26px, which is SMALLER than the 17px body — the packet's figure,
	 * and deliberate on its part. The red rule carries the emphasis, so the
	 * type does not have to, and setting it larger as well (it was
	 * `--ih-text-lg`, 20px) made the passage shout twice.
	 */
	font-size: 0.96875rem;
	line-height: 1.6774; /* 26 / 15.5 */
	color: var(--ih-text);
}

.pull-quote cite {
	display: block;
	margin-block-start: var(--ih-space-3);
	font-size: var(--ih-text-sm);
	font-style: normal;
	color: var(--ih-text-muted);
}

/*
 * The band's inner wrapper: restores the reading measure the band itself
 * escapes. See ih_band_shortcode() for why both halves are needed.
 */
.band {
	padding-inline: var(--ih-gutter);
	border-radius: var(--ih-radius-lg);
	margin-block: var(--ih-space-6);
}

.band__inner {
	max-width: var(--ih-measure);
	margin-inline: auto;
}

.band__inner > :first-child {
	margin-block-start: 0;
}

.band__inner > :last-child {
	margin-block-end: 0;
}

/*
 * ---------- FAQ accordions ----------
 *
 * Native `<details>` and `<summary>`, no JavaScript. The handoff specifies
 * native elements and is right to: keyboard operation, screen-reader
 * semantics and expand-on-find-in-page all come free, and every one of them
 * would have to be rebuilt by hand on a div-and-click version.
 *
 * ⚠️ THE MARKER IS DRAWN, NOT TYPED. `::marker` on a summary is
 * inconsistently styleable across browsers, so the disclosure triangle is
 * removed and a `+` is composed from two pseudo-element bars that rotate
 * into an `×`. That keeps the control's appearance under this stylesheet's
 * control rather than the browser's. The packet types a literal `+` glyph;
 * the drawn one renders identically and does not depend on the body font
 * having a well-centred plus.
 *
 * 🔴 EACH ROW IS ITS OWN CARD, CORRECTED 2026-09-14. I first built these as
 * one list divided by rules, which is a common accordion pattern but is not
 * what the packet draws — it gives every `<details>` the white fill, the 1px
 * border, a 16px radius and the resting card shadow, separated by a 12px gap.
 * That was wrong in my first pass against the original packet too, not just
 * against the revision.
 *
 * The gap is a margin rather than a flex `gap` on a wrapper, because
 * `toAccordions()` emits the `<details>` elements as bare siblings in the
 * content and adding a wrapper would mean republishing every page to change a
 * visual detail.
 */
.faq-item {
	background: var(--ih-white);
	border: 1px solid var(--ih-border);
	border-radius: 16px;
	padding-inline: 22px;
	box-shadow: var(--ih-shadow);
	margin-block-end: 12px;

	/* The handoff's card lift — see `.card:hover` for the shared rule. */
	transition: transform var(--ih-duration) var(--ih-ease),
		box-shadow var(--ih-duration) var(--ih-ease);
}

/*
 * ⚠️ ZEROED SO THE 12px ABOVE ACTUALLY APPLIES. Adjacent siblings collapse to
 * the LARGER of the two margins, and `.entry-content` gives every flow child a
 * 16px top — so setting only `margin-block-end: 12px` measured 16px on the
 * rendered page. Between two rows the gap is now 12px; the first row keeps the
 * inherited top margin, which is what separates it from its heading.
 */
.faq-item + .faq-item {
	margin-block-start: 0;
}

.faq-item summary {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--ih-space-4);

	/*
	 * ⚠️ THE LAST 200%-TEXT OVERFLOW ON THE SITE, and it was here. Measured
	 * in a 320px frame: this summary's min-content was 287px against 219px of
	 * content box, so `/faq/` scrolled sideways by 32px while every other one
	 * of the 47 pages was clean.
	 *
	 * A question is a flex container, and the text inside it is an anonymous
	 * flex item with `min-width: auto` — it will not go below its longest
	 * WORD. At 34px, "appointment?" alone is most of the available width once
	 * the 22px side padding and the drawn `+` have taken theirs.
	 *
	 * `anywhere` rather than `break-word` for the reason given on
	 * `.fact__text`: only `anywhere` lets the broken form count toward
	 * min-content, which is the half that actually shrinks the box. It bites
	 * only when a word cannot otherwise fit, so questions at ordinary text
	 * size are untouched.
	 */
	min-width: 0;
	overflow-wrap: anywhere;

	/*
	 * The whole row is the control, so it needs a real target height. A
	 * summary is focusable and clickable by default but has no minimum size,
	 * and a one-line question on a phone lands well under the 44px floor
	 * `--ih-touch` exists to enforce.
	 */
	min-height: var(--ih-touch);
	padding-block: 18px;

	font-family: var(--ih-font-display);
	font-weight: var(--ih-weight-display);
	font-size: var(--ih-text-base);
	line-height: var(--ih-leading-snug);
	color: var(--ih-ink);
	cursor: pointer;

	/* Remove the native triangle in both engines. */
	list-style: none;
}

.faq-item summary::-webkit-details-marker {
	display: none;
}

.faq-item summary:hover {
	color: var(--ih-brand);
}

/* The drawn +, which becomes × when open. */
.faq-item summary::after {
	content: '';
	flex: none;
	inline-size: 1rem;
	block-size: 1rem;
	margin-block-start: 0.15em;

	/*
	 * Two bars via crossed gradients rather than two extra elements, so the
	 * marker needs no markup of its own and cannot be lost by an editor.
	 */
	background:
		linear-gradient(var(--ih-brand), var(--ih-brand)) center / 100% 2px no-repeat,
		linear-gradient(var(--ih-brand), var(--ih-brand)) center / 2px 100% no-repeat;

	transition: transform var(--ih-duration) var(--ih-ease);
}

.faq-item[open] summary::after {
	transform: rotate(45deg);
}

.faq-item__answer {
	padding-block-end: 20px;
}

.faq-item__answer > :first-child {
	margin-block-start: 0;
}

.faq-item__answer > :last-child {
	margin-block-end: 0;
}

/*
 * ---------- The page kicker ----------
 *
 * A tint pill above an interior page's headline, from the handoff: tint fill,
 * deep red, uppercase, 13.5px, pill radius. Tells a reader what KIND of page
 * they are on before they read the title.
 *
 * --ih-brand-deep on the tint is 8.37:1, which matters more here than at body
 * size: this is small uppercase text with added letter-spacing, the least
 * legible combination on the site, so it gets the darkest red rather than the
 * brand one.
 */
.page-kicker,
.hero__eyebrow {
	display: inline-flex;
	margin: 0 0 20px;
	padding: 7px 16px;
	background: var(--ih-brand-tint);
	color: var(--ih-brand-deep);
	border-radius: var(--ih-radius-pill);
	font-size: 0.84375rem; /* 13.5px */
	font-weight: var(--ih-weight-bold);
	letter-spacing: 0.04em;
	text-transform: uppercase;

	/*
	 * 🔴 THE PACKET'S `white-space: nowrap` IS CONDITIONAL HERE, AND ONLY
	 * HERE. Measured on staging in a 320px frame at 200% text: the longest
	 * kicker, "Understanding an ER visit", renders at 27px and is 408px wide
	 * with nowrap — against a 314px viewport, a right edge of 440px. It does
	 * not fit, and `overflow-wrap` cannot break a line that is forbidden to
	 * wrap, so the page gets a horizontal scrollbar. That is the WCAG 1.4.10
	 * reflow failure.
	 *
	 * `.btn` was measured the same way and does fit, so it takes the packet's
	 * flat nowrap. The difference is uppercase plus 0.04em tracking: this is
	 * the widest string on the site for its font size.
	 *
	 * THE QUERY IS IN `rem` AND THAT IS THE MECHANISM. A `px` query asks only
	 * about the viewport; a `rem` query asks about the viewport measured in
	 * the reader's own text size. At 200% text 30rem is 960px, so a 320px
	 * phone does not match and the label wraps to two lines. At default text
	 * the same query is 480px, every real phone matches, and the packet's
	 * nowrap is what ships. Changing this to `px` silently re-breaks it.
	 */
	white-space: normal;
}

@media (min-width: 30rem) {
	.page-kicker,
	.hero__eyebrow {
		white-space: nowrap;
	}
}

/* The hero drawing gives its pill 22px below, not the 20px an interior page uses. */
.hero__eyebrow {
	margin-bottom: 22px;
}
