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: "Split stat feature section"
Library page: https://astro.baysixmedia.com/components/split-stat-feature-section/
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/SplitStatFeatureSection.astro =====
---
/**
* Split stat feature section
*
* A two-column section: a headline block on the left carrying an eyebrow, a
* large uppercase heading, a short paragraph and a row of figures divided by
* hairlines; a grid of feature cards on the right, each with a ringed icon,
* an uppercase title and a line or two of body.
*
* Static: no script at all, and nothing focusable — it is a block of content,
* not a control. There is nothing for a client-side router to tear down and
* nothing a motion preference changes.
*
* Self-contained: no imports, no packages, no global stylesheet, no webfont.
* Every colour, size and duration is a `--fsl-*` custom property on the root.
*/
export interface FeatureStat {
/** The figure, already formatted — "18K+", "99.9%", "4.8". */
value: string;
/** The word under it. Set in small caps-height uppercase. */
label: string;
}
export interface FeatureCard {
/** The uppercase title. */
title: string;
/** One to three lines under it. */
body: string;
/** Which glyph sits in the ring. See GLYPHS below to extend the set. */
icon?: "cloud" | "monitor" | "spark" | "shield" | "chart" | "lock";
}
interface Props {
/** The small pill above the heading. `""` hides it. */
eyebrow?: string;
/** The heading. Rendered uppercase by the stylesheet, not by the string. */
heading?: string;
/** One or two sentences under the heading. `""` hides it. */
body?: string;
/** The figures. Three is the measured shape; more wrap. */
stats?: FeatureStat[];
/** The cards. Four is the measured shape; the grid takes any number. */
features?: FeatureCard[];
/** Heading level for the section title. Cards use the next one down. */
headingLevel?: "h1" | "h2" | "h3";
/** The section surface, painted edge to edge. */
background?: string;
/** Every text colour and every hairline derives from this. */
ink?: string;
/**
* The card fill. Separate from `ink` because the reference does not derive
* it: dark cards are white at 6 per cent, light ones are white at 55, so
* one is a lift off the surface and the other is a panel on top of it.
*/
cardBackground?: string;
/** The card hairline. */
cardBorderColor?: string;
/**
* Content width before the section padding. `"none"` is the reference,
* which does not cap — on a very wide display the two columns simply keep
* growing. Most pages will want a number here.
*/
maxWidth?: string;
/** Added to the root. */
class?: string;
/** Root element id. */
id?: string;
}
const {
eyebrow = "",
heading = "",
body = "",
stats = [],
features = [],
headingLevel = "h2",
background = "#111111",
ink = "#f4f4f4",
cardBackground = "rgb(255 255 255 / 0.06)",
cardBorderColor = "rgb(255 255 255 / 0.12)",
maxWidth = "none",
class: className,
id,
} = Astro.props;
const Heading = headingLevel;
const CardHeading = headingLevel === "h1" ? "h2" : headingLevel === "h2" ? "h3" : "h4";
/*
* A figure needs both its value and its label, and a card needs its title; a
* partial record is dropped rather than drawn half-empty. With no heading, no
* figures and no cards there is nothing to show, so nothing renders.
*/
const figures = stats.filter((stat) => stat && stat.value && stat.label);
const cards = features.filter((card) => card && card.title);
const hasContent = Boolean(heading) || figures.length > 0 || cards.length > 0;
/*
* A <section> is only a landmark when it has an accessible name, so the
* heading supplies one. The id has to be unique per instance because two of
* these can sit on one page; it derives from the caller's `id` when there is
* one and is generated when there is not.
*/
const uid = id ?? `fsl-${Math.random().toString(36).slice(2, 9)}`;
const headingId = `${uid}-heading`;
/*
* Inlined rather than fetched, so the section makes no request of its own.
* Drawn on a 24 grid at stroke 1.7, matching the reference's weight. Generic
* UI glyphs, not anyone's trademark.
*/
const GLYPHS: Record<string, string[]> = {
cloud: ["M17.3 19H7a4.5 4.5 0 0 1-.8-8.9 6 6 0 0 1 11.5 1.1 4 4 0 0 1-.4 7.8z"],
monitor: [
"M3 5.5A1.5 1.5 0 0 1 4.5 4h15A1.5 1.5 0 0 1 21 5.5v9a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 14.5z",
"M12 16v4",
"M8 20h8",
],
spark: ["M13 2.5 5 13.5h6l-1 8 8-11.5h-6z"],
shield: ["M12 3.2 19 6v5.6c0 4.2-2.9 7.6-7 8.4-4.1-.8-7-4.2-7-8.4V6z", "m9.2 11.8 2 2 3.6-3.8"],
chart: ["M3 20h18", "M7.5 20v-5.5", "M12 20V7", "M16.5 20v-9"],
lock: [
"M6.5 10.5h11a1 1 0 0 1 1 1V19a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1v-7.5a1 1 0 0 1 1-1z",
"M9 10.5V8a3 3 0 0 1 6 0v2.5",
],
};
const style = [
`--fsl-bg:${background}`,
`--fsl-ink:${ink}`,
`--fsl-card-bg:${cardBackground}`,
`--fsl-card-border:${cardBorderColor}`,
`--fsl-max:${maxWidth}`,
].join(";");
---
{hasContent && (
<section
class:list={["split-stat-feature", className]}
id={id}
style={style}
aria-labelledby={heading ? headingId : undefined}
data-split-stat-feature
>
<div class="fsl-inner">
<header class="fsl-head">
{eyebrow && (
<p class="fsl-eyebrow"><span class="fsl-pill">{eyebrow}</span></p>
)}
{heading && <Heading class="fsl-title" id={headingId}>{heading}</Heading>}
{body && <p class="fsl-body">{body}</p>}
{figures.length > 0 && (
<ul class="fsl-stats">
{figures.map((stat) => (
<li class="fsl-stat">
<span class="fsl-stat-value">{stat.value}</span>
<span class="fsl-stat-label">{stat.label}</span>
</li>
))}
</ul>
)}
</header>
{cards.length > 0 && (
<ul class="fsl-cards">
{cards.map((card) => (
<li>
<article class="fsl-card">
<div class="fsl-ring">
<svg
class="fsl-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.7"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
{(GLYPHS[card.icon ?? "cloud"] ?? GLYPHS.cloud).map((d) => (
<path d={d}></path>
))}
</svg>
</div>
<div class="fsl-card-text">
<CardHeading class="fsl-card-title">{card.title}</CardHeading>
{card.body && <p class="fsl-card-body">{card.body}</p>}
</div>
</article>
</li>
))}
</ul>
)}
</div>
</section>
)}
<style>
.split-stat-feature {
/*
* Four steps, and they are the reference's own: 1024, 768 and 431 are
* where it changes padding, column count and type size. Written as
* min-width queries below so the boundaries land on the same pixel.
*/
--fsl-pad: 56px;
--fsl-gap: 56px;
--fsl-title-size: 48px;
/* The figure row has its own two steps, and they are not the section's:
above 768 the figures are large and hairline-divided, below it they
are smaller, closer together and undivided. */
--fsl-stat-gap: 56px;
--fsl-stat-size: 36px;
--fsl-stat-min: 0px;
--fsl-divider-w: 1px;
/*
* Every tone in the section is one of these alphas over the ink. The
* reference uses the same ratios in both its themes, which is why two
* colour props are enough to reskin the whole thing.
*/
--fsl-a-pill-bg: 0.08;
--fsl-a-pill-edge: 0.14;
--fsl-a-pill-text: 0.5;
--fsl-a-body: 0.62;
--fsl-a-stat-label: 0.55;
--fsl-a-divider: 0.14;
--fsl-a-ring: 0.22;
--fsl-a-card-body: 0.55;
--fsl-card-radius: 22px;
--fsl-card-gap: 12px;
box-sizing: border-box;
display: block;
inline-size: 100%;
padding: var(--fsl-pad);
background: var(--fsl-bg);
color: var(--fsl-ink);
/* A system stack on purpose: a component in this library fetches
nothing, so it can never be waiting on a webfont. */
font-family:
system-ui,
-apple-system,
"Segoe UI",
Roboto,
Helvetica,
Arial,
sans-serif;
}
.split-stat-feature *,
.split-stat-feature *::before,
.split-stat-feature *::after {
box-sizing: border-box;
}
/*
* A scoped reset, and it earns its place. Everything below sets type on
* classes, which beats inheritance — but it does not beat a host rule
* aimed at the bare element, and a marketing page that styles `h2`, `ul`
* or `p` globally is the normal case rather than the exception.
*
* `:where()` keeps this at the specificity of the root alone, so the rules
* underneath still win on source order while a host's element selector
* loses. The `:global()` is load-bearing: Astro cannot put its scope
* attribute inside `:where()`, so without it the compiler emits a second
* attribute beside it and the whole thing outranks the class rules.
*/
.split-stat-feature :global(:where(h1, h2, h3, h4, p, ul, li, span, article, header)) {
margin: 0;
padding: 0;
border: 0;
font: inherit;
color: inherit;
list-style: none;
}
.fsl-inner {
display: grid;
grid-template-columns: 1fr 1fr;
/* Centred against each other: the two columns are rarely the same
height, and the reference balances them rather than topping them. */
align-items: center;
gap: var(--fsl-gap);
max-inline-size: var(--fsl-max);
margin-inline: auto;
}
/* ---- the headline column ------------------------------------------- */
.fsl-head {
display: flex;
flex-direction: column;
gap: 22px;
}
.fsl-eyebrow {
display: flex;
}
.fsl-pill {
display: inline-block;
padding: 5px 12px;
border: 1px solid color-mix(in srgb, var(--fsl-ink) calc(var(--fsl-a-pill-edge) * 100%), transparent);
border-radius: 999px;
background: color-mix(in srgb, var(--fsl-ink) calc(var(--fsl-a-pill-bg) * 100%), transparent);
color: color-mix(in srgb, var(--fsl-ink) calc(var(--fsl-a-pill-text) * 100%), transparent);
font-size: 12px;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.fsl-title {
/*
* Uppercased here rather than in the string, so the prop stays
* readable prose and a screen reader is not handed shouted text.
* Line height is 0.95 at every step, which is the reference's ratio.
*/
font-size: var(--fsl-title-size);
line-height: 0.95;
font-weight: 400;
letter-spacing: -0.03em;
text-transform: uppercase;
text-wrap: balance;
color: var(--fsl-ink);
}
.fsl-body {
max-inline-size: 460px;
font-size: 16px;
line-height: 1.7;
color: color-mix(in srgb, var(--fsl-ink) calc(var(--fsl-a-body) * 100%), transparent);
}
.fsl-stats {
display: flex;
flex-wrap: wrap;
gap: 20px var(--fsl-stat-gap);
/*
* Load-bearing, and it is the fix for a defect the reference has.
*
* Each divider is drawn half a gap to the LEFT of its own item, so an
* item that begins a line puts its divider at a negative offset —
* outside this box, where `overflow: hidden` removes it. Written the
* obvious way, as `border-inline-end` on every item but the last, the
* hairline survives a wrap and ends a line with nothing after it. The
* reference does exactly that, and it shows: from about 950px down to
* 768 its figure row wraps and leaves a hairline hanging off the end
* of the first line. Measured at 900, 850, 800, 780, 769 and 768.
*/
overflow: hidden;
}
.fsl-stat {
position: relative;
display: flex;
flex-direction: column;
gap: 6px;
min-inline-size: var(--fsl-stat-min);
}
.fsl-stat::before {
content: "";
position: absolute;
inset-block: 0;
inset-inline-start: calc(var(--fsl-stat-gap) / -2);
border-inline-start: var(--fsl-divider-w) solid
color-mix(in srgb, var(--fsl-ink) calc(var(--fsl-a-divider) * 100%), transparent);
}
.fsl-stat-value {
font-size: var(--fsl-stat-size);
line-height: 1;
font-weight: 900;
letter-spacing: -0.04em;
/* Tabular, so a figure that changes does not shift the row. */
font-variant-numeric: tabular-nums;
color: var(--fsl-ink);
}
.fsl-stat-label {
font-size: 11px;
line-height: 1.4;
letter-spacing: 0.08em;
text-transform: uppercase;
color: color-mix(in srgb, var(--fsl-ink) calc(var(--fsl-a-stat-label) * 100%), transparent);
}
/* ---- the card grid -------------------------------------------------- */
.fsl-cards {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--fsl-card-gap);
}
.fsl-card {
display: flex;
flex-direction: column;
gap: 14px;
/* Full height, so two cards in a row match even when one body wraps
to a third line. The reference's row does this by grid default; an
explicit height keeps it true when the grid is a single column. */
block-size: 100%;
padding: 24px;
border: 1px solid var(--fsl-card-border);
border-radius: var(--fsl-card-radius);
background: var(--fsl-card-bg);
/* Lift, then a one-pixel highlight along the top edge. */
box-shadow:
0 8px 28px color-mix(in srgb, var(--fsl-ink) 6%, transparent),
inset 0 1px 0 rgb(255 255 255 / 0.06);
}
.fsl-ring {
flex: 0 0 auto;
display: grid;
place-items: center;
inline-size: 40px;
block-size: 40px;
border: 1.33px solid color-mix(in srgb, var(--fsl-ink) calc(var(--fsl-a-ring) * 100%), transparent);
border-radius: 999px;
}
.fsl-icon {
inline-size: 18px;
block-size: 18px;
color: var(--fsl-ink);
}
.fsl-card-text {
display: flex;
flex-direction: column;
gap: 6px;
}
.fsl-card-title {
font-size: 16px;
line-height: 1.2;
font-weight: 900;
letter-spacing: -0.03em;
text-transform: uppercase;
color: var(--fsl-ink);
}
.fsl-card-body {
font-size: 14px;
line-height: 1.55;
color: color-mix(in srgb, var(--fsl-ink) calc(var(--fsl-a-card-body) * 100%), transparent);
}
/* ---- responsive ----------------------------------------------------- */
/*
* Mobile first, so each boundary lands on the same pixel as the
* reference's. The reference changes at 1024, 768 and 431; written as
* `max-width` these would each miss a viewport reporting a fractional
* width just under the round number.
*
* Base = the smallest step: 16px padding, one column, one card per row.
*/
.split-stat-feature {
--fsl-pad: 16px;
--fsl-gap: 32px;
--fsl-title-size: 28px;
/* Below the section's own 768 step the figures shrink, close up and
lose their dividers entirely — the reference's treatment, measured
at 767 and below. The minimum keeps three short figures in an even
row the way the reference's are, without clipping a longer label. */
--fsl-stat-gap: 20px;
--fsl-stat-size: 28px;
--fsl-stat-min: 88px;
--fsl-divider-w: 0;
}
.fsl-inner {
grid-template-columns: minmax(0, 1fr);
}
.fsl-cards {
grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 431px) {
.split-stat-feature {
--fsl-pad: 24px;
--fsl-gap: 40px;
--fsl-title-size: 34px;
}
.fsl-cards {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (min-width: 768px) {
.split-stat-feature {
--fsl-pad: 40px;
--fsl-gap: 56px;
--fsl-title-size: 42px;
--fsl-stat-gap: 56px;
--fsl-stat-size: 36px;
--fsl-stat-min: 0px;
--fsl-divider-w: 1px;
}
.fsl-inner {
grid-template-columns: 1fr 1fr;
}
}
@media (min-width: 1024px) {
.split-stat-feature {
--fsl-pad: 56px;
--fsl-title-size: 48px;
}
}
/* ---- preferences ---------------------------------------------------- */
@media (forced-colors: active) {
/*
* The cards are a translucent fill and a translucent hairline, the
* pill and the icon ring likewise, and none of that survives here.
* Each one takes a real border instead.
*/
.fsl-card,
.fsl-pill,
.fsl-ring {
border-color: CanvasText;
}
.fsl-card {
box-shadow: none;
}
.fsl-stat::before {
border-inline-start-color: CanvasText;
}
}
</style>
===== END src/components/SplitStatFeatureSection.astro =====
===== FILE (supporting): src/components/SplitStatFeatureSection.md =====
# Split stat feature section
A two-column section: an eyebrow, a large uppercase heading, a short
paragraph and a row of hairline-divided figures on the left; a grid of
ringed-icon cards on the right.
Catalog page: `/components/split-stat-feature-section`
## Purpose
The "what this actually does" block on a marketing page — the one that comes
after the hero and has to carry both the claim and the evidence. The left
column argues, the right column enumerates, and the figures sit between them
so the claim has something under it.
Use something else if you have eight features. Four cards is the shape; six
still reads, and past that the grid stops being scannable and becomes a
table.
## Files required
**`SplitStatFeatureSection.astro`** — one file, the whole component.
- No imports at all, not even a type.
- No npm packages, no icon library, no React, no Tailwind, no CSS reset.
- No global stylesheet. Every colour and size is declared on the component's
own root element as a `--fsl-*` custom property.
- No webfonts and **no images**. Every icon is inline SVG, so the section
makes **no network request of its own** — nothing to copy into `public/`.
- The only assumption about the host is that Astro compiles `.astro` files.
`SplitStatFeatureSection.md` — this file. Documentation, not required to run.
## Basic usage
```astro
---
import SplitStatFeatureSection from "../components/SplitStatFeatureSection.astro";
---
<SplitStatFeatureSection
eyebrow="Workflow"
heading="Start small. Ship often. Scale when it matters."
body="Everything a small team needs to get work out the door."
stats={[
{ value: "18K+", label: "Teams onboard" },
{ value: "99.9%", label: "Uptime" },
]}
features={[
{ title: "Shared drafts", body: "Everyone edits the same version.", icon: "cloud" },
{ title: "Locked by default", body: "Permissions start closed.", icon: "shield" },
]}
/>
```
No client directive, no wrapper, no init call — the component ships **no
script at all**.
It is a full-bleed band: it paints its own background edge to edge and
applies its own padding, so it drops straight into the page flow.
## Props
Every prop is optional, and no content is built in: with no `heading`, no
`stats` and no `features` the component renders nothing at all. The catalog
demo passes its copy, figures and cards as props.
| Prop | Type | Default | What it does |
| :--- | :--- | :--- | :--- |
| `eyebrow` | `string?` | `""` | The pill above the heading. Hidden when empty; never renders the section on its own. |
| `heading` | `string?` | `""` | The heading. **Pass sentence case** — the stylesheet uppercases it. Also names the section landmark; hidden when empty. |
| `body` | `string?` | `""` | One or two sentences under it. Hidden when empty. |
| `stats` | `FeatureStat[]?` | `[]` | The figures. Real numbers only: the default is none, and the row is dropped. A figure missing its value or label is dropped. |
| `features` | `FeatureCard[]?` | `[]` | The cards. A card without a `title` is dropped; one without a `body` shows just its title. |
| `headingLevel` | `"h1" \| "h2" \| "h3"?` | `"h2"` | The section heading's element. Cards use the next level down. |
| `background` | `string?` | `#111111` | The surface it paints, edge to edge. |
| `ink` | `string?` | `#f4f4f4` | Every text colour and hairline derives from this. |
| `cardBackground` | `string?` | `rgb(255 255 255 / 0.06)` | The card fill. |
| `cardBorderColor` | `string?` | `rgb(255 255 255 / 0.12)` | The card hairline. |
| `maxWidth` | `string?` | `"none"` | Content width before the padding. See below. |
| `class` | `string?` | — | Extra class on the root. |
| `id` | `string?` | — | Element id. |
### One figure
| Field | Type | What it does |
| :--- | :--- | :--- |
| `value` | `string` | Already formatted — `"18K+"`, `"99.9%"`. Set in tabular figures. |
| `label` | `string` | The word under it. Uppercased by the stylesheet. |
### One card
| Field | Type | What it does |
| :--- | :--- | :--- |
| `title` | `string` | Uppercased by the stylesheet. |
| `body` | `string` | One to three lines. |
| `icon` | `"cloud" \| "monitor" \| "spark" \| "shield" \| "chart" \| "lock"?` | Which glyph sits in the ring. |
```ts
import type { FeatureStat, FeatureCard } from "../components/SplitStatFeatureSection.astro";
```
### About `maxWidth`
It defaults to `"none"`, which is what the reference does — the two columns
keep growing on a very wide display. That is faithful but rarely what you
want past about 1600px:
```astro
<SplitStatFeatureSection maxWidth="1440px" />
```
### A light section
Every tone derives from `ink` except the card fill, so the light version is
four props:
```astro
<SplitStatFeatureSection
background="#ececec"
ink="#111111"
cardBackground="rgb(255 255 255 / 0.55)"
cardBorderColor="rgb(17 17 17 / 0.12)"
/>
```
Those are the reference's own light values, read off its theme toggle. There
is no `prefers-color-scheme` rule in the file, on purpose: no component in
this library ships one, because a component that picks its own theme fights
the page it lands in.
### Adding an icon
The glyphs live in a `GLYPHS` map near the top of the file. Once the
component is in your project it is your file — add paths drawn on a 24 grid
at stroke 1.7 and widen the `icon` union to match.
## Behaviour
None. It is a block of content: no script, no state, nothing focusable,
nothing that animates. The only thing that changes is the layout, and only
with the viewport.
## Responsive
Four steps, and they are the reference's own pixels:
| Width | Padding | Columns | Cards | Heading |
| :--- | :--- | :--- | :--- | :--- |
| ≥ 1024 | 56px | two | 2-up | 48px |
| 768–1023 | 40px | two | 2-up | 42px |
| 431–767 | 24px | one | 2-up | 34px |
| ≤ 430 | 16px | one | 1-up | 28px |
Line height is 0.95 at every step.
The figure row has its own step at 768, separate from the section's: above
it the figures are 36px and divided by hairlines, below it they are 28px,
closer together and undivided.
## Accessibility
- It renders a `<section>` **named by its own heading** via
`aria-labelledby`, so it is a real landmark rather than a generic region.
The id is generated per instance, so two of these on one page do not
collide.
- `headingLevel` sets the section heading and the cards follow one level
down, so the outline stays correct instead of every section being an `h2`.
- **The heading is uppercased by CSS, not by the string.** Pass sentence
case. Shouted text in the markup is read as shouted text by some screen
readers, and it is unreadable in the prop.
- Icons are `aria-hidden`. They decorate the card title, which carries the
meaning.
- Figures are set in tabular numerals, so a number that updates does not
shift the row.
- Nothing here is focusable, so there is no tab order to get wrong and no
focus ring to draw.
- Under `forced-colors: active` the cards, the pill, the icon rings and the
figure dividers each take a real border, since all four are otherwise a
translucent fill or hairline that does not survive.
## Reduced motion
Nothing moves, so there is nothing to reduce. The component declares
`hasMotion: false` and the readiness record marks the reduced-motion check
*not applicable* rather than claiming a pass it did not earn.
## Without JavaScript
Identical. The component ships no script, so there is nothing to degrade.
## Content length
- **Eyebrow** — one or two words.
- **Heading** — six to ten words. It is set very large and very tight; past
about twelve words it stops being a heading.
- **Body** — one or two sentences, capped at 460px so it never runs the full
column width.
- **Figures** — two to four. Values of four or five characters.
- **Cards** — four is the measured shape. Bodies of one to three lines; the
cards in a row match heights, so a long one sets the row.
## Sizing
Full width, painting its own background edge to edge, with content capped at
`maxWidth` and centred. The two columns are equal halves above 768px and
stack below it, centred against each other vertically so a short left column
sits level with a tall card grid.
Retune from CSS without touching the file:
```css
.my-page .split-stat-feature {
--fsl-pad: 40px;
--fsl-card-radius: 12px;
--fsl-stat-gap: 40px;
}
```
## Differences from the reference
Rebuilt from a live page, measured rather than copied. Every value taken
matches: 56/40/24/16 padding at 1024/768/431, two equal columns at 56px gap,
a 22px card radius with 24px padding and a 12px grid gap, a 40px icon ring
around an 18px glyph, and type at 48/16/36/11/16/14 with the same tracking
and the same 0.95 heading ratio. What differs:
- **The copy, the figures and the icons are original.** Nothing of the
reference's wording or artwork is reproduced.
- **A wrapped figure row no longer leaves a hairline hanging.** The
reference draws its dividers as `border-right` on every figure but the
last, which survives a line break: from about 950px down to 768 its row
wraps and a hairline ends the first line with nothing after it — measured
at 900, 850, 800, 780, 769 and 768. Here each divider is drawn half a gap
to its own left and clipped by the row, so an item that begins a line has
no divider at all.
- **The heading is a real landmark name.** The reference's section has no
accessible name.
- **Figures have a minimum width below 768px** so three short ones line up
evenly, as the reference's do, without clipping a longer label. The
reference fixes the width instead, which only works for its own copy.
- **Sub-pixel:** the reference's hairlines report 0.667px because its page is
read at a fractional device pixel ratio; these are authored 1px, as are
the reference's. The divider being positioned rather than in flow also
makes each figure run 0.7px narrower than the reference's.
- The reference sets its type in Manrope at weight 900. This uses the system
stack, so the platform's heaviest face stands in and the headline reads
slightly differently. That is deliberate: a component in this library
fetches nothing.
===== END src/components/SplitStatFeatureSection.md =====
--- VERIFIED IN THE COMPONENT LIBRARY ---
NOT production ready in the library.
Verified 2026-09-21 at 1600, 1440, 1280, 1024, 1023, 900, 834, 768, 767, 640, 480, 431, 430, 390, 360, 320px.
Passed: full-page context, keyboard, no javascript, reduced motion, two instances, no overflow, declarations corroborated, lifecycle.
Library source has CHANGED since verification. Treat every result above as expired.
--- 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.