Component library
Back to catalog

Featured quote reviews

Reviews that need only the words and the name: the first set large as a lead quote with its attribution under it, the rest in a ruled grid of plain quotes. Each review can link to where it was published and carry its date; a supplied aggregate rating sits beside the heading. No photos, no cards, no carousel. Nothing is filled in; with no reviews it renders nothing.

testimonialsreviewsquotestext onlyno photo neededratingslight

Open preview in a new tab

Use this component

Three ways to get Featured quote reviews 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 Featured quote reviews from my Astro Component Library to this Astro project.

Library page, for reference only:
https://astro.baysixmedia.com/components/featured-quote-reviews/

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: "Featured quote reviews"
Library page: https://astro.baysixmedia.com/components/featured-quote-reviews/
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/FeaturedQuoteReviews.astro =====
---
/**
 * FeaturedQuoteReviews
 *
 * Reviews that need nothing but the words and the name. The first review is
 * set large as the section's lead quote, its attribution standing beside it on
 * wide screens; the rest follow in a ruled grid of plain quotes — no cards, no
 * photos, no carousel, nothing hidden. Quotes in the grid start on one line
 * whether or not a review carries a rating, and an odd last review spans the
 * row at two columns instead of leaving a hole. Built for
 * a business whose proof is what customers wrote, not a wall of faces.
 *
 * Nothing is added to a review. Its attribution is exactly what is passed —
 * a name, then any role, company or location given — and a rating appears
 * only when a real number from 0 to 5 is supplied. No stars by default, no
 * review count, no platform, no "verified". With no reviews the component
 * renders nothing at all: a reviews heading over no reviews is a claim.
 *
 * Step 40: provenance, all optional. A review may carry where it was left
 * (`source`), a link to the published review (`sourceUrl`, http(s) only) and
 * when it was left (`date`, shown as written). A supplied aggregate
 * (`overallRating`: a value, plus any count, platform and profile link) sits
 * beside the heading as one proof line. None of it is ever filled in.
 *
 * No script. Layout follows the section's own width (container queries).
 * Reads --fqr-* tokens from any ancestor, with fallbacks.
 */

export interface FeaturedQuoteReview {
	/** The customer's words, as written. */
	quote: string;
	/** Who wrote it, as they agreed to be named: "Maria L.", "The Okafor family". */
	name: string;
	role?: string;
	company?: string;
	location?: string;
	/** The rating they gave, 0–5. Omit and no stars are drawn. */
	rating?: number;
	/** Where it was left, only if true: "Google", "Yelp". */
	source?: string;
	/** Step 40: the published review's own http(s) URL, only if supplied. */
	sourceUrl?: string;
	/** Step 40: when it was left, as written ("March 2026", "2026-03-14"). */
	date?: string;
}

/** Step 40: the business's aggregate rating, exactly as supplied. */
export interface FeaturedQuoteOverallRating {
	value: number;
	count?: number;
	source?: string;
	href?: string;
}

export interface FeaturedQuoteReviewsProps {
	heading: string;
	headingLevel?: "h2" | "h3";
	eyebrow?: string;
	intro?: string;
	reviews?: readonly FeaturedQuoteReview[];
	/** Step 40: the aggregate rating beside the heading; only a real 0–5 value renders. */
	overallRating?: FeaturedQuoteOverallRating | null;
	/** Set the first review large. Off, every review sits in the grid. */
	featureFirst?: boolean;
	/** A link under the reviews, e.g. to a full reviews page. */
	cta?: { label: string; href: string } | null;
	fontStylesheet?: string;
	class?: string;
	id?: string;
}

interface Props extends FeaturedQuoteReviewsProps {}

const {
	heading,
	headingLevel = "h2",
	eyebrow = "",
	intro = "",
	reviews = [],
	overallRating = null,
	featureFirst = true,
	cta = null,
	fontStylesheet = "https://fonts.googleapis.com/css2?family=Manrope:wght@500;600;700;800&display=swap",
	class: className,
	id,
} = Astro.props;

const SAFE = /^(?:https?:|mailto:|tel:|[#/.?])/i;
const safeHref = (href: string) => (SAFE.test(href.trim()) ? href.trim() : "#");

/* A rating is drawn only for a real number in range: never assumed, never five by default. */
const ratingOf = (value: unknown) =>
	typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 5 ? value : null;

const text = (value: unknown) => (typeof value === "string" ? value.trim() : "");
/* A provenance link must point at a real web page: http(s) only, never an anchor or a script. */
const webHref = (value: unknown) => (typeof value === "string" && /^https?:\/\/\S+$/i.test(value.trim()) ? value.trim() : "");
/* A date is shown exactly as written; only an ISO date is also made machine-readable. */
const isoDate = (value: string) => (/^\d{4}-\d{2}(-\d{2})?$/.test(value) ? value : undefined);

const items = (reviews ?? [])
	.filter((r) => r && text(r.quote) && text(r.name))
	.map((r) => ({
		quote: text(r.quote),
		name: text(r.name),
		meta: [text(r.role), text(r.company), text(r.location)].filter(Boolean).join(" · "),
		source: text(r.source),
		sourceUrl: webHref(r.sourceUrl),
		date: text(r.date),
		rating: ratingOf(r.rating),
	}));

/* The aggregate renders only for a real value; its count, platform and link only when passed. */
const overallValue = overallRating ? ratingOf(overallRating.value) : null;
const overall =
	overallRating && overallValue !== null
		? {
				value: overallValue,
				count: typeof overallRating.count === "number" && Number.isFinite(overallRating.count) && overallRating.count > 0 ? Math.round(overallRating.count) : null,
				source: text(overallRating.source),
				href: webHref(overallRating.href),
			}
		: null;
const overallBasis = overall
	? [overall.count !== null ? `${overall.count.toLocaleString("en-US")} ${overall.count === 1 ? "review" : "reviews"}` : "", overall.source ? `on ${overall.source}` : ""].filter(Boolean).join(" ")
	: "";

type Item = (typeof items)[number];
/* Where and when a review was left, as one line: the platform (a link when its URL is given), then the date. */
const provenanceOf = (r: Item) => ({ label: r.source || (r.sourceUrl ? "Original review" : ""), href: r.sourceUrl, date: r.date });

const lead = featureFirst && items.length > 0 ? items[0] : null;
const rest = lead ? items.slice(1) : items;
/* A long lead quote steps down a size so it stays a quote, not a wall. */
const leadLong = lead ? lead.quote.length > 220 : false;
/* When any grid review has a rating, the rest keep its line so quotes align. */
const gridRated = rest.some((r) => r.rating !== null);
const Heading = headingLevel;
---

{
	items.length > 0 && (
		<>
			{fontStylesheet && <link rel="stylesheet" href={fontStylesheet} />}
			<section class:list={["fqr", className]} id={id}>
				<div class="fqr-inner">
					<header class:list={["fqr-head", { "fqr-head--rated": overall }]}>
						<div class="fqr-head-copy">
							{eyebrow && <p class="fqr-eyebrow">{eyebrow}</p>}
							<Heading class="fqr-title">{heading}</Heading>
							{intro && <p class="fqr-intro">{intro}</p>}
						</div>
						{overall && (
							<p class="fqr-overall">
								<span class="fqr-overall-value" aria-hidden="true">
									{overall.value.toFixed(1)}
								</span>
								<span class="fqr-overall-detail">
									<span class="fqr-stars" role="img" aria-label={`Rated ${overall.value} out of 5${overallBasis ? ` from ${overallBasis}` : ""}`}>
										<span class="fqr-stars-fill" style={`width: ${(overall.value / 5) * 100}%`} />
									</span>
									{overallBasis &&
										(overall.href ? (
											<a class="fqr-overall-basis fqr-link" href={overall.href} rel="noopener">
												{overallBasis}
												<span class="fqr-arrow" aria-hidden="true">
													↗
												</span>
											</a>
										) : (
											<span class="fqr-overall-basis" aria-hidden="true">
												{overallBasis}
											</span>
										))}
								</span>
							</p>
						)}
					</header>

					{lead && (
						<figure class:list={["fqr-lead", { "fqr-lead--long": leadLong }]}>
							<span class="fqr-mark" aria-hidden="true">
								“
							</span>
							<blockquote class="fqr-lead-quote">
								<p>{lead.quote}</p>
							</blockquote>
							<figcaption class="fqr-by">
								<span class="fqr-name">{lead.name}</span>
								{lead.meta && <span class="fqr-meta">{lead.meta}</span>}
								{(lead.rating !== null || lead.source || lead.sourceUrl || lead.date) && (
									<span class="fqr-proof">
										{lead.rating !== null && (
											<span class="fqr-stars" role="img" aria-label={`Rated ${lead.rating} out of 5`}>
												<span class="fqr-stars-fill" style={`width: ${(lead.rating / 5) * 100}%`} />
											</span>
										)}
										{(() => {
											const p = provenanceOf(lead);
											return (
												<span class="fqr-prov">
													{p.label &&
														(p.href ? (
															<a class="fqr-source fqr-link" href={p.href} rel="noopener">
																{p.label}
																<span class="fqr-arrow" aria-hidden="true">
																	↗
																</span>
																<span class="fqr-sr"> (original review by {lead.name})</span>
															</a>
														) : (
															<span class="fqr-source">{p.label}</span>
														))}
													{p.date && (
														<time class="fqr-date" datetime={isoDate(p.date)}>
															{p.date}
														</time>
													)}
												</span>
											);
										})()}
									</span>
								)}
							</figcaption>
						</figure>
					)}

					{rest.length > 0 && (
						<ul class:list={["fqr-grid", { "fqr-grid--rated": gridRated, "fqr-grid--odd": rest.length % 2 === 1, "fqr-grid--pairs": rest.length === 2 || rest.length === 4 }]} role="list">
							{rest.map((r) => (
								<li class="fqr-item">
									<figure>
										{r.rating !== null && (
											<span class="fqr-stars" role="img" aria-label={`Rated ${r.rating} out of 5`}>
												<span class="fqr-stars-fill" style={`width: ${(r.rating / 5) * 100}%`} />
											</span>
										)}
										<blockquote class="fqr-quote">
											<p>{r.quote}</p>
										</blockquote>
										<figcaption class="fqr-by">
											<span class="fqr-name">{r.name}</span>
											{r.meta && <span class="fqr-meta">{r.meta}</span>}
											{(r.source || r.sourceUrl || r.date) &&
												(() => {
													const p = provenanceOf(r);
													return (
														<span class="fqr-prov">
															{p.label &&
																(p.href ? (
																	<a class="fqr-source fqr-link" href={p.href} rel="noopener">
																		{p.label}
																		<span class="fqr-arrow" aria-hidden="true">
																			↗
																		</span>
																		<span class="fqr-sr"> (original review by {r.name})</span>
																	</a>
																) : (
																	<span class="fqr-source">{p.label}</span>
																))}
															{p.date && (
																<time class="fqr-date" datetime={isoDate(p.date)}>
																	{p.date}
																</time>
															)}
														</span>
													);
												})()}
										</figcaption>
									</figure>
								</li>
							))}
						</ul>
					)}

					{cta && (
						<p class="fqr-cta-row">
							<a class="fqr-cta" href={safeHref(cta.href)}>
								{cta.label}
							</a>
						</p>
					)}
				</div>
			</section>
		</>
	)
}

<style>
	.fqr {
		--fqr-surface: var(--fqr-bg, #ffffff);
		--fqr-ink: var(--fqr-text, #0f1b2d);
		--fqr-muted: var(--fqr-text-muted, #475569);
		--fqr-accent: var(--fqr-brand, #1d4ed8);
		--fqr-star: var(--fqr-star-color, #b45309);
		--fqr-rule: var(--fqr-border, #d9dee7);
		--fqr-font: var(--fqr-family, Manrope, ui-sans-serif, system-ui, sans-serif);

		container-type: inline-size;
		background: var(--fqr-surface);
		color: var(--fqr-ink);
		font-family: var(--fqr-font);
	}

	.fqr *,
	.fqr *::before,
	.fqr *::after {
		box-sizing: border-box;
	}

	.fqr-inner {
		max-width: 1200px;
		margin: 0 auto;
		padding: 56px 20px;
	}

	.fqr-head {
		max-width: 680px;
	}

	.fqr-head--rated {
		max-width: none;
		display: grid;
		gap: 28px;
	}

	.fqr-head-copy {
		max-width: 680px;
		min-width: 0;
	}

	.fqr-eyebrow {
		margin: 0 0 12px;
		color: var(--fqr-muted);
		font: 700 15px/1.4 var(--fqr-font);
	}

	/* Step 40: the supplied aggregate — one figure, its stars, and where it comes from. */
	.fqr-overall {
		display: flex;
		align-items: center;
		gap: 16px;
		margin: 0;
		padding-top: 20px;
		border-top: 1px solid var(--fqr-rule);
		min-width: 0;
	}

	.fqr-overall-value {
		font: 800 56px/0.9 var(--fqr-font);
		letter-spacing: -0.04em;
		font-variant-numeric: tabular-nums;
	}

	.fqr-overall-detail {
		display: flex;
		flex-direction: column;
		gap: 8px;
		min-width: 0;
	}

	.fqr-overall-basis {
		color: var(--fqr-muted);
		font: 600 15px/1.4 var(--fqr-font);
		overflow-wrap: anywhere;
	}

	/* Provenance links: a web page the review or rating was read from. */
	.fqr-link {
		display: inline-flex;
		align-items: center;
		gap: 4px;
		/* A comfortable target on touch screens without breaking the meta line's rhythm. */
		min-height: 32px;
		color: var(--fqr-ink);
		text-decoration: underline;
		text-decoration-color: var(--fqr-rule);
		text-decoration-thickness: 1px;
		text-underline-offset: 4px;
		transition: text-decoration-color 0.15s ease;
	}

	.fqr-link:hover {
		text-decoration-color: var(--fqr-accent);
	}

	.fqr-link:focus-visible {
		outline: 3px solid var(--fqr-accent);
		outline-offset: 3px;
		border-radius: 2px;
	}

	/* An inline-block glyph takes no underline from its link. */
	.fqr-arrow {
		display: inline-block;
		font-size: 0.9em;
		line-height: 1;
	}

	.fqr-sr {
		position: absolute;
		width: 1px;
		height: 1px;
		margin: -1px;
		padding: 0;
		overflow: hidden;
		clip: rect(0 0 0 0);
		white-space: nowrap;
		border: 0;
	}

	.fqr-prov {
		display: inline-flex;
		flex-wrap: wrap;
		align-items: baseline;
		gap: 2px 10px;
		min-width: 0;
	}

	.fqr-date {
		color: var(--fqr-muted);
		font: 500 14px/1.5 var(--fqr-font);
	}

	/* Platform, then date, joined by a quiet point. */
	.fqr-source + .fqr-date::before {
		content: "·";
		margin-right: 10px;
		color: var(--fqr-rule);
	}

	.fqr-item .fqr-prov {
		margin-top: 4px;
	}

	.fqr-title {
		margin: 0;
		font: 800 clamp(30px, 6.4cqi, 44px) / 1.1 var(--fqr-font);
		letter-spacing: -0.025em;
		text-wrap: balance;
		overflow-wrap: anywhere;
	}

	.fqr-intro {
		margin: 16px 0 0;
		color: var(--fqr-muted);
		font: 500 17px/1.6 var(--fqr-font);
		overflow-wrap: anywhere;
	}

	figure {
		margin: 0;
	}

	blockquote {
		margin: 0;
	}

	blockquote p {
		margin: 0;
	}

	.fqr-lead {
		position: relative;
		margin-top: 40px;
		padding-left: 0;
	}

	.fqr-mark {
		display: block;
		height: 0.55em;
		color: var(--fqr-accent);
		font: 800 88px/1 Georgia, "Times New Roman", serif;
	}

	.fqr-lead-quote {
		max-width: 30ch;
		font: 700 clamp(24px, 4.6cqi, 40px) / 1.26 var(--fqr-font);
		letter-spacing: -0.015em;
		text-wrap: pretty;
		overflow-wrap: anywhere;
	}

	.fqr-lead--long .fqr-lead-quote {
		max-width: 46ch;
		font-size: clamp(20px, 3.2cqi, 27px);
		line-height: 1.45;
	}

	.fqr-by {
		display: flex;
		flex-direction: column;
		gap: 2px;
		margin-top: 16px;
		min-width: 0;
	}

	.fqr-lead .fqr-by {
		margin-top: 24px;
	}

	.fqr-name {
		font: 800 16px/1.4 var(--fqr-font);
		overflow-wrap: anywhere;
	}

	.fqr-meta,
	.fqr-source {
		color: var(--fqr-muted);
		font: 500 14px/1.5 var(--fqr-font);
		overflow-wrap: anywhere;
	}

	.fqr-proof {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: 4px 12px;
		margin-top: 8px;
	}

	/* Five outlines, filled to the rating from the left. */
	.fqr-stars {
		position: relative;
		display: inline-block;
		width: 92px;
		height: 18px;
		flex: none;
		background: var(--fqr-rule);
		-webkit-mask: var(--fqr-star-mask) 0 0 / 18.4px 18px repeat-x;
		mask: var(--fqr-star-mask) 0 0 / 18.4px 18px repeat-x;
		--fqr-star-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m12 2.5 2.9 6 6.6.9-4.8 4.6 1.2 6.5L12 17.4l-5.9 3.1 1.2-6.5-4.8-4.6 6.6-.9z'/%3E%3C/svg%3E");
	}

	.fqr-stars-fill {
		position: absolute;
		inset: 0 auto 0 0;
		background: var(--fqr-star);
	}

	.fqr-item .fqr-stars {
		display: block;
		margin-bottom: 12px;
	}


	.fqr-grid {
		display: grid;
		grid-template-columns: 1fr;
		gap: 0;
		margin: 40px 0 0;
		padding: 0;
		list-style: none;
	}

	.fqr-item {
		min-width: 0;
		padding: 24px 0;
		border-top: 2px solid var(--fqr-ink);
	}

	.fqr-quote {
		max-width: 46ch;
		font: 500 17px/1.65 var(--fqr-font);
		overflow-wrap: anywhere;
	}

	/* The close: a hairline across the section, the action sitting on it. */
	.fqr-cta-row {
		margin: 32px 0 0;
		padding-top: 20px;
		border-top: 1px solid var(--fqr-rule);
	}

	.fqr-cta {
		display: inline-flex;
		align-items: baseline;
		gap: 10px;
		min-height: 44px;
		padding: 10px 0;
		color: var(--fqr-ink);
		font: 700 16px/1.4 var(--fqr-font);
		text-decoration: underline;
		text-decoration-color: var(--fqr-accent);
		text-decoration-thickness: 2px;
		text-underline-offset: 6px;
		transition: text-underline-offset 0.18s ease;
		overflow-wrap: anywhere;
	}

	.fqr-cta:hover {
		text-underline-offset: 3px;
	}

	.fqr-cta:focus-visible {
		outline: 3px solid var(--fqr-accent);
		outline-offset: 3px;
	}

	@container (min-width: 700px) {
		.fqr-inner {
			padding: 72px 32px;
		}

		.fqr-grid {
			grid-template-columns: repeat(2, minmax(0, 1fr));
			gap: 0 40px;
		}

		/* Two columns and an odd count: the last review takes the row. */
		.fqr-grid--odd .fqr-item:last-child {
			grid-column: 1 / -1;
		}

		.fqr-grid--odd .fqr-item:last-child .fqr-quote {
			max-width: 60ch;
		}

		/* Side by side, rated and unrated reviews start their quotes on one line (one column needs no gap). */
		.fqr-grid--rated .fqr-item figure:not(:has(.fqr-stars)) {
			padding-top: 30px;
		}
	}

	@container (min-width: 1000px) {
		/* Step 39.2: --fqr-grid-max / --fqr-grid-gutter put the content on a site grid; the fallbacks are the original 1200 / 40. */
		.fqr-inner {
			padding: 96px 0;
			max-width: var(--fqr-grid-max, 1200px);
			padding-inline: var(--fqr-grid-gutter, 40px);
		}

		/* Step 40: the attribution sits directly under the lead quote, on its left edge, not across the page. */
		.fqr-lead {
			margin-top: 56px;
			padding-left: 76px;
		}

		.fqr-lead-quote {
			max-width: 34ch;
			font-size: clamp(30px, 3.4cqi, 44px);
		}

		/* Name and place, then the proof on its own line: two quiet lines, not one busy one. */
		.fqr-lead .fqr-by {
			margin: 32px 0 0;
			padding-left: 20px;
			border-left: 3px solid var(--fqr-accent);
		}

		.fqr-lead .fqr-proof {
			margin-top: 6px;
		}

		/* The aggregate stands beside the heading, on its baseline, once there is room for both. */
		.fqr-head--rated {
			grid-template-columns: minmax(0, 1fr) auto;
			align-items: end;
			column-gap: 56px;
		}

		.fqr-overall {
			padding: 0 0 4px 28px;
			border-top: 0;
			border-left: 1px solid var(--fqr-rule);
		}

		/* Two or four grid reviews sit as pairs instead of leaving a hole in a row of three. */
		.fqr-grid.fqr-grid--pairs {
			grid-template-columns: repeat(2, minmax(0, 1fr));
		}

		.fqr-grid--odd .fqr-item:last-child {
			grid-column: auto;
		}

		.fqr-mark {
			position: absolute;
			top: 0;
			left: 0;
			height: auto;
			font-size: 112px;
			line-height: 0.8;
		}

		.fqr-grid {
			grid-template-columns: repeat(3, minmax(0, 1fr));
			margin-top: 64px;
		}
	}

	@media (forced-colors: active) {
		.fqr-stars {
			forced-color-adjust: none;
			background: GrayText;
		}

		.fqr-stars-fill {
			background: CanvasText;
		}
	}
</style>

===== END src/components/FeaturedQuoteReviews.astro =====

===== FILE (supporting): src/components/FeaturedQuoteReviews.md =====
# Featured quote reviews

Reviews that need only the words and the name. The first review is set large
as the section's lead quote, with its attribution directly under it; the rest follow in a ruled grid of plain quotes — no cards, no
photos, no carousel, nothing hidden. Grid quotes start on one line whether or
not a review carries a rating, and an odd last review spans the row at two
columns. Built for a business whose
proof is what its customers wrote: a plumber, a childcare centre, a law
office, any local or professional service.

Catalog page: `/components/featured-quote-reviews`

## Files required

- **`FeaturedQuoteReviews.astro`** — the whole component. No script, no images.
- `FeaturedQuoteReviews.md` — this file.

## Basic usage

```astro
<FeaturedQuoteReviews
  eyebrow="Reviews"
  heading="What our customers say"
  reviews={[
    { quote: "They found the leak without opening half the wall.", name: "Maria L.", location: "San Mateo", rating: 5 },
    { quote: "On time, tidy, and the price was the price.", name: "James R." },
  ]}
  cta={{ label: "Read more reviews", href: "/reviews" }}
/>
```

## Props

| Prop | Type | Default | What it does |
| :--- | :--- | :--- | :--- |
| `heading` | `string` | **required** | The section heading. |
| `headingLevel` | `"h2" \| "h3"` | `"h2"` | |
| `eyebrow` | `string?` | `""` | Short line above the heading. |
| `intro` | `string?` | `""` | A sentence under the heading. |
| `reviews` | `FeaturedQuoteReview[]?` | `[]` | See below. None — nothing renders. |
| `overallRating` | `{ value, count?, source?, href? } | null` | `null` | The business's aggregate rating beside the heading. Only a real 0–5 `value` renders. |
| `featureFirst` | `boolean?` | `true` | Set the first review large. `false` puts every review in the grid. |
| `cta` | `{ label, href } \| null` | `null` | A text link under the reviews. |
| `fontStylesheet` | `string?` | Manrope | `""` skips it. |
| `class`, `id` | | | Root attributes. |

Each review: `quote` and `name` (both required — a review missing either is
dropped), then optional `role`, `company`, `location`, `rating`, `source`,
`sourceUrl` (the published review's http(s) URL) and `date` (as written).

## Trust data

- **No default reviews.** With none, the component renders nothing — not even
  its heading. A reviews section over no reviews would be a claim.
- **Attribution is exactly what you pass.** The name, then role, company and
  location joined with `·`, each only if given. Nothing like "Verified
  customer", "Homeowner" or a town is ever added.
- **Ratings only when given.** Stars appear only for a `rating` that is a
  number from 0 to 5, filled to that exact value (4.5 draws four and a half)
  and labelled "Rated 4.5 out of 5" for screen readers. A missing, string or
  out-of-range rating draws nothing. There is no overall rating, review count
  or platform unless you put it in the copy yourself.
- `source` ("Google", "Yelp") is printed as passed, and only if passed.
- **Provenance (Step 40).** With a `sourceUrl` the source becomes a link to
  the published review (http(s) only; anything else is dropped), named for
  screen readers as the original review by that customer. A URL with no
  `source` reads "Original review". `date` is shown exactly as written; an
  ISO date (`2026-03` or `2026-03-14`) is also put in a `<time datetime>`.
- **Aggregate rating (Step 40).** `overallRating` draws one figure, its stars
  and, only if passed, the count and platform ("212 reviews on Google"),
  linked to `href` when given. It is never computed from the reviews shown
  and never copied into a review.

## Layout

| Supplied | Result |
| :--- | :--- |
| One review | The lead quote alone. |
| Two or more | Lead quote, then the rest in a ruled grid. |
| `featureFirst={false}` | Every review in the grid. |

The lead quote steps down a size past about 220 characters so a long review
stays readable.

## Responsive behaviour

- Grid: one column, two from 768px, three from 1024px.
- The lead's quotation mark sits above the quote on small screens and hangs
  in the margin from 1024px.
- Long names, quotes and attributions wrap anywhere rather than overflow.

## Motion

None.

## Accessibility

- Each review is a `<figure>` with a `<blockquote>` and a `<figcaption>`.
- The grid is a list. The decorative quotation mark is `aria-hidden`.
- Stars are one `role="img"` with a text label.
- Links show a 3px focus outline in the brand colour. The closing link is
  at least 44px tall.
- Under forced colours the stars use system colours.

## Tokens

`--fqr-bg`, `--fqr-text`, `--fqr-text-muted`, `--fqr-brand`,
`--fqr-star-color`, `--fqr-border`, `--fqr-family` — set on any ancestor to
recolour it.

## Selection

Roles `testimonial` (and the `social-proof` umbrella, by convention). No
market: quotes and names suit any business. Professional and minimal; grid,
no media, light; no motion; supporting pressure (the optional link). It
requires `testimonials` — real ones — and nothing else: no portraits, photos,
logos or ratings.

===== END src/components/FeaturedQuoteReviews.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
“Featured quote reviews” from my Astro Component Library:
https://astro.baysixmedia.com/components/featured-quote-reviews/

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/FeaturedQuoteReviews.astro

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

---
/**
 * FeaturedQuoteReviews
 *
 * Reviews that need nothing but the words and the name. The first review is
 * set large as the section's lead quote, its attribution standing beside it on
 * wide screens; the rest follow in a ruled grid of plain quotes — no cards, no
 * photos, no carousel, nothing hidden. Quotes in the grid start on one line
 * whether or not a review carries a rating, and an odd last review spans the
 * row at two columns instead of leaving a hole. Built for
 * a business whose proof is what customers wrote, not a wall of faces.
 *
 * Nothing is added to a review. Its attribution is exactly what is passed —
 * a name, then any role, company or location given — and a rating appears
 * only when a real number from 0 to 5 is supplied. No stars by default, no
 * review count, no platform, no "verified". With no reviews the component
 * renders nothing at all: a reviews heading over no reviews is a claim.
 *
 * Step 40: provenance, all optional. A review may carry where it was left
 * (`source`), a link to the published review (`sourceUrl`, http(s) only) and
 * when it was left (`date`, shown as written). A supplied aggregate
 * (`overallRating`: a value, plus any count, platform and profile link) sits
 * beside the heading as one proof line. None of it is ever filled in.
 *
 * No script. Layout follows the section's own width (container queries).
 * Reads --fqr-* tokens from any ancestor, with fallbacks.
 */

export interface FeaturedQuoteReview {
	/** The customer's words, as written. */
	quote: string;
	/** Who wrote it, as they agreed to be named: "Maria L.", "The Okafor family". */
	name: string;
	role?: string;
	company?: string;
	location?: string;
	/** The rating they gave, 0–5. Omit and no stars are drawn. */
	rating?: number;
	/** Where it was left, only if true: "Google", "Yelp". */
	source?: string;
	/** Step 40: the published review's own http(s) URL, only if supplied. */
	sourceUrl?: string;
	/** Step 40: when it was left, as written ("March 2026", "2026-03-14"). */
	date?: string;
}

/** Step 40: the business's aggregate rating, exactly as supplied. */
export interface FeaturedQuoteOverallRating {
	value: number;
	count?: number;
	source?: string;
	href?: string;
}

export interface FeaturedQuoteReviewsProps {
	heading: string;
	headingLevel?: "h2" | "h3";
	eyebrow?: string;
	intro?: string;
	reviews?: readonly FeaturedQuoteReview[];
	/** Step 40: the aggregate rating beside the heading; only a real 0–5 value renders. */
	overallRating?: FeaturedQuoteOverallRating | null;
	/** Set the first review large. Off, every review sits in the grid. */
	featureFirst?: boolean;
	/** A link under the reviews, e.g. to a full reviews page. */
	cta?: { label: string; href: string } | null;
	fontStylesheet?: string;
	class?: string;
	id?: string;
}

interface Props extends FeaturedQuoteReviewsProps {}

const {
	heading,
	headingLevel = "h2",
	eyebrow = "",
	intro = "",
	reviews = [],
	overallRating = null,
	featureFirst = true,
	cta = null,
	fontStylesheet = "https://fonts.googleapis.com/css2?family=Manrope:wght@500;600;700;800&display=swap",
	class: className,
	id,
} = Astro.props;

const SAFE = /^(?:https?:|mailto:|tel:|[#/.?])/i;
const safeHref = (href: string) => (SAFE.test(href.trim()) ? href.trim() : "#");

/* A rating is drawn only for a real number in range: never assumed, never five by default. */
const ratingOf = (value: unknown) =>
	typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 5 ? value : null;

const text = (value: unknown) => (typeof value === "string" ? value.trim() : "");
/* A provenance link must point at a real web page: http(s) only, never an anchor or a script. */
const webHref = (value: unknown) => (typeof value === "string" && /^https?:\/\/\S+$/i.test(value.trim()) ? value.trim() : "");
/* A date is shown exactly as written; only an ISO date is also made machine-readable. */
const isoDate = (value: string) => (/^\d{4}-\d{2}(-\d{2})?$/.test(value) ? value : undefined);

const items = (reviews ?? [])
	.filter((r) => r && text(r.quote) && text(r.name))
	.map((r) => ({
		quote: text(r.quote),
		name: text(r.name),
		meta: [text(r.role), text(r.company), text(r.location)].filter(Boolean).join(" · "),
		source: text(r.source),
		sourceUrl: webHref(r.sourceUrl),
		date: text(r.date),
		rating: ratingOf(r.rating),
	}));

/* The aggregate renders only for a real value; its count, platform and link only when passed. */
const overallValue = overallRating ? ratingOf(overallRating.value) : null;
const overall =
	overallRating && overallValue !== null
		? {
				value: overallValue,
				count: typeof overallRating.count === "number" && Number.isFinite(overallRating.count) && overallRating.count > 0 ? Math.round(overallRating.count) : null,
				source: text(overallRating.source),
				href: webHref(overallRating.href),
			}
		: null;
const overallBasis = overall
	? [overall.count !== null ? `${overall.count.toLocaleString("en-US")} ${overall.count === 1 ? "review" : "reviews"}` : "", overall.source ? `on ${overall.source}` : ""].filter(Boolean).join(" ")
	: "";

type Item = (typeof items)[number];
/* Where and when a review was left, as one line: the platform (a link when its URL is given), then the date. */
const provenanceOf = (r: Item) => ({ label: r.source || (r.sourceUrl ? "Original review" : ""), href: r.sourceUrl, date: r.date });

const lead = featureFirst && items.length > 0 ? items[0] : null;
const rest = lead ? items.slice(1) : items;
/* A long lead quote steps down a size so it stays a quote, not a wall. */
const leadLong = lead ? lead.quote.length > 220 : false;
/* When any grid review has a rating, the rest keep its line so quotes align. */
const gridRated = rest.some((r) => r.rating !== null);
const Heading = headingLevel;
---

{
	items.length > 0 && (
		<>
			{fontStylesheet && <link rel="stylesheet" href={fontStylesheet} />}
			<section class:list={["fqr", className]} id={id}>
				<div class="fqr-inner">
					<header class:list={["fqr-head", { "fqr-head--rated": overall }]}>
						<div class="fqr-head-copy">
							{eyebrow && <p class="fqr-eyebrow">{eyebrow}</p>}
							<Heading class="fqr-title">{heading}</Heading>
							{intro && <p class="fqr-intro">{intro}</p>}
						</div>
						{overall && (
							<p class="fqr-overall">
								<span class="fqr-overall-value" aria-hidden="true">
									{overall.value.toFixed(1)}
								</span>
								<span class="fqr-overall-detail">
									<span class="fqr-stars" role="img" aria-label={`Rated ${overall.value} out of 5${overallBasis ? ` from ${overallBasis}` : ""}`}>
										<span class="fqr-stars-fill" style={`width: ${(overall.value / 5) * 100}%`} />
									</span>
									{overallBasis &&
										(overall.href ? (
											<a class="fqr-overall-basis fqr-link" href={overall.href} rel="noopener">
												{overallBasis}
												<span class="fqr-arrow" aria-hidden="true">
													↗
												</span>
											</a>
										) : (
											<span class="fqr-overall-basis" aria-hidden="true">
												{overallBasis}
											</span>
										))}
								</span>
							</p>
						)}
					</header>

					{lead && (
						<figure class:list={["fqr-lead", { "fqr-lead--long": leadLong }]}>
							<span class="fqr-mark" aria-hidden="true">
								“
							</span>
							<blockquote class="fqr-lead-quote">
								<p>{lead.quote}</p>
							</blockquote>
							<figcaption class="fqr-by">
								<span class="fqr-name">{lead.name}</span>
								{lead.meta && <span class="fqr-meta">{lead.meta}</span>}
								{(lead.rating !== null || lead.source || lead.sourceUrl || lead.date) && (
									<span class="fqr-proof">
										{lead.rating !== null && (
											<span class="fqr-stars" role="img" aria-label={`Rated ${lead.rating} out of 5`}>
												<span class="fqr-stars-fill" style={`width: ${(lead.rating / 5) * 100}%`} />
											</span>
										)}
										{(() => {
											const p = provenanceOf(lead);
											return (
												<span class="fqr-prov">
													{p.label &&
														(p.href ? (
															<a class="fqr-source fqr-link" href={p.href} rel="noopener">
																{p.label}
																<span class="fqr-arrow" aria-hidden="true">
																	↗
																</span>
																<span class="fqr-sr"> (original review by {lead.name})</span>
															</a>
														) : (
															<span class="fqr-source">{p.label}</span>
														))}
													{p.date && (
														<time class="fqr-date" datetime={isoDate(p.date)}>
															{p.date}
														</time>
													)}
												</span>
											);
										})()}
									</span>
								)}
							</figcaption>
						</figure>
					)}

					{rest.length > 0 && (
						<ul class:list={["fqr-grid", { "fqr-grid--rated": gridRated, "fqr-grid--odd": rest.length % 2 === 1, "fqr-grid--pairs": rest.length === 2 || rest.length === 4 }]} role="list">
							{rest.map((r) => (
								<li class="fqr-item">
									<figure>
										{r.rating !== null && (
											<span class="fqr-stars" role="img" aria-label={`Rated ${r.rating} out of 5`}>
												<span class="fqr-stars-fill" style={`width: ${(r.rating / 5) * 100}%`} />
											</span>
										)}
										<blockquote class="fqr-quote">
											<p>{r.quote}</p>
										</blockquote>
										<figcaption class="fqr-by">
											<span class="fqr-name">{r.name}</span>
											{r.meta && <span class="fqr-meta">{r.meta}</span>}
											{(r.source || r.sourceUrl || r.date) &&
												(() => {
													const p = provenanceOf(r);
													return (
														<span class="fqr-prov">
															{p.label &&
																(p.href ? (
																	<a class="fqr-source fqr-link" href={p.href} rel="noopener">
																		{p.label}
																		<span class="fqr-arrow" aria-hidden="true">
																			↗
																		</span>
																		<span class="fqr-sr"> (original review by {r.name})</span>
																	</a>
																) : (
																	<span class="fqr-source">{p.label}</span>
																))}
															{p.date && (
																<time class="fqr-date" datetime={isoDate(p.date)}>
																	{p.date}
																</time>
															)}
														</span>
													);
												})()}
										</figcaption>
									</figure>
								</li>
							))}
						</ul>
					)}

					{cta && (
						<p class="fqr-cta-row">
							<a class="fqr-cta" href={safeHref(cta.href)}>
								{cta.label}
							</a>
						</p>
					)}
				</div>
			</section>
		</>
	)
}

<style>
	.fqr {
		--fqr-surface: var(--fqr-bg, #ffffff);
		--fqr-ink: var(--fqr-text, #0f1b2d);
		--fqr-muted: var(--fqr-text-muted, #475569);
		--fqr-accent: var(--fqr-brand, #1d4ed8);
		--fqr-star: var(--fqr-star-color, #b45309);
		--fqr-rule: var(--fqr-border, #d9dee7);
		--fqr-font: var(--fqr-family, Manrope, ui-sans-serif, system-ui, sans-serif);

		container-type: inline-size;
		background: var(--fqr-surface);
		color: var(--fqr-ink);
		font-family: var(--fqr-font);
	}

	.fqr *,
	.fqr *::before,
	.fqr *::after {
		box-sizing: border-box;
	}

	.fqr-inner {
		max-width: 1200px;
		margin: 0 auto;
		padding: 56px 20px;
	}

	.fqr-head {
		max-width: 680px;
	}

	.fqr-head--rated {
		max-width: none;
		display: grid;
		gap: 28px;
	}

	.fqr-head-copy {
		max-width: 680px;
		min-width: 0;
	}

	.fqr-eyebrow {
		margin: 0 0 12px;
		color: var(--fqr-muted);
		font: 700 15px/1.4 var(--fqr-font);
	}

	/* Step 40: the supplied aggregate — one figure, its stars, and where it comes from. */
	.fqr-overall {
		display: flex;
		align-items: center;
		gap: 16px;
		margin: 0;
		padding-top: 20px;
		border-top: 1px solid var(--fqr-rule);
		min-width: 0;
	}

	.fqr-overall-value {
		font: 800 56px/0.9 var(--fqr-font);
		letter-spacing: -0.04em;
		font-variant-numeric: tabular-nums;
	}

	.fqr-overall-detail {
		display: flex;
		flex-direction: column;
		gap: 8px;
		min-width: 0;
	}

	.fqr-overall-basis {
		color: var(--fqr-muted);
		font: 600 15px/1.4 var(--fqr-font);
		overflow-wrap: anywhere;
	}

	/* Provenance links: a web page the review or rating was read from. */
	.fqr-link {
		display: inline-flex;
		align-items: center;
		gap: 4px;
		/* A comfortable target on touch screens without breaking the meta line's rhythm. */
		min-height: 32px;
		color: var(--fqr-ink);
		text-decoration: underline;
		text-decoration-color: var(--fqr-rule);
		text-decoration-thickness: 1px;
		text-underline-offset: 4px;
		transition: text-decoration-color 0.15s ease;
	}

	.fqr-link:hover {
		text-decoration-color: var(--fqr-accent);
	}

	.fqr-link:focus-visible {
		outline: 3px solid var(--fqr-accent);
		outline-offset: 3px;
		border-radius: 2px;
	}

	/* An inline-block glyph takes no underline from its link. */
	.fqr-arrow {
		display: inline-block;
		font-size: 0.9em;
		line-height: 1;
	}

	.fqr-sr {
		position: absolute;
		width: 1px;
		height: 1px;
		margin: -1px;
		padding: 0;
		overflow: hidden;
		clip: rect(0 0 0 0);
		white-space: nowrap;
		border: 0;
	}

	.fqr-prov {
		display: inline-flex;
		flex-wrap: wrap;
		align-items: baseline;
		gap: 2px 10px;
		min-width: 0;
	}

	.fqr-date {
		color: var(--fqr-muted);
		font: 500 14px/1.5 var(--fqr-font);
	}

	/* Platform, then date, joined by a quiet point. */
	.fqr-source + .fqr-date::before {
		content: "·";
		margin-right: 10px;
		color: var(--fqr-rule);
	}

	.fqr-item .fqr-prov {
		margin-top: 4px;
	}

	.fqr-title {
		margin: 0;
		font: 800 clamp(30px, 6.4cqi, 44px) / 1.1 var(--fqr-font);
		letter-spacing: -0.025em;
		text-wrap: balance;
		overflow-wrap: anywhere;
	}

	.fqr-intro {
		margin: 16px 0 0;
		color: var(--fqr-muted);
		font: 500 17px/1.6 var(--fqr-font);
		overflow-wrap: anywhere;
	}

	figure {
		margin: 0;
	}

	blockquote {
		margin: 0;
	}

	blockquote p {
		margin: 0;
	}

	.fqr-lead {
		position: relative;
		margin-top: 40px;
		padding-left: 0;
	}

	.fqr-mark {
		display: block;
		height: 0.55em;
		color: var(--fqr-accent);
		font: 800 88px/1 Georgia, "Times New Roman", serif;
	}

	.fqr-lead-quote {
		max-width: 30ch;
		font: 700 clamp(24px, 4.6cqi, 40px) / 1.26 var(--fqr-font);
		letter-spacing: -0.015em;
		text-wrap: pretty;
		overflow-wrap: anywhere;
	}

	.fqr-lead--long .fqr-lead-quote {
		max-width: 46ch;
		font-size: clamp(20px, 3.2cqi, 27px);
		line-height: 1.45;
	}

	.fqr-by {
		display: flex;
		flex-direction: column;
		gap: 2px;
		margin-top: 16px;
		min-width: 0;
	}

	.fqr-lead .fqr-by {
		margin-top: 24px;
	}

	.fqr-name {
		font: 800 16px/1.4 var(--fqr-font);
		overflow-wrap: anywhere;
	}

	.fqr-meta,
	.fqr-source {
		color: var(--fqr-muted);
		font: 500 14px/1.5 var(--fqr-font);
		overflow-wrap: anywhere;
	}

	.fqr-proof {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: 4px 12px;
		margin-top: 8px;
	}

	/* Five outlines, filled to the rating from the left. */
	.fqr-stars {
		position: relative;
		display: inline-block;
		width: 92px;
		height: 18px;
		flex: none;
		background: var(--fqr-rule);
		-webkit-mask: var(--fqr-star-mask) 0 0 / 18.4px 18px repeat-x;
		mask: var(--fqr-star-mask) 0 0 / 18.4px 18px repeat-x;
		--fqr-star-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m12 2.5 2.9 6 6.6.9-4.8 4.6 1.2 6.5L12 17.4l-5.9 3.1 1.2-6.5-4.8-4.6 6.6-.9z'/%3E%3C/svg%3E");
	}

	.fqr-stars-fill {
		position: absolute;
		inset: 0 auto 0 0;
		background: var(--fqr-star);
	}

	.fqr-item .fqr-stars {
		display: block;
		margin-bottom: 12px;
	}


	.fqr-grid {
		display: grid;
		grid-template-columns: 1fr;
		gap: 0;
		margin: 40px 0 0;
		padding: 0;
		list-style: none;
	}

	.fqr-item {
		min-width: 0;
		padding: 24px 0;
		border-top: 2px solid var(--fqr-ink);
	}

	.fqr-quote {
		max-width: 46ch;
		font: 500 17px/1.65 var(--fqr-font);
		overflow-wrap: anywhere;
	}

	/* The close: a hairline across the section, the action sitting on it. */
	.fqr-cta-row {
		margin: 32px 0 0;
		padding-top: 20px;
		border-top: 1px solid var(--fqr-rule);
	}

	.fqr-cta {
		display: inline-flex;
		align-items: baseline;
		gap: 10px;
		min-height: 44px;
		padding: 10px 0;
		color: var(--fqr-ink);
		font: 700 16px/1.4 var(--fqr-font);
		text-decoration: underline;
		text-decoration-color: var(--fqr-accent);
		text-decoration-thickness: 2px;
		text-underline-offset: 6px;
		transition: text-underline-offset 0.18s ease;
		overflow-wrap: anywhere;
	}

	.fqr-cta:hover {
		text-underline-offset: 3px;
	}

	.fqr-cta:focus-visible {
		outline: 3px solid var(--fqr-accent);
		outline-offset: 3px;
	}

	@container (min-width: 700px) {
		.fqr-inner {
			padding: 72px 32px;
		}

		.fqr-grid {
			grid-template-columns: repeat(2, minmax(0, 1fr));
			gap: 0 40px;
		}

		/* Two columns and an odd count: the last review takes the row. */
		.fqr-grid--odd .fqr-item:last-child {
			grid-column: 1 / -1;
		}

		.fqr-grid--odd .fqr-item:last-child .fqr-quote {
			max-width: 60ch;
		}

		/* Side by side, rated and unrated reviews start their quotes on one line (one column needs no gap). */
		.fqr-grid--rated .fqr-item figure:not(:has(.fqr-stars)) {
			padding-top: 30px;
		}
	}

	@container (min-width: 1000px) {
		/* Step 39.2: --fqr-grid-max / --fqr-grid-gutter put the content on a site grid; the fallbacks are the original 1200 / 40. */
		.fqr-inner {
			padding: 96px 0;
			max-width: var(--fqr-grid-max, 1200px);
			padding-inline: var(--fqr-grid-gutter, 40px);
		}

		/* Step 40: the attribution sits directly under the lead quote, on its left edge, not across the page. */
		.fqr-lead {
			margin-top: 56px;
			padding-left: 76px;
		}

		.fqr-lead-quote {
			max-width: 34ch;
			font-size: clamp(30px, 3.4cqi, 44px);
		}

		/* Name and place, then the proof on its own line: two quiet lines, not one busy one. */
		.fqr-lead .fqr-by {
			margin: 32px 0 0;
			padding-left: 20px;
			border-left: 3px solid var(--fqr-accent);
		}

		.fqr-lead .fqr-proof {
			margin-top: 6px;
		}

		/* The aggregate stands beside the heading, on its baseline, once there is room for both. */
		.fqr-head--rated {
			grid-template-columns: minmax(0, 1fr) auto;
			align-items: end;
			column-gap: 56px;
		}

		.fqr-overall {
			padding: 0 0 4px 28px;
			border-top: 0;
			border-left: 1px solid var(--fqr-rule);
		}

		/* Two or four grid reviews sit as pairs instead of leaving a hole in a row of three. */
		.fqr-grid.fqr-grid--pairs {
			grid-template-columns: repeat(2, minmax(0, 1fr));
		}

		.fqr-grid--odd .fqr-item:last-child {
			grid-column: auto;
		}

		.fqr-mark {
			position: absolute;
			top: 0;
			left: 0;
			height: auto;
			font-size: 112px;
			line-height: 0.8;
		}

		.fqr-grid {
			grid-template-columns: repeat(3, minmax(0, 1fr));
			margin-top: 64px;
		}
	}

	@media (forced-colors: active) {
		.fqr-stars {
			forced-color-adjust: none;
			background: GrayText;
		}

		.fqr-stars-fill {
			background: CanvasText;
		}
	}
</style>