Component library
Back to catalog

Markets served

Where a business works, set as one typeset statement: a split header (heading; sentence and an optional action) over a heavy rule, then the supplied markets, regions or areas running across the full width as display type sized by count. Lists only what is supplied, in order; no map, chips, rows, numbers or claims. A summary presentation for a mention on another page.

coveragemarkets servedservice areatypographiceditoriallightlocal service

Open preview in a new tab

Use this component

Three ways to get Markets served into one of your own projects. The first two carry the component's files with them, so nothing has to fetch this page.

Start here

Placement prompt

The whole thing: what to do, where it goes, what must not change, and every one of the component's 1 file appended underneath with the path each belongs at. Paste it into Claude Code inside the destination project — it fetches nothing and needs nothing else.

Read it first — the files are added underneath when you copy
Add Markets served from my Astro Component Library to this Astro project.

Library page, for reference only:
https://astro.baysixmedia.com/components/markets-served/

Place it in:
[ENTER PAGE, FILE, OR ROUTE]

Position:
[ENTER WHERE IT SHOULD APPEAR]

Every file you need is appended below, each fenced with the path it belongs at. Write them there, relative to the project root. Do not import anything from the deployed library at runtime, and do not fetch the library page — the files below are the source of truth.

Adapt its demo content, links, colors, typography, and images to this project through documented props where possible. Preserve its responsive behavior, accessibility, interaction logic, reduced-motion behavior, and support for multiple instances. Avoid changing unrelated project code.

Test it at desktop, tablet, and mobile widths. Run the project's available check and build commands. Report the files changed and any differences from the library version. Do not commit or deploy.

Install kit

The 1 file this component needs and nothing else, each fenced with the path it belongs at, followed by what the library's own verification covered and what it did not. No instructions attached — for placing it yourself, or handing it to something that has its own.

Read it first
Install kit: "Markets served"
Library page: https://astro.baysixmedia.com/components/markets-served/
Files: 1 required, 1 supporting

Write each block below to the path named in its header, relative to the project root. A block marked (required) is one the component does not work without; (supporting) is documentation. Nothing here needs downloading except a block that says so in as many words.

===== FILE (required): src/components/MarketsServed.astro =====
---
/**
 * MarketsServed (candidate, Step 38.2 — owner-directed original, role `coverage`)
 *
 * Where a business works, set as a typographic statement. A header — eyebrow over heading on one
 * side, a sentence over one optional action on the other, the two columns sharing a top and a bottom
 * line — sits over one heavy rule; below it the supplied markets run across the full measure as
 * display type, one after another like a line of set text, separated by a light accent stroke. The
 * statement is the section's subject: no map, no pins, no cards, no photograph, no ruled index rows.
 * An optional quiet note sits under a hairline at the end.
 *
 * Scale follows the list so the block always reads as finished: 1–3 markets are set very large,
 * 4–7 large, 8–12 medium, 13+ small. `presentation="summary"` (a homepage mention of a footprint
 * that has its own page) sets everything one step smaller and tighter; "feature" is the default.
 *
 * Truth rules. It shows only the markets passed in `markets`, in the order given and exactly as
 * written — never sorted, merged, grouped, abbreviated, counted or ranked (no numerals). A market is
 * a place the business says it serves: nothing here draws or implies an office, terminal, depot,
 * yard, lane, route, radius, schedule, capacity or coverage guarantee. No markets, no section.
 * Heading, intro, note and action render only when supplied; the action only with a safe href.
 *
 * Responsive (container queries on the section's own width): below 760px one column in reading
 * order — heading, sentence, rule, markets, the action, then the note. From 760px the header sits
 * above the rule (stacked, then split heading | copy from 960px). Each market is one unit at every
 * width: lines break between markets, separators sit only between markets on the same line, and only
 * a name longer than the whole line wraps inside itself, with tighter leading than between markets.
 *
 * Reads, never declares: --msv-bg, --msv-text, --msv-text-muted, --msv-brand, --msv-brand-text,
 * --msv-border, --msv-family, --msv-display, --msv-grid-max, --msv-grid-gutter, --msv-heading-size.
 * No script.
 */
export interface MarketsServedAction {
	label: string;
	href: string;
}

interface Props {
	/** Section heading. */
	heading: string;
	headingLevel?: "h2" | "h3";
	/** Short label above the heading. */
	eyebrow?: string;
	/** One or two sentences beside the heading. */
	intro?: string;
	/** The markets, regions, cities or areas the business serves — exactly as supplied, in order. */
	markets?: readonly string[];
	/** One quiet factual line under the statement (e.g. that the list is as supplied). */
	note?: string;
	/** One optional action. */
	cta?: MarketsServedAction | null;
	/** "feature" (default) for a page about the footprint; "summary" for a shorter mention elsewhere. */
	presentation?: "feature" | "summary";
	fontStylesheet?: string;
	class?: string;
	id?: string;
}

const {
	heading,
	headingLevel = "h2",
	eyebrow = "",
	intro = "",
	markets = [],
	note = "",
	cta = null,
	presentation = "feature",
	fontStylesheet = "https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,300..800;1,62..125,300..800&display=swap",
	class: className,
	id,
} = Astro.props;

const list = markets.map((m) => (typeof m === "string" ? m.trim() : "")).filter(Boolean);
const safeHref = (href: string | undefined) => {
	const h = (href ?? "").trim();
	return /^(https?:\/\/|mailto:|tel:|#|\/(?!\/))/i.test(h) ? h : null;
};
const action = cta && cta.label?.trim() && safeHref(cta.href) ? { label: cta.label.trim(), href: safeHref(cta.href)! } : null;
const steps = ["xl", "lg", "md", "sm"] as const;
const base = list.length <= 3 ? 0 : list.length <= 7 ? 1 : list.length <= 12 ? 2 : 3;
const scale = steps[Math.min(3, base + (presentation === "summary" ? 1 : 0))];
const Heading = headingLevel;
const headingId = `${id ?? "msv"}-heading`;
---

{list.length > 0 && heading?.trim() && (
	<section class:list={["msv", className]} id={id} data-presentation={presentation} aria-labelledby={headingId}>
		{fontStylesheet && <link rel="stylesheet" href={fontStylesheet} />}
		<div class="msv-inner">
			<header class="msv-head">
				<div class="msv-title">
					{eyebrow.trim() && <p class="msv-eyebrow">{eyebrow.trim()}</p>}
					<Heading class="msv-heading" id={headingId}>{heading.trim()}</Heading>
				</div>
				{(intro.trim() || action) && (
					<div class="msv-copy">
						{intro.trim() && <p class="msv-intro">{intro.trim()}</p>}
						{action && <a class="msv-action" href={action.href}>{action.label}</a>}
					</div>
				)}
			</header>
			<div class="msv-statement">
				<ul class="msv-list" data-scale={scale} role="list">
					{list.map((m) => <li class="msv-market"><span class="msv-name">{m}</span></li>)}
				</ul>
			</div>
			{note.trim() && <p class="msv-note">{note.trim()}</p>}
		</div>
	</section>
)}

<style>
	.msv {
		--msv-surface: var(--msv-bg, #f4f4f1);
		--msv-ink: var(--msv-text, #101214);
		--msv-soft: var(--msv-text-muted, #3b3f46);
		--msv-accent: var(--msv-brand, #2d43c4);
		--msv-accent-ink: var(--msv-brand-text, #ffffff);
		--msv-line: var(--msv-border, #d3d4cf);
		--msv-font: var(--msv-family, "Archivo", ui-sans-serif, system-ui, sans-serif);
		--msv-font-display: var(--msv-display, "Archivo", ui-sans-serif, system-ui, sans-serif);
		container-type: inline-size;
		background: var(--msv-surface);
		color: var(--msv-ink);
		font-family: var(--msv-font);
	}
	/*
	 * Below 760px the section reads top to bottom as one column — heading, sentence, the markets, the
	 * action, then the note — so the visitor sees where the business works before being asked to act.
	 * The header's boxes step aside (display: contents) and `order` sets that sequence.
	 */
	.msv-inner {
		box-sizing: border-box;
		display: flex;
		flex-direction: column;
		align-items: flex-start;
		max-width: var(--msv-grid-max, 1232px);
		margin: 0 auto;
		padding: 56px 20px 60px;
	}
	.msv[data-presentation="summary"] .msv-inner {
		padding-block: 44px 48px;
	}
	.msv-head,
	.msv-copy {
		display: contents;
	}
	.msv-title { order: 1; }
	.msv-intro { order: 2; }
	.msv-statement { order: 3; }
	.msv-action { order: 4; }
	.msv-note { order: 5; }

	.msv-title {
		display: flex;
		flex-direction: column;
		align-items: flex-start;
		gap: 14px;
	}
	.msv-eyebrow {
		margin: 0;
		font-size: 15px;
		font-weight: 600;
		line-height: 1.3;
		color: var(--msv-accent);
	}
	.msv-heading {
		margin: auto 0 0;
		font-family: var(--msv-font-display);
		font-size: var(--msv-heading-size, clamp(36px, 6cqi, 64px));
		font-weight: 680;
		font-stretch: 86%;
		line-height: 1;
		letter-spacing: -0.02em;
		text-wrap: balance;
	}
	.msv[data-presentation="summary"] .msv-heading {
		font-size: var(--msv-heading-size, clamp(30px, 3.8cqi, 48px));
	}
	.msv-intro {
		margin: 18px 0 0;
		max-width: 44ch;
		font-size: 17px;
		line-height: 1.55;
		color: var(--msv-soft);
		text-wrap: pretty;
	}
	.msv-action {
		display: inline-flex;
		align-items: center;
		min-height: 48px;
		margin-top: 28px;
		padding: 0 24px;
		background: var(--msv-ink);
		color: var(--msv-surface);
		font-size: 16px;
		font-weight: 600;
		text-decoration: none;
		transition: background-color 160ms ease, color 160ms ease;
	}
	.msv-action:hover {
		background: var(--msv-accent);
		color: var(--msv-accent-ink);
	}
	.msv-action:focus-visible {
		outline: 3px solid var(--msv-accent);
		outline-offset: 3px;
	}

	/*
	 * The statement: the markets as set type across the full measure, under the one heavy rule.
	 * Each market carries its separator in front of it; the list starts one separator-width to the left
	 * and the statement clips that margin, so the separator of whichever market begins a line is cut
	 * away. Strokes only ever sit between two markets on the same line — none hangs at a line end.
	 */
	.msv-statement {
		align-self: stretch;
		margin-top: 28px;
		padding-top: 32px;
		border-top: 3px solid var(--msv-ink);
		overflow-x: clip;
	}
	.msv-list {
		--msv-sep: 0.8em;
		margin: 0 0 0 calc(-1 * var(--msv-sep));
		padding: 0;
		list-style: none;
		font-family: var(--msv-font-display);
		font-weight: 470;
		font-stretch: 92%;
		letter-spacing: -0.025em;
		line-height: 1.12;
		text-wrap: pretty;
	}
	/* Each market is one unit: lines break between markets, and only a name longer than the line wraps inside itself. */
	.msv-market {
		display: inline-flex;
		align-items: baseline;
		max-width: 100%;
		margin-block: 0.07em;
		vertical-align: baseline;
	}
	.msv-market::before {
		content: "/" / "";
		flex: none;
		width: var(--msv-sep);
		padding-right: 0.02em;
		text-align: center;
		font-weight: 300;
		font-stretch: 100%;
		color: var(--msv-accent);
	}
	/* A name that must wrap keeps tighter leading than the space between markets, so it still reads as one place. */
	.msv-name {
		min-width: 0;
		line-height: 0.98;
		overflow-wrap: anywhere;
	}
	.msv-list[data-scale="xl"] { font-size: 44px; }
	.msv-list[data-scale="lg"] { font-size: 32px; }
	.msv-list[data-scale="md"] { font-size: 26px; }
	.msv-list[data-scale="sm"] { font-size: 22px; }

	.msv-note {
		align-self: stretch;
		margin: 28px 0 0;
		padding-top: 16px;
		border-top: 1px solid var(--msv-line);
		font-size: 15px;
		line-height: 1.5;
		color: var(--msv-soft);
	}

	@container (min-width: 760px) {
		/* From 760px: the header sits above the rule in reading order (stacked until 960px), note last. */
		.msv-inner {
			display: block;
			padding: 88px 40px 80px;
		}
		.msv[data-presentation="summary"] .msv-inner {
			padding-block: 64px 60px;
		}
		.msv-title,
		.msv-intro,
		.msv-statement,
		.msv-note,
		.msv-action {
			order: 0;
		}
		.msv-head {
			display: grid;
			row-gap: 22px;
			padding-bottom: 36px;
		}
		.msv-copy {
			display: flex;
			flex-direction: column;
			align-items: flex-start;
			gap: 24px;
		}
		.msv-intro {
			margin: 0;
			max-width: 52ch;
		}
		.msv-action {
			margin-top: 0;
		}
		.msv-statement {
			margin-top: 0;
			padding-top: 40px;
		}
		/* Market type grows with the section but stays clearly under the heading at tablet widths. */
		.msv-list[data-scale="xl"] { font-size: clamp(52px, calc(10cqi - 24px), 120px); }
		.msv-list[data-scale="lg"] { font-size: clamp(36px, calc(7.2cqi - 36px), 68px); }
		.msv-list[data-scale="md"] { font-size: clamp(30px, calc(5.6cqi - 26px), 56px); }
		.msv-list[data-scale="sm"] { font-size: clamp(26px, calc(4.2cqi - 18px), 44px); }
		.msv-note {
			margin-top: 32px;
		}
	}
	@container (min-width: 960px) {
		/* Header beside header — eyebrow | sentence on the top line, heading | action on the bottom line. */
		.msv-head {
			grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
			column-gap: 56px;
			align-items: stretch;
		}
		.msv-copy {
			gap: 18px;
		}
		.msv-intro {
			max-width: 44ch;
		}
		.msv-action {
			margin-top: auto;
		}
	}
	@container (min-width: 1100px) {
		.msv-inner {
			padding-inline: var(--msv-grid-gutter, 48px);
		}
	}

	@media (prefers-reduced-motion: reduce) {
		.msv-action {
			transition: none;
		}
	}
	@media (forced-colors: active) {
		.msv-statement {
			border-top-color: CanvasText;
		}
		.msv-action {
			border: 2px solid ButtonText;
		}
		.msv-market::before {
			color: CanvasText;
		}
	}
</style>

===== END src/components/MarketsServed.astro =====

===== FILE (supporting): src/components/MarketsServed.md =====
# Markets served

Where a business works, set as one typeset statement: a split header (heading; sentence and an optional action) over a heavy rule, then the supplied markets, regions or areas running across the full width as display type sized by count. Lists only what is supplied, in order; no map, chips, rows, numbers or claims. A summary presentation for a mention on another page.

## Integration

- A section heading (h2 by default).
- No markets, no section. Markets render in the order and wording supplied; the component adds no map, pin, lane, route, count or claim.
- Type scales with the count: 2–3 very large, 4–7 large, 8–12 medium. `presentation="summary"` sets it one step smaller for a mention on a page that is not about the footprint.
- Header splits heading | sentence from 760px of the section's own width (container queries); stacked below.
- The action renders only from `cta` with a safe href.
- Loads Archivo (variable width) from Google Fonts by default. Pass fontStylesheet="" on a site that loads its own faces (via --msv-family / --msv-display).

## Provenance

Staged as candidate `markets-served` (Step 28) and admitted through the candidate pipeline. Source type: original. References (direction only): none. Quality history: quality/candidates/records/markets-served.json.

===== END src/components/MarketsServed.md =====

--- VERIFIED IN THE COMPONENT LIBRARY ---
Enrolled for verification but never run.
No verification run has been recorded.
No checks have passed yet.
No usable source fingerprint, so these results cannot be tied to the files below.

--- NOT PROVEN ---
- ClientRouter: not applicable — this component ships no script.

--- WHAT THIS DOES NOT CERTIFY ---
Verification was performed on the unmodified component, in an isolated fixture, in the
library. It says nothing about this project's CSS, routes, layout or data, and nothing
about the component once you adapt it. A verified component is a good starting point,
not a guarantee about the installation you are about to build.

--- TEST IN THIS PROJECT AFTER INSTALLING OR CUSTOMISING ---
- Horizontal overflow at 1440, 1280, 1024, 834, 390 and 320px.
- Keyboard operation end to end, including visible focus.
- The no-JavaScript render.
- prefers-reduced-motion: reduce.
- Two instances on one page, if this project renders more than one.
- If this project uses <ClientRouter />: teardown and reinitialisation across a real navigation.

Component reference

A fragment for a request you write yourself, e.g. “I want to add [paste] to Section 3 of my homepage.” It names the component, links its page, and fixes what must not change — the design build and its effects — while leaving branding and content open. It does not carry the code.

Read it first
“Markets served” from my Astro Component Library:
https://astro.baysixmedia.com/components/markets-served/

Use the existing library component as the implementation source. Preserve its design structure, layout, proportions, spacing system, responsive behavior, visual effects, animations, transitions, hover states, interactions, and accessibility.

The copy, colors, typography, images, and other content may be adapted to match the destination website. Do not redesign, simplify, or reinterpret the component’s underlying design build or effects.

Component readiness

Judged on recorded evidence, not on how it looks in the frame above. A description of a component is not a result.

Interactivity
Static
Profile
core only
Installation files
1 required + 1 supporting
Verified
Never
Client navigation
Not applicable — ships no script
Source fingerprint
No fingerprint recorded
Production ready
Not yet

Not yet verified

Enrolled for verification, but never run. Silence is reported as silence rather than assumed to be fine.

Open the verification fixture

src/components/library/MarketsServed.astro

one fileNo imports, no companion files, no packages. Copy MarketsServed.astro into any Astro project's components folder and render it.

---
/**
 * MarketsServed (candidate, Step 38.2 — owner-directed original, role `coverage`)
 *
 * Where a business works, set as a typographic statement. A header — eyebrow over heading on one
 * side, a sentence over one optional action on the other, the two columns sharing a top and a bottom
 * line — sits over one heavy rule; below it the supplied markets run across the full measure as
 * display type, one after another like a line of set text, separated by a light accent stroke. The
 * statement is the section's subject: no map, no pins, no cards, no photograph, no ruled index rows.
 * An optional quiet note sits under a hairline at the end.
 *
 * Scale follows the list so the block always reads as finished: 1–3 markets are set very large,
 * 4–7 large, 8–12 medium, 13+ small. `presentation="summary"` (a homepage mention of a footprint
 * that has its own page) sets everything one step smaller and tighter; "feature" is the default.
 *
 * Truth rules. It shows only the markets passed in `markets`, in the order given and exactly as
 * written — never sorted, merged, grouped, abbreviated, counted or ranked (no numerals). A market is
 * a place the business says it serves: nothing here draws or implies an office, terminal, depot,
 * yard, lane, route, radius, schedule, capacity or coverage guarantee. No markets, no section.
 * Heading, intro, note and action render only when supplied; the action only with a safe href.
 *
 * Responsive (container queries on the section's own width): below 760px one column in reading
 * order — heading, sentence, rule, markets, the action, then the note. From 760px the header sits
 * above the rule (stacked, then split heading | copy from 960px). Each market is one unit at every
 * width: lines break between markets, separators sit only between markets on the same line, and only
 * a name longer than the whole line wraps inside itself, with tighter leading than between markets.
 *
 * Reads, never declares: --msv-bg, --msv-text, --msv-text-muted, --msv-brand, --msv-brand-text,
 * --msv-border, --msv-family, --msv-display, --msv-grid-max, --msv-grid-gutter, --msv-heading-size.
 * No script.
 */
export interface MarketsServedAction {
	label: string;
	href: string;
}

interface Props {
	/** Section heading. */
	heading: string;
	headingLevel?: "h2" | "h3";
	/** Short label above the heading. */
	eyebrow?: string;
	/** One or two sentences beside the heading. */
	intro?: string;
	/** The markets, regions, cities or areas the business serves — exactly as supplied, in order. */
	markets?: readonly string[];
	/** One quiet factual line under the statement (e.g. that the list is as supplied). */
	note?: string;
	/** One optional action. */
	cta?: MarketsServedAction | null;
	/** "feature" (default) for a page about the footprint; "summary" for a shorter mention elsewhere. */
	presentation?: "feature" | "summary";
	fontStylesheet?: string;
	class?: string;
	id?: string;
}

const {
	heading,
	headingLevel = "h2",
	eyebrow = "",
	intro = "",
	markets = [],
	note = "",
	cta = null,
	presentation = "feature",
	fontStylesheet = "https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,300..800;1,62..125,300..800&display=swap",
	class: className,
	id,
} = Astro.props;

const list = markets.map((m) => (typeof m === "string" ? m.trim() : "")).filter(Boolean);
const safeHref = (href: string | undefined) => {
	const h = (href ?? "").trim();
	return /^(https?:\/\/|mailto:|tel:|#|\/(?!\/))/i.test(h) ? h : null;
};
const action = cta && cta.label?.trim() && safeHref(cta.href) ? { label: cta.label.trim(), href: safeHref(cta.href)! } : null;
const steps = ["xl", "lg", "md", "sm"] as const;
const base = list.length <= 3 ? 0 : list.length <= 7 ? 1 : list.length <= 12 ? 2 : 3;
const scale = steps[Math.min(3, base + (presentation === "summary" ? 1 : 0))];
const Heading = headingLevel;
const headingId = `${id ?? "msv"}-heading`;
---

{list.length > 0 && heading?.trim() && (
	<section class:list={["msv", className]} id={id} data-presentation={presentation} aria-labelledby={headingId}>
		{fontStylesheet && <link rel="stylesheet" href={fontStylesheet} />}
		<div class="msv-inner">
			<header class="msv-head">
				<div class="msv-title">
					{eyebrow.trim() && <p class="msv-eyebrow">{eyebrow.trim()}</p>}
					<Heading class="msv-heading" id={headingId}>{heading.trim()}</Heading>
				</div>
				{(intro.trim() || action) && (
					<div class="msv-copy">
						{intro.trim() && <p class="msv-intro">{intro.trim()}</p>}
						{action && <a class="msv-action" href={action.href}>{action.label}</a>}
					</div>
				)}
			</header>
			<div class="msv-statement">
				<ul class="msv-list" data-scale={scale} role="list">
					{list.map((m) => <li class="msv-market"><span class="msv-name">{m}</span></li>)}
				</ul>
			</div>
			{note.trim() && <p class="msv-note">{note.trim()}</p>}
		</div>
	</section>
)}

<style>
	.msv {
		--msv-surface: var(--msv-bg, #f4f4f1);
		--msv-ink: var(--msv-text, #101214);
		--msv-soft: var(--msv-text-muted, #3b3f46);
		--msv-accent: var(--msv-brand, #2d43c4);
		--msv-accent-ink: var(--msv-brand-text, #ffffff);
		--msv-line: var(--msv-border, #d3d4cf);
		--msv-font: var(--msv-family, "Archivo", ui-sans-serif, system-ui, sans-serif);
		--msv-font-display: var(--msv-display, "Archivo", ui-sans-serif, system-ui, sans-serif);
		container-type: inline-size;
		background: var(--msv-surface);
		color: var(--msv-ink);
		font-family: var(--msv-font);
	}
	/*
	 * Below 760px the section reads top to bottom as one column — heading, sentence, the markets, the
	 * action, then the note — so the visitor sees where the business works before being asked to act.
	 * The header's boxes step aside (display: contents) and `order` sets that sequence.
	 */
	.msv-inner {
		box-sizing: border-box;
		display: flex;
		flex-direction: column;
		align-items: flex-start;
		max-width: var(--msv-grid-max, 1232px);
		margin: 0 auto;
		padding: 56px 20px 60px;
	}
	.msv[data-presentation="summary"] .msv-inner {
		padding-block: 44px 48px;
	}
	.msv-head,
	.msv-copy {
		display: contents;
	}
	.msv-title { order: 1; }
	.msv-intro { order: 2; }
	.msv-statement { order: 3; }
	.msv-action { order: 4; }
	.msv-note { order: 5; }

	.msv-title {
		display: flex;
		flex-direction: column;
		align-items: flex-start;
		gap: 14px;
	}
	.msv-eyebrow {
		margin: 0;
		font-size: 15px;
		font-weight: 600;
		line-height: 1.3;
		color: var(--msv-accent);
	}
	.msv-heading {
		margin: auto 0 0;
		font-family: var(--msv-font-display);
		font-size: var(--msv-heading-size, clamp(36px, 6cqi, 64px));
		font-weight: 680;
		font-stretch: 86%;
		line-height: 1;
		letter-spacing: -0.02em;
		text-wrap: balance;
	}
	.msv[data-presentation="summary"] .msv-heading {
		font-size: var(--msv-heading-size, clamp(30px, 3.8cqi, 48px));
	}
	.msv-intro {
		margin: 18px 0 0;
		max-width: 44ch;
		font-size: 17px;
		line-height: 1.55;
		color: var(--msv-soft);
		text-wrap: pretty;
	}
	.msv-action {
		display: inline-flex;
		align-items: center;
		min-height: 48px;
		margin-top: 28px;
		padding: 0 24px;
		background: var(--msv-ink);
		color: var(--msv-surface);
		font-size: 16px;
		font-weight: 600;
		text-decoration: none;
		transition: background-color 160ms ease, color 160ms ease;
	}
	.msv-action:hover {
		background: var(--msv-accent);
		color: var(--msv-accent-ink);
	}
	.msv-action:focus-visible {
		outline: 3px solid var(--msv-accent);
		outline-offset: 3px;
	}

	/*
	 * The statement: the markets as set type across the full measure, under the one heavy rule.
	 * Each market carries its separator in front of it; the list starts one separator-width to the left
	 * and the statement clips that margin, so the separator of whichever market begins a line is cut
	 * away. Strokes only ever sit between two markets on the same line — none hangs at a line end.
	 */
	.msv-statement {
		align-self: stretch;
		margin-top: 28px;
		padding-top: 32px;
		border-top: 3px solid var(--msv-ink);
		overflow-x: clip;
	}
	.msv-list {
		--msv-sep: 0.8em;
		margin: 0 0 0 calc(-1 * var(--msv-sep));
		padding: 0;
		list-style: none;
		font-family: var(--msv-font-display);
		font-weight: 470;
		font-stretch: 92%;
		letter-spacing: -0.025em;
		line-height: 1.12;
		text-wrap: pretty;
	}
	/* Each market is one unit: lines break between markets, and only a name longer than the line wraps inside itself. */
	.msv-market {
		display: inline-flex;
		align-items: baseline;
		max-width: 100%;
		margin-block: 0.07em;
		vertical-align: baseline;
	}
	.msv-market::before {
		content: "/" / "";
		flex: none;
		width: var(--msv-sep);
		padding-right: 0.02em;
		text-align: center;
		font-weight: 300;
		font-stretch: 100%;
		color: var(--msv-accent);
	}
	/* A name that must wrap keeps tighter leading than the space between markets, so it still reads as one place. */
	.msv-name {
		min-width: 0;
		line-height: 0.98;
		overflow-wrap: anywhere;
	}
	.msv-list[data-scale="xl"] { font-size: 44px; }
	.msv-list[data-scale="lg"] { font-size: 32px; }
	.msv-list[data-scale="md"] { font-size: 26px; }
	.msv-list[data-scale="sm"] { font-size: 22px; }

	.msv-note {
		align-self: stretch;
		margin: 28px 0 0;
		padding-top: 16px;
		border-top: 1px solid var(--msv-line);
		font-size: 15px;
		line-height: 1.5;
		color: var(--msv-soft);
	}

	@container (min-width: 760px) {
		/* From 760px: the header sits above the rule in reading order (stacked until 960px), note last. */
		.msv-inner {
			display: block;
			padding: 88px 40px 80px;
		}
		.msv[data-presentation="summary"] .msv-inner {
			padding-block: 64px 60px;
		}
		.msv-title,
		.msv-intro,
		.msv-statement,
		.msv-note,
		.msv-action {
			order: 0;
		}
		.msv-head {
			display: grid;
			row-gap: 22px;
			padding-bottom: 36px;
		}
		.msv-copy {
			display: flex;
			flex-direction: column;
			align-items: flex-start;
			gap: 24px;
		}
		.msv-intro {
			margin: 0;
			max-width: 52ch;
		}
		.msv-action {
			margin-top: 0;
		}
		.msv-statement {
			margin-top: 0;
			padding-top: 40px;
		}
		/* Market type grows with the section but stays clearly under the heading at tablet widths. */
		.msv-list[data-scale="xl"] { font-size: clamp(52px, calc(10cqi - 24px), 120px); }
		.msv-list[data-scale="lg"] { font-size: clamp(36px, calc(7.2cqi - 36px), 68px); }
		.msv-list[data-scale="md"] { font-size: clamp(30px, calc(5.6cqi - 26px), 56px); }
		.msv-list[data-scale="sm"] { font-size: clamp(26px, calc(4.2cqi - 18px), 44px); }
		.msv-note {
			margin-top: 32px;
		}
	}
	@container (min-width: 960px) {
		/* Header beside header — eyebrow | sentence on the top line, heading | action on the bottom line. */
		.msv-head {
			grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
			column-gap: 56px;
			align-items: stretch;
		}
		.msv-copy {
			gap: 18px;
		}
		.msv-intro {
			max-width: 44ch;
		}
		.msv-action {
			margin-top: auto;
		}
	}
	@container (min-width: 1100px) {
		.msv-inner {
			padding-inline: var(--msv-grid-gutter, 48px);
		}
	}

	@media (prefers-reduced-motion: reduce) {
		.msv-action {
			transition: none;
		}
	}
	@media (forced-colors: active) {
		.msv-statement {
			border-top-color: CanvasText;
		}
		.msv-action {
			border: 2px solid ButtonText;
		}
		.msv-market::before {
			color: CanvasText;
		}
	}
</style>