/* ==========================================================================
   Home screen
   Contents: hero · payment strip · service tiles · city tiles · trust row
   ========================================================================== */


/* Hero
   ========================================================================== */

/*
 * The surface: the brand blue, deepening downwards, with light falling from the
 * top-left corner. In parts, because a wide screen adds a mirrored copy of the
 * light on the right (see the 1400px rule at the end of this section).
 */
.home-hero {
	--home-hero-light: radial-gradient(120% 90% at 0% 0%, rgb(46 104 196 / 0.55) 0%, transparent 55%);
	--home-hero-light-mirrored: radial-gradient(120vw 90% at 100% 0%, rgb(46 104 196 / 0.55) 0%, transparent 55%);
	--home-hero-blue: linear-gradient(180deg, #1c4a92 0%, var(--color-hero) 100%);

	position: relative;
	display: flex;
	container-type: inline-size; /* for --container-edge */
	flex-direction: column;
	overflow: hidden;
	color: var(--color-white);
	background: var(--home-hero-light), var(--home-hero-blue);
}

/* Soft brand arcs behind the text panel. */
.home-hero::before {
	position: absolute;
	top: -140px;
	left: 30%;
	width: 520px;
	height: 520px;
	pointer-events: none;
	content: "";
	border: 60px solid rgb(255 255 255 / 0.035);
	border-radius: 50%;
}

.home-hero__media {
	position: relative;
	height: var(--hero-media-height);
}

/*
 * The fade lives on the slides, not on .home-hero__media around them.
 *
 * A mask applies to an element AND its descendants, so while it sat on the
 * media block it also faded the pause button in the bottom-right corner —
 * on phones, where the mask runs downwards, precisely into nothing. The two
 * elements occupy the same box (inset: 0), so moving it changes no pixel of
 * the photograph and takes the button out from under it.
 */
.home-hero__slides {
	position: absolute;
	inset: 0;
	-webkit-mask-image: var(--hero-mask-vertical);
	mask-image: var(--hero-mask-vertical);
}

/*
 * Crossfade: each photograph holds for six seconds and the loop lasts as long
 * as the set, which is where the 24s of four slides comes from. The -1s offset
 * makes the first one fully visible on first paint.
 *
 * The set is chosen in wp-admin (Settings → Quantum → Home) and may be one,
 * two, three or four photographs, so the template prints the count on the
 * container and the timing below follows it.
 *
 * Four keyframe blocks rather than one, because a percentage inside @keyframes
 * is measured against that animation's own duration: the same block read
 * against twelve seconds would show each slide for half as long and leave the
 * rest of the loop with nothing visible at all. What has to stay fixed are the
 * moments — 1.2s to fade in, held until 6s, gone by 7.2s — and each duration
 * writes those same moments as its own percentages.
 *
 * The four-slide timing is the default, declared without a [data-slides]
 * qualifier so markup that carries no count still behaves; two and three
 * override only the name and the duration below.
 */
.home-hero__slide {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: var(--hero-photo-x, center) 35%;
	opacity: 0;
}

/*
 * Nothing moves until main.js says so, and main.js only says so once it has
 * printed the pause button. WCAG 2.2.2 asks for a mechanism to stop motion that
 * starts on its own; a browser with no JavaScript would otherwise get the
 * motion and no mechanism, which is the one state this whole feature exists to
 * prevent. Without the class the first photograph simply sits there, which is
 * also what reduced-motion does below.
 */
.home-hero__slide:first-child {
	opacity: 1;
}

.home-hero__slides.is-playing .home-hero__slide {
	opacity: 0;
	animation: home-hero-fade-4 24s infinite;
	animation-delay: calc(var(--i, 0) * 6s - 1s);
}

/* Pressed: the loop holds wherever it is, rather than restarting from slide one. */
.home-hero__slides.is-paused .home-hero__slide {
	animation-play-state: paused;
}

/*
 * One photograph does not fade — there is nothing to fade to. It sits there,
 * which is the right answer for a single picture and also what the
 * reduced-motion rule below does with any number of them.
 */
.home-hero__slides[data-slides="1"] .home-hero__slide {
	opacity: 1;
	animation: none;
}

.home-hero__slides.is-playing[data-slides="2"] .home-hero__slide {
	animation-name: home-hero-fade-2;
	animation-duration: 12s;
}

.home-hero__slides.is-playing[data-slides="3"] .home-hero__slide {
	animation-name: home-hero-fade-3;
	animation-duration: 18s;
}

/*
 * The scale is the previous theme's effect, put back where it belongs. There it was
 * not a separate flourish: it WAS the slide change — each slide entered
 * oversize, landed, drifted, and left larger still (previous theme, main.css:285).
 * The rebuild kept the crossfade and dropped the drift, which left a dissolve
 * with no direction.
 *
 * Three percent across the visible window, not the previous theme's six: that circle was
 * 320px wide and this photograph is 900, so the same percentage would travel
 * three times the distance. Measured against the rendered box, 3% here moves
 * 27px, its 6% moved 19.
 *
 * Never below 1, so an object-fit: cover image can never uncover an edge. The
 * return leg from 30% to 100% happens while the slide is transparent.
 */
@keyframes home-hero-fade-4 {
	0% { opacity: 0; transform: scale(1.02); }
	5% { opacity: 1; transform: scale(1.025); }
	25% { opacity: 1; transform: scale(1.055); }
	30% { opacity: 0; transform: scale(1.06); }
	100% { opacity: 0; transform: scale(1.02); }
}

/* The same 1.2s / 6s / 7.2s, read against 18s. */
@keyframes home-hero-fade-3 {
	0% { opacity: 0; transform: scale(1.02); }
	6.667% { opacity: 1; transform: scale(1.025); }
	33.333% { opacity: 1; transform: scale(1.055); }
	40% { opacity: 0; transform: scale(1.06); }
	100% { opacity: 0; transform: scale(1.02); }
}

/* The same 1.2s / 6s / 7.2s, read against 12s. */
@keyframes home-hero-fade-2 {
	0% { opacity: 0; transform: scale(1.02); }
	10% { opacity: 1; transform: scale(1.025); }
	50% { opacity: 1; transform: scale(1.055); }
	60% { opacity: 0; transform: scale(1.06); }
	100% { opacity: 0; transform: scale(1.02); }
}

/*
 * The same closing beat the inner heroes get, and it belongs here most of all:
 * this note is the first sentence of the brand a visitor ever reads, and it
 * lands once the first slide has arrived instead of being there before it.
 *
 * Opacity only. .home-hero__script is the .script-note element itself, and that
 * element carries a rotate(-8deg) — animating transform here would flatten the
 * handwriting to horizontal.
 *
 * The carousel underneath keeps moving on its own; the two do not interfere,
 * because this one runs once and stops.
 */
.home-hero__script {
	animation: quantum-note-in 0.6s ease-out 0.55s both;
}

/*
 * Reduced motion has to match the specificity of the .is-playing rule above, or
 * it loses to it and stops working. main.js also refuses to start the slideshow
 * at all when the preference is set, so this is the belt to that braces — and
 * the button stays hidden there, because a control that pauses something that
 * is not moving is a control with nothing to do.
 */
@media (prefers-reduced-motion: reduce) {
	.home-hero__slides.is-playing .home-hero__slide { animation: none; opacity: 0; }
	.home-hero__slides.is-playing .home-hero__slide:first-child { opacity: 1; }
	.home-hero__script { animation: none; }
}

/*
 * The pause control. WCAG 2.2.2 asks for it; template-parts/home/hero.php says
 * why at length, including why prefers-reduced-motion does not answer it.
 *
 * 32px because that is what this theme gives an icon-only control — the same as
 * .modal__close, .pill-form__clear and the two controls in the top bar — and it
 * clears the 24x24 that SC 2.5.8 asks of a target with eight to spare.
 *
 * Two colours, not one, and the white ring is load-bearing. The photograph
 * underneath changes every six seconds and runs from nearly white to dark
 * green, measured at this exact corner: a lone white glyph reads 1.32:1 against
 * the first slide and a lone navy disc 1.27:1 against the second, both under
 * the 3:1 that SC 1.4.11 asks of a control's boundary. Together they cover all
 * four — the disc carries the edge at 3.49:1 where the photograph is pale, the
 * ring at 7.59, 4.11 and 5.27:1 where it is dark. It is the same arrangement,
 * for the same reason, as the distance pill on a location card and the
 * two-tone focus ring in main.css.
 */
.home-hero__pause {
	position: absolute;
	right: 16px;
	bottom: 16px;
	z-index: 2;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	padding: 0;
	color: #fff;
	cursor: pointer;
	background: rgb(15 31 51 / 0.55);
	border: 0;
	border-radius: 50%;
	box-shadow: 0 0 0 1px rgb(255 255 255 / 0.92);
	transition: background-color var(--transition);
	-webkit-backdrop-filter: blur(3px);
	backdrop-filter: blur(3px);
}

.home-hero__pause:hover {
	background: rgb(15 31 51 / 0.78);
}

/*
 * Hand the box-shadow back on focus.
 *
 * The global :focus-visible ring paints its white band with box-shadow, and so
 * does the hairline above — same specificity, and this stylesheet loads after
 * main.css, so the hairline would win and silently delete the band. That band
 * is what carries the indicator where the surface is too dark for the blue
 * outline, which over a photograph is most of the time. The band is a superset
 * of the hairline — 2px from the same edge instead of 1 — so restoring it loses
 * nothing. main.css documents the same trap at .mxchat-popular-question.
 */
.home-hero__pause:focus-visible {
	box-shadow: 0 0 0 2px var(--color-white);
}

.home-hero__pause-icon {
	display: inline-flex;
}

/*
 * One glyph at a time: the icon is the state a sighted visitor reads, and the
 * accessible name is the same statement in words. Keyed on a class rather than
 * aria-pressed because the W3C's carousel pattern specifies no state on this
 * control — hero.php says why.
 */
.home-hero__pause .home-hero__pause-icon--play,
.home-hero__pause.is-paused .home-hero__pause-icon--pause {
	display: none;
}

.home-hero__pause.is-paused .home-hero__pause-icon--play {
	display: inline-flex;
}

.home-hero__script {
	display: none;
}

.home-hero__inner {
	position: relative;
	z-index: 1;
	padding-bottom: var(--space-10);
}

.home-hero__title {
	font-size: clamp(2.2rem, 1.4rem + 2.6vw, 3.5rem);
	font-weight: 700;
	line-height: 1.08;
	color: var(--color-white);
	letter-spacing: -0.02em;
}

.home-hero__title .text-accent {
	color: var(--color-sky);
}

.home-hero__lead {
	margin-top: var(--space-4);
	font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.25rem);
	line-height: 1.45;
	color: rgb(255 255 255 / 0.92);
}

.home-hero__actions {
	margin-top: var(--space-6);
}

.hero-stats {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-5) var(--space-10);
	margin-top: var(--space-8);
}

.hero-stats__item {
	display: flex;
	gap: var(--space-3);
	align-items: flex-start;
}

.hero-stats__icon {
	color: var(--color-sky-strong);
}

.hero-stats__text {
	display: grid;
	gap: 0.35rem;
}

.hero-stats__value {
	font-family: var(--font-heading);
	font-size: 1.75rem;
	font-weight: 800;
	line-height: 1;
	color: var(--color-white);
}

.hero-stats__value--word {
	font-weight: 700;
}

.hero-stats__label {
	font-size: var(--fs-xs);
	line-height: 1.2;
	color: rgb(255 255 255 / 0.85);
}

/*
 * The row above keeps each icon beside its figure only where the box holds all
 * three on one line: 618px in English, 625 in Spanish. It does from a window of
 * 657px to 991, and again from about 1164, where the column beside the
 * photograph has grown back to it. Narrower, the row broke: "Thousands" alone
 * under the other two, or all three in a column at the left.
 *
 * There each figure stands over its label instead, centred, with the icon on
 * top (the way the payment options below are), and the three still make one
 * line. The switch is at the theme's own breakpoints, 768 and 1200, not at 657
 * and 1164: that leaves the row room for a longer label (95px to spare at 768
 * and 11 at 1200, in Spanish), and from 657 to 767, or 1164 to 1199, the
 * stacked figures read just as well.
 *
 * One column per figure (grid-auto-flow), not repeat(3): a figure the site has
 * no data for is not printed (quantum_hero_stats()), and the rest must still
 * line up. From 576 they sit together at the left, like the two buttons above
 * them, and end before those buttons do. Measured from 320 to 1920 in both
 * languages: one line everywhere.
 */
@media (max-width: 767.98px), (min-width: 992px) and (max-width: 1199.98px) {
	.hero-stats {
		display: grid;
		grid-auto-flow: column;
		justify-content: start;
	}

	.hero-stats__item {
		flex-direction: column;
		align-items: center;
		gap: var(--space-2);
		text-align: center;
	}

	.hero-stats__text {
		justify-items: center;
	}
}

/*
 * Phones: the buttons above stretch to the full width up to 575.98
 * (.button-group in main.css), and so do the figures, spread edge to edge. The
 * figure drops to 22px: at 24, "Thousands" ran 10px past the content at 320px.
 */
@media (max-width: 575.98px) {
	.hero-stats {
		justify-content: space-between;
		gap: var(--space-3);
	}

	.hero-stats__value {
		font-size: 1.375rem;
	}
}

@media (min-width: 992px) {
	/*
	 * 24px from the bottom here against 16 on phones: the same step the
	 * container's own gutter takes at this width, so the control sits on the
	 * theme's rhythm rather than on a number of its own.
	 *
	 * And the gutter itself from the photograph's right edge. While the
	 * photograph runs to the window that ends the control exactly where the page
	 * content ends, in line with the header's button above it; from 1400, where
	 * the photograph's edge is the content's, it keeps the control the same
	 * distance inside the photograph's corner. It was a fixed 24px: the gutter up
	 * to 1200px, and 8px past the content after.
	 */
	.home-hero__pause {
		right: var(--gutter);
		bottom: 24px;
	}

	.home-hero {
		display: block;
	}

	/*
	 * The slides keep their right edge in view, where the note's wall is, for
	 * the reason the inner heroes do: see --hero-photo-x in main.css. Here it
	 * mattered most from 992 to 1199, where this hero is 510-570px tall and
	 * cover drew the slide up to 1,011px wide in a 635-767px box.
	 */
	.home-hero:has(> .home-hero__script) {
		--hero-photo-x: right;
	}

	.home-hero__media {
		position: absolute;
		inset: 0 0 0 auto;
		width: 64%;
		height: auto;
	}

	/*
	 * The horizontal fade goes on the slides for the same reason the vertical one
	 * does higher up: a mask creates a stacking context, and while it sat on
	 * .home-hero__media it trapped the pause button's z-index inside that block.
	 * The block itself is z-index:auto against .home-hero__inner's z-index:1, so
	 * the text container won the hit test and the button could not be clicked
	 * where the two overlap — visible, and dead to the mouse.
	 *
	 * Masking the photograph, rather than laying a separate gradient over it,
	 * avoids the seam that second layer leaves on the blue panel.
	 */
	.home-hero__slides {
		-webkit-mask-image: var(--hero-mask-horizontal);
		mask-image: var(--hero-mask-horizontal);
	}

	/*
	 * Ends where the page content ends (+0.2em offsets the rotation overhang),
	 * and from 1400, where the photograph's edge is the content's, 1.5rem inside
	 * it (--hero-note-clearance in main.css).
	 */
	.home-hero__script {
		--swoosh-width: 2.85em;
		--swoosh-offset: 1.45em;
		--swoosh-gap: 0.2em;
		position: absolute;
		top: 14.5%;
		right: calc(var(--container-edge) + 0.2em + var(--hero-note-clearance));
		display: inline-flex;
		font-size: 1.5625rem;
		color: var(--color-navy-soft);
		filter: var(--script-glow);
	}

	/*
	 * The same breathing room as every other hero, which is why it comes from the
	 * same variable. It used to be 77px top and 77 bottom against the 36/32 of the
	 * other screens, and the padding only explained part of that: the rest came
	 * from a `min-height: 540px` inherited from the mockup, which with
	 * `align-items: center` split the surplus across both sides. With the minimum
	 * gone, the content decides the height, as it does everywhere else.
	 */
	.home-hero__inner {
		display: flex;
		align-items: center;
		padding-block: var(--hero-padding-block);
	}

	.home-hero__content {
		max-width: 56%;
	}
}

@media (min-width: 1400px) {
	.home-hero__content {
		max-width: 740px;
	}

	/* Stops at the content, square-cut, like the inner heroes' photograph: see .page-hero__media in main.css. */
	.home-hero__media {
		right: var(--hero-outside);
		width: calc(var(--hero-frame) * 0.64);
	}

	/*
	 * And the blue right of the photograph matches the blue left of the
	 * content, as on the inner heroes (main.css, the same rule): the light from
	 * the top-left corner brightens the left strip and never reached the right
	 * one, so the strip right of the content gets the same light, mirrored from
	 * the top-right corner. Its size is the left one's: 120vw is 120% of the
	 * hero but for the scrollbar, which is 20px out of some 3,000. Measured at
	 * 2560, the two strips are the same colour pixel for pixel.
	 */
	.home-hero:has(.home-hero__slide) {
		background:
			var(--home-hero-light-mirrored) right top / var(--hero-outside) 100% no-repeat,
			var(--home-hero-light),
			var(--home-hero-blue);
	}
}


/* Payment strip
   ========================================================================== */

.payment-strip {
	background: #f6f9fc;
	border-bottom: 1px solid var(--color-border);
}

.payment-strip__inner {
	display: grid;
	gap: var(--space-6);
	padding-block: var(--space-6);
}

.payment-strip__intro {
	display: flex;
	gap: var(--space-4);
	align-items: flex-start;
}

.payment-strip__intro-icon {
	color: var(--color-nav);
	stroke-width: 1.6;
}

.payment-strip__title {
	font-size: 1.15rem;
	color: var(--color-nav);
}

.payment-strip__text {
	max-width: 300px;
	margin-top: var(--space-2);
	font-size: var(--fs-xs);
	line-height: 1.4;
	color: var(--color-slate-blue);
}

.payment-strip__methods {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--space-5);
}

.payment-strip__method {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	align-items: center;
	font-family: var(--font-heading);
	font-size: var(--fs-sm);
	font-weight: 600;
	line-height: 1.3;
	color: var(--color-nav);
	text-align: center;
}

.payment-strip__method .icon {
	color: #0d1f69;
	stroke-width: 1.6;
}

.payment-strip__contact {
	font-size: 0.9375rem;
}

.payment-strip__contact p {
	margin-bottom: var(--space-2);
	color: var(--color-slate-blue);
}

@media (min-width: 768px) {
	.payment-strip__methods {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}

/*
 * Stacked, the three columns lose the rules that separate them across, and with them
 * the reason the middle one is centred while the text above and below is not. The
 * grouping comes back as space, not as a line: the benefits row on Careers already
 * settled that question for this theme — a divider is drawn only where the row is
 * actually a row, because stacked it is a stray mark. Wider gaps say the same thing
 * and add nothing to look at.
 */
@media (max-width: 1199.98px) {
	.payment-strip__inner {
		gap: var(--space-8);
	}
}

@media (min-width: 1200px) {
	.payment-strip__inner {
		grid-template-columns: auto minmax(0, 1fr) auto;
		align-items: stretch;
		gap: 0;
	}

	/*
	 * The other two columns are 92px tall and distribute their content inside it;
	 * this one is shorter, so stretched it sat against the top of the row while its
	 * neighbours read as centred. It keeps its own height and centres in the row.
	 */
	.payment-strip__intro {
		align-self: center;
	}

	.payment-strip__methods,
	.payment-strip__contact {
		min-height: 92px; /* mockup divider height, so the strip keeps its proportions */
		padding-left: var(--space-8);
		margin-left: var(--space-8);
		border-left: 1px solid #d9e2ec;
	}

	/* Content-sized columns with equal gaps, as in the mockup; keeps "& Out-of-Network" on one line. */
	.payment-strip__methods {
		grid-template-columns: repeat(4, auto);
		align-items: center;
		justify-content: space-between;
		gap: var(--space-6);
	}

	.payment-strip__contact {
		display: flex;
		flex-direction: column;
		justify-content: space-between;
	}

	/* Two lines in the narrow desktop column; on smaller screens the question uses the full width. */
	.payment-strip__contact p {
		max-width: 180px;
	}
}


/* Services & locations sections (shared rhythm)
   ========================================================================== */

.home-services,
.home-locations {
	padding-block: clamp(2.25rem, 1.8rem + 1.5vw, 3rem);
}

/* Desktop rhythm: the mockup's ~268px per section, plus a little air (cards here are narrower than in the mockup). */
@media (min-width: 992px) {
	.home-services,
	.home-locations {
		padding-block: 1.5rem 1.75rem;
	}

	:is(.home-services, .home-locations) .section-heading {
		margin-bottom: 1.25rem;
	}

	:is(.home-services, .home-locations) .section-heading__subtitle {
		margin-top: 0;
		line-height: 1.4;
	}
}

/* Home subtitles are slate-blue in its mockup (other screens use body gray). */
:is(.home-services, .home-locations) .section-heading__subtitle {
	color: var(--color-slate-blue);
}


/* Service tiles
   ========================================================================== */

/*
 * Up to ten tiles: two to a row on a phone and five from 992px, the shape of
 * the locations row below. Each row is as tall as its own tallest tile, and
 * the tiles in it stretch to match (a grid item's default), so a name or a
 * line that wraps — "Workers' Compensation", "Recover. Rebuild. Move
 * Forward." in a narrow column — evens out its own row and not the others.
 * Not every row at the tallest tile's height (grid-auto-rows: 1fr, tried
 * while the tiles grew to ten and dropped on 17 October 2026): at 480px one
 * line that wrapped left empty space under all ten tiles, 829px for a block
 * that 766 hold. There used to be a three-column step from 768px, which with
 * ten tiles leaves one alone on the last row.
 */
.service-tiles {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--space-4);
}

/* Compact tiles as in the mockup: large thin-line icon close to the top, content top-aligned. */
.service-tile {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	align-items: center;
	height: 100%;
	padding: 0.625rem 0.5rem;
	text-align: center;
	background: #f7fafd;
	border: 1px solid var(--color-border);
	border-radius: var(--radius);
}

.service-tile:hover {
	border-color: #cfdcf0;
}

/*
 * The tile is a link, and keeps the tile's colours; its parts set their own.
 * No underline on its name: the whole tile is the link, and it answers the
 * pointer by lifting (card-lift) and with its border, as the location tiles
 * below do. Keyboard focus keeps the site's focus ring.
 */
a.service-tile,
a.service-tile:hover {
	color: inherit;
}

.service-tile__icon {
	color: var(--color-link);
	stroke-width: 1.25;
}

.service-tile__title {
	font-size: 1.0625rem;
	font-weight: 600;
	color: var(--color-nav);
}

.service-tile__text {
	font-size: var(--fs-sm);
	line-height: 1.3;
	color: var(--color-slate-blue);
}

@media (min-width: 992px) {
	.service-tiles { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}


/* City tiles
   ========================================================================== */

/*
 * Two to a row on a phone and five from 992px. A last row that is not full
 * starts at the left, as the cards on the Locations page do: the tiles are a
 * list in the directory's order, read left to right, and a last one set in the
 * middle would stand out for nothing more than coming last.
 *
 * Every row is as tall as the tallest (grid-auto-rows: 1fr). Without it a name
 * that wraps to two lines — "Jamaica Estates" in a phone's column — made its
 * row taller than the others, and a column of five rows read uneven.
 */
.city-tiles {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	grid-auto-rows: 1fr;
	gap: var(--space-4);
}

.city-tile {
	position: relative;
	display: grid;
	grid-template-columns: 1fr auto;
	grid-template-rows: minmax(0, 1fr) auto; /* the photo absorbs any extra row height */
	align-items: center;
	overflow: hidden;
	font-family: var(--font-heading);
	font-size: 0.9375rem;
	font-weight: 600;
	line-height: 1.3;
	color: var(--color-nav);
	background: var(--color-white);
	border-radius: var(--radius-tile);
	box-shadow: var(--shadow-sm);
}

.city-tile:hover {
	color: var(--color-nav);
}

/*
 * The frame, not the photograph, is the grid item.
 *
 * Until 30 September 2026 the <img> itself sat in the first row with
 * `height: 100%`. Chrome and Firefox resolved that 100% against the row; WebKit
 * (Safari, and every browser on an iPhone) resolved it against the whole tile,
 * so the photograph ran down over the name and its arrow. Measured in Safari's
 * responsive mode at 393px: tile 144, photo 144, name starting at 104.
 *
 * A box inside a frame with a definite size is sized the same way everywhere:
 * the frame takes the row (its ratio gives the row its height, and
 * `align-self: stretch` lets it absorb extra height when a neighbour's name
 * wraps to two lines), and the photograph fills the frame absolutely — the
 * same construction the badges on the Locations cards already use.
 *
 * `justify-self: stretch` is not redundant. A grid item with an aspect-ratio
 * treats `normal` alignment as `start` (CSS Grid, "normal" for items with a
 * preferred aspect ratio), so without it the frame took its width from the
 * stretched height and ran 290px wide inside a 174px tile at 992px.
 */
.city-tile__media {
	position: relative;
	grid-column: 1 / -1;
	align-self: stretch;
	justify-self: stretch;
	aspect-ratio: 5 / 3;
}

.city-tile__image {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.city-tile__name {
	padding: 0.625rem 0.5rem 0.7rem 1.25rem;
}

.city-tile__arrow {
	margin-right: 1.2rem;
	color: var(--color-link);
	transition: transform var(--transition);
}

.city-tile:hover .city-tile__arrow {
	transform: translateX(3px);
}

@media (min-width: 992px) {
	.city-tiles {
		grid-template-columns: repeat(5, minmax(0, 1fr));
	}

	.city-tile__media {
		aspect-ratio: 9 / 4;
	}
}


/* Trust row
   ========================================================================== */

.trust-row__inner {
	display: grid;
	gap: var(--space-8);
	align-items: center;
	padding-block: var(--space-6);
}

/* Stars, then quote and attribution flowing as one paragraph with a hanging opening quote mark. */
.trust-row__quote {
	/*
	 * Centred while the row is stacked. Below 992px the three parts sit one
	 * under another, and the other two centre themselves — the values grid
	 * fills the width and the script note carries justify-self. The quote was
	 * the only one left hanging at the far left, which read as a mistake
	 * because it was one. The text inside stays left-aligned: a three-line
	 * quote centred line by line is harder to read than one that is not.
	 */
	justify-self: center;
	max-width: 19.5em; /* breaks after "back", as in the mockup */
	padding-left: 0.45em;
	font-size: 0.9375rem;
	line-height: 1.55;
	text-indent: -0.45em;
}

.trust-row__quote .stars {
	display: flex;
	gap: 4px;
	margin: 0 0 0.6rem -0.45em;
}

.trust-row__quote .stars .icon {
	width: 22px;
	height: 22px;
}

.trust-row__quote blockquote,
.trust-row__quote blockquote p,
.trust-row__quote figcaption {
	display: inline;
}

.trust-row__quote blockquote {
	font-style: italic;
	color: var(--color-navy-soft);
}

.trust-row__quote figcaption {
	margin-left: 0.3em;
	/*
	 * Never split. The caption runs inline after the quote, so without this a
	 * name that does not fit in what is left of the line breaks in half —
	 * "Sample Patient" on one line and "A." alone on the next, which is how
	 * this block grew to four lines. Kept whole, it moves down entire and the
	 * quote's own character budget (template-parts/home/trust-row.php) is what
	 * keeps the pair inside three lines.
	 */
	white-space: nowrap;
	font-size: var(--fs-sm);
	color: var(--color-slate-blue);
}

.trust-row__values {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--space-4);
}

.trust-row__value {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	align-items: center;
	font-size: 0.9375rem;
	line-height: 1.3;
	color: var(--color-slate-blue);
	text-align: center;
}

.trust-row__value .icon {
	color: var(--color-link);
	stroke-width: 1.5;
}

.trust-row__script {
	--swoosh-width: 2.4em;
	--swoosh-offset: 1.35em;
	--swoosh-gap: 0.15em;
	justify-self: center;
	font-size: 1.6875rem;
	color: var(--color-navy-soft);
}

@media (min-width: 992px) {
	/* Column proportions measured on the mockup (quote · values · tagline). */
	.trust-row__inner {
		grid-template-columns: minmax(0, 343fr) minmax(0, 725fr) minmax(0, 212fr);
		align-items: center;
		gap: 0;
	}

	/* Content-sized values with equal space around them; dividers span the full row. */
	.trust-row__values {
		display: flex;
		align-self: stretch;
		align-items: center;
		justify-content: space-evenly;
		padding-inline: var(--space-3);
		border-inline: 1px solid var(--color-border);
	}

	.trust-row__script {
		justify-self: end;
	}

	/* Three columns again: the quote goes back to the start of its own. */
	.trust-row__quote {
		justify-self: start;
	}

	/*
	 * No quote yet: two columns, not three with a hole at the end. The quote is
	 * the one part of this row that waits on the practice collecting a
	 * testimonial with written consent, so "not yet" is a state it will sit in
	 * for a while — and with the three-column track still in force the values
	 * were squeezed into the narrow first column while the empty third took the
	 * space. The opening border goes too: with nothing to its left it read as a
	 * rule floating at the edge of the page.
	 */
	.trust-row--no-quote .trust-row__inner {
		/*
		 * `1fr` next to `212fr` is a 1:212 ratio, not "the rest and 212": fr units
		 * are proportional to each other, so the values column came out 6px wide
		 * and the note took the other 1249. The note is sized by its own content
		 * and the values take what is left.
		 */
		grid-template-columns: minmax(0, 1fr) auto;

		/*
		 * And a gap: with three columns the note sat at the end of a 212fr track
		 * with room to spare, so nothing separated it from the divider. Sized to
		 * its own content it landed flush against that line.
		 */
		column-gap: var(--space-8);
	}

	.trust-row--no-quote .trust-row__values {
		padding-inline-start: 0;
		border-inline-start: 0;
	}
}

@media (min-width: 1200px) {
	.trust-row__value {
		white-space: nowrap;
	}
}
