Divided statistics band
Four figures separated by rules rather than boxed in cards.
Live preview
Source
This exact file renders the preview above.
import { Container } from '@/components/ui/layout'
import { stats } from '@/content/demo'
/**
* Divided statistics band
*
* Four figures separated by rules rather than boxed in cards. On a page that
* already has several card sections, a divided band is the quieter choice and
* reads as fact rather than as another module.
*/
export default function DividedStatsBand() {
return (
<section className="border-b border-line bg-surface-sunken py-16">
<Container>
<dl className="grid grid-cols-2 gap-y-10 lg:grid-cols-4 lg:divide-x lg:divide-[var(--color-border)]">
{stats.map((stat) => (
<div key={stat.label} className="px-0 text-center lg:px-6">
<dd className="display-type text-4xl font-semibold text-ink-strong tabular-nums">
{stat.value}
</dd>
<dt className="mt-2 text-sm font-medium text-ink">{stat.label}</dt>
{stat.detail ? <p className="mt-1 text-xs text-ink-muted">{stat.detail}</p> : null}
</div>
))}
</dl>
</Container>
</section>
)
}
components/blocks/sections/stats/divided-band.tsx
import { Container } from '@/components/ui/layout'
import { stats } from '@/content/demo'
/**
* Divided statistics band
*
* Four figures separated by rules rather than boxed in cards. On a page that
* already has several card sections, a divided band is the quieter choice and
* reads as fact rather than as another module.
*/
export default function DividedStatsBand() {
return (
<section className="border-b border-line bg-surface-sunken py-16">
<Container>
<dl className="grid grid-cols-2 gap-y-10 lg:grid-cols-4 lg:divide-x lg:divide-[var(--color-border)]">
{stats.map((stat) => (
<div key={stat.label} className="px-0 text-center lg:px-6">
<dd className="display-type text-4xl font-semibold text-ink-strong tabular-nums">
{stat.value}
</dd>
<dt className="mt-2 text-sm font-medium text-ink">{stat.label}</dt>
{stat.detail ? <p className="mt-1 text-xs text-ink-muted">{stat.detail}</p> : null}
</div>
))}
</dl>
</Container>
</section>
)
}
content/demo.ts
/**
* Shared demo content.
*
* Marketing copy lives here rather than inside JSX, so a section file stays a
* layout decision and nothing else. Every section in the library draws from
* this module, which is also what keeps 110 sections from becoming 110 copies
* of the same paragraph.
*
* All names, companies and figures are fictional.
*/
export interface Feature {
title: string
description: string
/** lucide-react icon name, resolved by the consuming section. */
icon: string
}
export const features: Feature[] = [
{
title: 'Token-driven theming',
description:
'Three orthogonal axes — scheme, palette, density — compose into every surface. Change one and the whole system follows.',
icon: 'Palette',
},
{
title: 'Accessible by construction',
description:
'Focus management, live regions and keyboard contracts are built into the primitives, not bolted on during review.',
icon: 'Accessibility',
},
{
title: 'Server-first rendering',
description:
'Sections are Server Components. Interactivity is scoped to small client islands, so a marketing page ships almost no JavaScript.',
icon: 'Server',
},
{
title: 'Composable sections',
description:
'Every block is a standalone export. Assemble a page from nine of them, or lift one into an existing codebase.',
icon: 'Layers',
},
{
title: 'Real source, always',
description:
'The code viewer reads the same file that renders the preview. Documentation cannot drift from implementation.',
icon: 'Code2',
},
{
title: 'Built to grow',
description:
'Adding a component means adding a catalogue record and a file. No page in the application needs to change.',
icon: 'Sprout',
},
]
export const secondaryFeatures: Feature[] = [
{
title: 'Responsive previews',
description: 'Inspect any block at 390, 768 and 1440 without leaving the page.',
icon: 'Smartphone',
},
{
title: 'Deterministic copy',
description: 'The copy button copies exactly what the viewer displays — no rewriting.',
icon: 'Clipboard',
},
{
title: 'Typed catalogue',
description: 'One record shape across six families, validated by the test suite.',
icon: 'ListTree',
},
{
title: 'Zero runtime CSS',
description: 'Tailwind v4 plus custom properties. No styling library in the bundle.',
icon: 'Feather',
},
{
title: 'Keyboard everything',
description: 'Menus, tabs, dialogs and the palette all follow published ARIA patterns.',
icon: 'Keyboard',
},
{
title: 'Dark authored, not inverted',
description: 'The dark scheme is designed, not derived from a filter.',
icon: 'Moon',
},
]
export interface Stat {
value: string
label: string
detail?: string
}
export const stats: Stat[] = [
{ value: '4', label: 'Composition levels', detail: 'Primitives through complete products' },
{ value: '3', label: 'Theme axes', detail: 'Scheme, palette, density' },
{ value: '0', label: 'Runtime dependencies', detail: 'Beyond React, Next and icons' },
{ value: '100%', label: 'Statically rendered', detail: 'Every catalogue route' },
]
export const companyLogos = [
'Northwind',
'Halcyon',
'Meridian',
'Kestrel',
'Lumen Works',
'Atlas Forge',
'Verdant',
'Ironwood',
]
export interface Testimonial {
quote: string
name: string
role: string
company: string
}
export const testimonials: Testimonial[] = [
{
quote:
'We replaced four half-finished internal libraries with one. The density axis alone paid for the migration — our admin tools and our marketing site finally share components.',
name: 'Priya Raman',
role: 'Principal Engineer',
company: 'Northwind',
},
{
quote:
'The accessibility work is the part I did not expect. Focus return, live regions, manual tab activation — the things that normally get filed as tech debt were already handled.',
name: 'Tomas Lindqvist',
role: 'Head of Design Systems',
company: 'Halcyon',
},
{
quote:
'Being able to read the exact source that renders the preview removed an entire class of "the docs are wrong" tickets.',
name: 'Amara Osei',
role: 'Staff Frontend Engineer',
company: 'Meridian',
},
{
quote:
'Our first landing page took an afternoon. The second took forty minutes, because by then we were composing rather than building.',
name: 'Jun Watanabe',
role: 'Product Lead',
company: 'Kestrel',
},
{
quote:
'Five palettes sounds like a gimmick until a client asks for a different accent on the third day and it is a one-line change.',
name: 'Elena Rossi',
role: 'Creative Director',
company: 'Lumen Works',
},
{
quote:
'The starters are the honest part. They are not screenshots — every route resolves, including the 404s.',
name: 'Marcus Bell',
role: 'Engineering Manager',
company: 'Atlas Forge',
},
]
export interface PricingTier {
name: string
price: string
cadence: string
description: string
features: string[]
cta: string
featured?: boolean
note?: string
}
export const pricingTiers: PricingTier[] = [
{
name: 'Solo',
price: '$0',
cadence: 'forever',
description: 'For personal projects and evaluation.',
features: [
'Every component and section',
'Copy-paste source',
'Light and dark schemes',
'Community support',
],
cta: 'Start building',
},
{
name: 'Team',
price: '$18',
cadence: 'per seat / month',
description: 'For product teams shipping together.',
features: [
'Everything in Solo',
'All five palettes',
'Starter products',
'Figma token export',
'Priority issue triage',
],
cta: 'Start a trial',
featured: true,
note: 'Most teams start here.',
},
{
name: 'Business',
price: '$2,400',
cadence: 'per year',
description: 'For organisations with a design-system function.',
features: [
'Everything in Team',
'Unlimited seats',
'Private component registry',
'Accessibility review sessions',
'Named support contact',
],
cta: 'Contact sales',
},
]
export interface FAQ {
question: string
answer: string
}
export const faqs: FAQ[] = [
{
question: 'Is Foundry a published npm package?',
answer:
'No. Foundry is a template demonstration. Components are copied into your project and owned by you — there is no registry, no install command and no version to upgrade.',
},
{
question: 'How do I change the accent colour?',
answer:
'Every accent in the system resolves from one ramp of custom properties. Redefine those seven values in your stylesheet and every button, focus ring, link and badge follows.',
},
{
question: 'Do the components require JavaScript?',
answer:
'Most do not. Sections, cards, tables, forms and layout primitives render entirely on the server. Only overlays, menus and the command palette are client islands.',
},
{
question: 'What does the density axis actually change?',
answer:
'Control heights, control padding, stack rhythm, card padding, table row height and section padding. It deliberately does not change the type scale, so text stays legible at every density.',
},
{
question: 'Can I use only part of the library?',
answer:
'Yes. Each block is a standalone file whose imports are visible in the code viewer. Copying one section brings the primitives it names and nothing else.',
},
{
question: 'How is the source in the documentation kept accurate?',
answer:
'A build step reads the real files from disk and generates the source registry. The preview and the code you copy come from the same file, and a test fails if the two ever diverge.',
},
{
question: 'Is there a Figma library?',
answer:
'The token manifest is designed to be exported to Figma variables, but no Figma file ships with this demo.',
},
{
question: 'What browsers are supported?',
answer:
'Current versions of Chrome, Edge, Safari and Firefox. The library uses container-free responsive CSS and standard custom properties throughout.',
},
]
export interface TeamMember {
name: string
role: string
bio: string
location: string
}
export const team: TeamMember[] = [
{
name: 'Priya Raman',
role: 'Design systems',
bio: 'Spent six years untangling component libraries before deciding to write one properly.',
location: 'Bengaluru',
},
{
name: 'Tomas Lindqvist',
role: 'Accessibility',
bio: 'Audits by day, writes focus-management utilities by night.',
location: 'Stockholm',
},
{
name: 'Amara Osei',
role: 'Frontend architecture',
bio: 'Believes most performance problems are really architecture problems.',
location: 'Accra',
},
{
name: 'Jun Watanabe',
role: 'Product',
bio: 'Turns "we should document this" into things that are actually documented.',
location: 'Osaka',
},
{
name: 'Elena Rossi',
role: 'Visual design',
bio: 'Editorial background; still measures leading by eye and is usually right.',
location: 'Milan',
},
{
name: 'Marcus Bell',
role: 'Developer experience',
bio: 'Optimises for the twentieth time you use something, not the first.',
location: 'Manchester',
},
{
name: 'Sofia Delgado',
role: 'Documentation',
bio: 'Thinks a component without a usage note is only half shipped.',
location: 'Madrid',
},
{
name: 'Idris Karim',
role: 'Infrastructure',
bio: 'Keeps the build under a minute so nobody is tempted to skip it.',
location: 'Toronto',
},
]
export interface ProcessStep {
title: string
description: string
duration?: string
}
export const processSteps: ProcessStep[] = [
{
title: 'Audit',
description:
'Inventory every surface, control and one-off in the existing product. Nothing is designed before the mess is measured.',
duration: 'Week 1–2',
},
{
title: 'Tokenise',
description:
'Extract the real colour, type and spacing decisions into a token set the whole team can read.',
duration: 'Week 3',
},
{
title: 'Build primitives',
description:
'Ship the twenty components that account for eighty per cent of screens, with states and keyboard contracts.',
duration: 'Week 4–7',
},
{
title: 'Compose',
description:
'Assemble sections and page patterns, then migrate a real route to prove the system holds.',
duration: 'Week 8–10',
},
{
title: 'Document',
description:
'Write the usage guidance while the decisions are fresh, and wire the docs to the source.',
duration: 'Week 11',
},
{
title: 'Hand over',
description:
'Contribution guide, review checklist, and a session on how to add the twenty-first component.',
duration: 'Week 12',
},
]
export interface TimelineEvent {
year: string
title: string
description: string
}
export const timelineEvents: TimelineEvent[] = [
{
year: '2021',
title: 'One repository, four libraries',
description:
'Four product teams, four component sets, four opinions about what "medium" meant.',
},
{
year: '2022',
title: 'The first token pass',
description: 'Colour and spacing consolidated. Everything else stayed where it was.',
},
{
year: '2023',
title: 'Primitives extracted',
description:
'Twenty components, one focus treatment, one control height. Adoption became easier than resistance.',
},
{
year: '2024',
title: 'Sections and patterns',
description: 'Marketing stopped rebuilding heroes and started composing them.',
},
{
year: '2025',
title: 'Density as an axis',
description: 'Admin tools and marketing pages finally shared a component set.',
},
{
year: '2026',
title: 'Foundry 1.0',
description: 'Four levels, one system, documented against its own source.',
},
]
export interface CaseStudy {
slug: string
client: string
title: string
summary: string
sector: string
year: string
metrics: Array<{ label: string; value: string }>
}
export const caseStudies: CaseStudy[] = [
{
slug: 'northwind-console',
client: 'Northwind',
title: 'One console for eleven internal tools',
summary:
'Eleven admin surfaces, each with its own table implementation, consolidated into a single shell with a shared data layer.',
sector: 'Logistics',
year: '2025',
metrics: [
{ label: 'Tools consolidated', value: '11' },
{ label: 'Bundle reduction', value: '61%' },
{ label: 'Time to new screen', value: '2 days' },
],
},
{
slug: 'halcyon-storefront',
client: 'Halcyon',
title: 'A storefront that loads on a train',
summary:
'Rebuilt a client-rendered catalogue as server components with small islands, targeting the worst connection the team could find.',
sector: 'Retail',
year: '2025',
metrics: [
{ label: 'JS shipped', value: '−78%' },
{ label: 'LCP, 3G', value: '1.4s' },
{ label: 'Conversion', value: '+9%' },
],
},
{
slug: 'meridian-docs',
client: 'Meridian',
title: 'Documentation that cannot go stale',
summary:
'Wired the documentation site to the component source so every example is generated from the file it documents.',
sector: 'Developer tools',
year: '2024',
metrics: [
{ label: 'Stale examples', value: '0' },
{ label: 'Docs PRs / month', value: '×3' },
{ label: 'Support tickets', value: '−34%' },
],
},
{
slug: 'kestrel-onboarding',
client: 'Kestrel',
title: 'Onboarding in four steps instead of nine',
summary:
'Reduced a nine-screen signup to four, with real validation, resumable progress and a working keyboard path throughout.',
sector: 'Fintech',
year: '2024',
metrics: [
{ label: 'Steps removed', value: '5' },
{ label: 'Completion', value: '+27%' },
{ label: 'Support contacts', value: '−41%' },
],
},
{
slug: 'lumen-rebrand',
client: 'Lumen Works',
title: 'A rebrand in one pull request',
summary:
'Because every surface resolved from tokens, a full visual rebrand touched one file and shipped in a single review.',
sector: 'Media',
year: '2023',
metrics: [
{ label: 'Files changed', value: '1' },
{ label: 'Screens updated', value: '240+' },
{ label: 'Regressions', value: '0' },
],
},
]
export interface Post {
slug: string
title: string
excerpt: string
category: string
date: string
readingTime: string
author: string
}
export const posts: Post[] = [
{
slug: 'density-as-an-axis',
title: 'Density belongs in your token system',
excerpt:
'Most design systems treat compact mode as a table prop. Making it a theme axis is what finally lets admin tools and marketing pages share components.',
category: 'Design systems',
date: '2026-03-12',
readingTime: '8 min',
author: 'Priya Raman',
},
{
slug: 'manual-tab-activation',
title: 'Why your tabs should not auto-activate',
excerpt:
'Automatic activation feels responsive and quietly punishes keyboard users. A short argument for the boring default.',
category: 'Accessibility',
date: '2026-02-27',
readingTime: '6 min',
author: 'Tomas Lindqvist',
},
{
slug: 'documentation-from-source',
title: 'Generate documentation from the file, not about it',
excerpt:
'A build step that reads the real component and a test that fails on drift removes an entire category of wrong documentation.',
category: 'Tooling',
date: '2026-02-09',
readingTime: '5 min',
author: 'Sofia Delgado',
},
{
slug: 'server-components-marketing',
title: 'Marketing pages do not need a framework runtime',
excerpt:
'What actually needs to be interactive on a landing page, and how small the remaining island can be.',
category: 'Performance',
date: '2026-01-22',
readingTime: '9 min',
author: 'Amara Osei',
},
{
slug: 'variants-that-earn-their-place',
title: 'A variant should represent a decision, not a padding value',
excerpt:
'How to tell a real variant from an inflated catalogue, and why one hundred good components beat three hundred similar ones.',
category: 'Design systems',
date: '2026-01-08',
readingTime: '7 min',
author: 'Elena Rossi',
},
{
slug: 'focus-return',
title: 'The half of focus management everyone forgets',
excerpt:
'Trapping focus in a dialog is the easy part. Putting it back where it came from is what keyboard users actually notice.',
category: 'Accessibility',
date: '2025-12-15',
readingTime: '4 min',
author: 'Tomas Lindqvist',
},
]
export interface Integration {
name: string
category: string
description: string
}
export const integrations: Integration[] = [
{
name: 'Vector',
category: 'Analytics',
description: 'Event streaming with a typed schema registry.',
},
{
name: 'Cinder',
category: 'Monitoring',
description: 'Traces, logs and alerts in one timeline.',
},
{
name: 'Postmark',
category: 'Email',
description: 'Transactional delivery with per-template metrics.',
},
{ name: 'Harbour', category: 'Storage', description: 'Object storage with signed upload URLs.' },
{
name: 'Sentinel',
category: 'Security',
description: 'Dependency and secret scanning on every push.',
},
{ name: 'Ledger', category: 'Billing', description: 'Usage metering and invoice generation.' },
{
name: 'Relay',
category: 'Messaging',
description: 'Webhooks with automatic retry and replay.',
},
{
name: 'Atlas',
category: 'Search',
description: 'Typo-tolerant search with faceted filtering.',
},
{ name: 'Beacon', category: 'Support', description: 'Shared inbox with conversation routing.' },
{ name: 'Quarry', category: 'Data', description: 'Warehouse sync with incremental models.' },
{ name: 'Pilot', category: 'Deployment', description: 'Preview environments per pull request.' },
{ name: 'Lantern', category: 'Documentation', description: 'Docs generated from typed schemas.' },
]
export interface Product {
slug: string
name: string
category: string
priceCents: number
compareAtCents?: number
description: string
material: string
badge?: string
inStock: boolean
rating: number
reviews: number
}
export const products: Product[] = [
{
slug: 'field-shell-jacket',
name: 'Field Shell Jacket',
category: 'outerwear',
priceCents: 32800,
compareAtCents: 41000,
description:
'A three-layer shell cut close enough to wear in a city and sealed well enough not to.',
material: 'Recycled ripstop',
badge: 'Last season pricing',
inStock: true,
rating: 4.7,
reviews: 214,
},
{
slug: 'quarry-overshirt',
name: 'Quarry Overshirt',
category: 'outerwear',
priceCents: 18500,
description: 'Heavyweight cotton twill that behaves like a jacket and packs like a shirt.',
material: 'Organic cotton twill',
inStock: true,
rating: 4.5,
reviews: 132,
},
{
slug: 'meridian-knit',
name: 'Meridian Merino Knit',
category: 'knitwear',
priceCents: 14900,
description: 'Fine-gauge merino with a high neck and no branding anywhere on it.',
material: 'Extrafine merino',
badge: 'Restocked',
inStock: true,
rating: 4.8,
reviews: 341,
},
{
slug: 'harbour-cardigan',
name: 'Harbour Cardigan',
category: 'knitwear',
priceCents: 21000,
description: 'A boxy cardigan with horn buttons and a shawl collar that holds its shape.',
material: 'Lambswool',
inStock: false,
rating: 4.4,
reviews: 88,
},
{
slug: 'atlas-chino',
name: 'Atlas Chino',
category: 'trousers',
priceCents: 12800,
compareAtCents: 15900,
description: 'A straight-leg chino with a proper waistband and pockets that hold a phone.',
material: 'Compact cotton',
inStock: true,
rating: 4.6,
reviews: 507,
},
{
slug: 'ironwood-trouser',
name: 'Ironwood Wool Trouser',
category: 'trousers',
priceCents: 24500,
description: 'Pleated, cuffed, and cut for people who sit down during the day.',
material: 'Wool flannel',
inStock: true,
rating: 4.3,
reviews: 76,
},
{
slug: 'lumen-tote',
name: 'Lumen Tote',
category: 'accessories',
priceCents: 9800,
description: 'Waxed canvas with a leather base and a strap long enough for a coat.',
material: 'Waxed canvas',
badge: 'Best seller',
inStock: true,
rating: 4.9,
reviews: 623,
},
{
slug: 'kestrel-cap',
name: 'Kestrel Six-Panel Cap',
category: 'accessories',
priceCents: 5200,
description: 'Unstructured, cotton-lined, with a brim that survives being sat on.',
material: 'Cotton canvas',
inStock: true,
rating: 4.2,
reviews: 195,
},
{
slug: 'verdant-tee',
name: 'Verdant Heavy Tee',
category: 'basics',
priceCents: 4800,
description: 'A 240gsm tee that holds its collar past the first wash.',
material: 'Organic cotton',
inStock: true,
rating: 4.6,
reviews: 1102,
},
{
slug: 'halcyon-socks',
name: 'Halcyon Ribbed Socks',
category: 'basics',
priceCents: 2200,
description: 'Three pairs. Ribbed, reinforced, and the same length as each other.',
material: 'Merino blend',
inStock: true,
rating: 4.5,
reviews: 289,
},
]
export const productCategories = [
{ slug: 'outerwear', name: 'Outerwear', description: 'Shells, overshirts and coats.' },
{ slug: 'knitwear', name: 'Knitwear', description: 'Merino, lambswool and cotton knits.' },
{ slug: 'trousers', name: 'Trousers', description: 'Chinos, wool and workwear cuts.' },
{ slug: 'accessories', name: 'Accessories', description: 'Bags, caps and small goods.' },
{ slug: 'basics', name: 'Basics', description: 'Tees, socks and everyday layers.' },
]
export interface MenuDish {
name: string
description: string
price: string
tags?: string[]
}
export interface MenuCourse {
course: string
note?: string
dishes: MenuDish[]
}
export const restaurantMenu: MenuCourse[] = [
{
course: 'To begin',
note: 'Served from opening until close.',
dishes: [
{
name: 'Cured trout, fennel, dill oil',
description: 'Two-day cure, shaved fennel, dill pressed the same morning.',
price: '16',
tags: ['GF'],
},
{
name: 'Charred leek, hazelnut, aged sheep cheese',
description: 'Leeks over embers until the outer layer gives up entirely.',
price: '14',
tags: ['V'],
},
{
name: 'Sourdough, cultured butter',
description: 'Four-day starter, butter churned in-house on Tuesdays.',
price: '7',
tags: ['V'],
},
],
},
{
course: 'Mains',
dishes: [
{
name: 'Aged duck breast, quince, bitter leaves',
description: 'Dry-aged fourteen days, quince from the orchard at Ashfield.',
price: '34',
},
{
name: 'Turbot on the bone, brown butter, capers',
description: 'Whole fish for two, carved at the table.',
price: '58',
tags: ['For two'],
},
{
name: 'Barley, wild mushroom, preserved lemon',
description: 'Slow-cooked barley with a mushroom broth reduced for six hours.',
price: '26',
tags: ['V', 'Vegan on request'],
},
],
},
{
course: 'To finish',
dishes: [
{
name: 'Burnt honey tart, crème fraîche',
description: 'Honey taken just past the point most people would stop.',
price: '12',
tags: ['V'],
},
{
name: 'Poached pear, walnut, blue cheese',
description: 'Pears poached in the last of the autumn cider.',
price: '13',
tags: ['V'],
},
{
name: 'Selection of British cheese',
description: 'Three cheeses, oat crackers, quince paste.',
price: '16',
tags: ['V'],
},
],
},
]
export const changelog = [
{
version: '1.0.0',
date: '2026-03-14',
title: 'Foundry 1.0',
summary:
'The first complete release: four composition levels, one token system, one catalogue.',
changes: [
{
kind: 'added' as const,
text: '45 primitives across actions, forms, feedback, overlay, navigation, data and layout.',
},
{
kind: 'added' as const,
text: '15 navigation patterns, 12 header systems and 10 footer systems.',
},
{
kind: 'added' as const,
text: '28 form flows with real validation, first-invalid focus and live error announcement.',
},
{
kind: 'added' as const,
text: '112 sections spanning marketing, commerce, SaaS, content, application and state.',
},
{
kind: 'added' as const,
text: '10 complete page patterns and 10 multi-route starter products.',
},
{
kind: 'added' as const,
text: 'Theme playground with five palettes and three densities, persisted and flash-free.',
},
],
},
{
version: '0.9.0',
date: '2026-02-20',
title: 'Starters and the composition playground',
summary: 'Level 4 arrives, and sections become assemblable rather than merely browsable.',
changes: [
{
kind: 'added' as const,
text: 'Ten starter products, each with working navigation and its own 404 path.',
},
{ kind: 'added' as const, text: 'URL-driven section composition playground.' },
{
kind: 'changed' as const,
text: 'Catalogue records gained `relatedItems`, validated to resolve.',
},
{
kind: 'fixed' as const,
text: 'Drawer no longer restored focus to a detached element after route changes.',
},
],
},
{
version: '0.8.0',
date: '2026-01-30',
title: 'Density becomes an axis',
summary: 'Compact, Default and Relaxed move out of component props and into the token layer.',
changes: [
{
kind: 'added' as const,
text: 'Density tokens for control height, padding, stack rhythm and row height.',
},
{
kind: 'changed' as const,
text: 'Every control now derives its height from `--density-control-height`.',
},
{
kind: 'removed' as const,
text: 'Per-component `compact` props, superseded by the density axis.',
},
],
},
{
version: '0.7.0',
date: '2026-01-12',
title: 'Source registry',
summary: 'Documentation is generated from the files it documents.',
changes: [
{
kind: 'added' as const,
text: 'Build-time source registry; the viewer reads the real file.',
},
{
kind: 'added' as const,
text: 'Drift test that regenerates the registry and fails on mismatch.',
},
{
kind: 'fixed' as const,
text: 'Copy button now falls back to a hidden textarea on insecure origins.',
},
],
},
{
version: '0.6.0',
date: '2025-12-04',
title: 'Accessibility pass',
summary: 'Focus management and live regions moved into the primitives.',
changes: [
{
kind: 'added' as const,
text: 'Focus trap with guaranteed focus return across Dialog, Drawer and the palette.',
},
{ kind: 'changed' as const, text: 'Tabs switched to manual activation.' },
{ kind: 'fixed' as const, text: 'Tooltips now open on keyboard focus, not only on hover.' },
{
kind: 'fixed' as const,
text: 'Toast queue announces in order instead of interrupting itself.',
},
],
},
]
export const faqShort = faqs.slice(0, 4)
Demo source — adapt to your project. Foundry is not published as a package.
Usage
On a page that already has several card sections, a divided band is the quieter choice and reads as fact rather than as another module.
- Give each figure a one-line detail; a bare number invites the question it should answer.
- Four figures. A fifth breaks the column rhythm at every breakpoint.
Variants and states
Every entry below is a genuine difference in behaviour or layout, and every one of them is visible in the preview above.
- Four columns at lg
- Two at sm
- Rule dividers
Accessibility
- Definition list
- Value and label are paired programmatically.
- Tabular figures
- Numerals align so the row does not shimmer between palettes.
Foundry implements published ARIA patterns and is tested against them. No WCAG certification is claimed — see the accessibility documentation for what is and is not covered.
Related
All sectionsInverted statistics panel
A dark band of four derived figures, used as punctuation between light sections.
starter3 variantsHero with statistics band
A claim above a four-figure band, with every figure read from the live catalogue.
starterFeatured3 variantsInline proof line
One sentence with the figures set inside it.
starter3 variants