Running text: a paragraph of the argument, the lede under a title, a small print line or the closing line of a page.

Atom · stable · v1.0.0 · owner: Site system lead · contract 19 of 20 points (open: figma)

Do and don't

Do: A lede

Rendered by text.ts

Open example: Text · Do: A lede Use the full-page example to follow page links.

The promise, in one sentence.

Do: A body paragraph

Rendered by text.ts

Open example: Text · Do: A body paragraph Use the full-page example to follow page links.

Plain words, one idea.

Don't: Hype

Rendered by text.ts

Open example: Text · Don't: Hype Use the full-page example to follow page links.

The glossary forbids 'revolutionary' and 'supercharge': they promise without saying anything.

Don't: A wall of text

Rendered by text.ts

Open example: Text · Don't: A wall of text Use the full-page example to follow page links.

Paragraphs of more than four sentences lose readers; split them.

Rules

RuleWhyCheck
Lines are at most 70 characters.Longer lines make the eye lose its place on the way back.Automated: brand gate (--w-text on .prose)
Copy follows the voice rules and the glossary.One voice is part of the brand, and forbidden terms are promises we cannot keep.Automated: glossary checker over site copy (apps/showcase/site/loom/content)

API

PropTypeRequiredDefaultWhat it does
kindbody | lede | small | note | closingNo"body"Which text role.
htmlhtmlYesThe paragraph's inline HTML (links, emphasis, code).

Contract details

The full contract: identity, anatomy, variants, states, tokens, layout, motion, accessibility, content, tests

Identity

AspectValue
Idtext
LayerAtoms
Categorytypography
OwnerSite system lead
Statusstable
Version1.0.0
Sourceapps/showcase/site/system/atoms/text.ts (private repository; the contract and the render function are this one module)
VersionDateChange
1.0.02026-10-26Body, lede, small, note and closing paragraphs in Atkinson Hyperlegible Next.

Use when

  • Any paragraph of copy. Why: One text style at one measure keeps every page as easy to read as the best one.
  • The lede that states a page's promise. Why: A larger first paragraph lets a skimming reader get the point in one line.

Do not use when

  • To label a figure or name its data. Why: That is the caption's job, with its honesty rule.
  • For a step count above a heading. Why: That is the eyebrow.

Anatomy

PartWhat it is
rootp, or p.lede / p.small / p.note-small / p.closing.

Made of: tokens:type, tokens:colour, tokens:layout.

Used in: callout, form-field, stat, table, contact-form, facts-list, faq-list, jobs-strip, panel, roles-grid, rows-list, showcase-frame, status-table, task-footer, tile, cta-section, flow-section, founder-section, hero, job-section, lead-section, page-head, problem-section, proof-section, prose-section, roadmap-strip, roles-section, tile-grid, titled-section.

Variants

VariantWhenWhy
bodyParagraphs.16 to 18 px at 1.6 line height, at most 70 characters a line.
ledeThe first paragraph of a page or section head.It states the promise in a size that is read first.
smallSecondary notes and footnotes.Present but quiet.
closingThe last line of a page.A rule above it marks the end of the argument.

States

StateRendered or not applicable
defaultdefault
hoverNot applicable: A paragraph is not interactive, so it has no hover state.
focus-visibleNot applicable: A paragraph does not take focus; links and buttons inside it carry their own focus ring.
activeNot applicable: A paragraph cannot be pressed.
disabledNot applicable: A paragraph has nothing to disable.
loadingNot applicable: A paragraph is rendered at build time and is complete when the page loads.
emptyNot applicable: A paragraph is not rendered without content; the builder skips it.
errorNot applicable: A paragraph shows no data that can fail.
currentNot applicable: A paragraph has no current item.
visitedNot applicable: A paragraph is not a link.
expandedNot applicable: A paragraph does not open or close.

Tokens

PartToken
body.font--type-body
lede.font--type-lede
small.font--type-small
root.color--ink; --ink-2 for small; field text on fields
root.max-width--w-text (70ch)
--text-font-type-ledevar(--type-lede)
--text-letter-spacing-ls-ledevar(--ls-lede)
--text-font-type-smallvar(--type-small)
--text-color-ink-2var(--ink-2)
--text-color-inkvar(--ink)
--text-padding-space-4var(--space-4)
--text-padding-space-5var(--space-5)
--text-border-bottom-rule-hairvar(--rule-hair)
--text-border-bottom-linevar(--line)
--text-border-bottom-rulevar(--rule)
--text-border-bottom-inkvar(--ink)
--text-font-weight-weight-strongvar(--weight-strong)
--text-margin-top-space-6var(--space-6)
--text-margin-top-space-12var(--space-12)
--text-max-width-w-textvar(--w-text)
--text-margin-top-space-10var(--space-10)
--text-font-type-h3var(--type-h3)
--text-letter-spacing-ls-h3var(--ls-h3)
--text-margin-top-space-5var(--space-5)
--text-padding-left-space-7var(--space-7)
--text-margin-top-space-7var(--space-7)
--text-padding-left-space-8var(--space-8)
--text-margin-top-space-3var(--space-3)
--text-color-indigo-inkvar(--indigo-ink)
--text-font-size-fs-labelvar(--fs-label)
--text-padding-space-6var(--space-6)
--text-border-top-rulevar(--rule)
--text-border-top-inkvar(--ink)
--text-background-surface-2var(--surface-2)
--text-padding-space-3var(--space-3)
--text-border-radius-radiusvar(--radius)
--text-background-term-bgvar(--term-bg)
--text-color-term-fgvar(--term-fg)
--text-padding-space-7var(--space-7)
--text-font-size-fs-smallvar(--fs-small)
--text-margin-space-11var(--space-11)
--text-background-inkvar(--ink)
--text-margin-bottom-space-6var(--space-6)
--text-color-cottonvar(--cotton)
--text-margin-top-sectionvar(--section)
--text-padding-top-space-8var(--space-8)
--text-border-top-rule-framevar(--rule-frame)
--text-font-type-h2var(--type-h2)
--text-letter-spacing-ls-h2var(--ls-h2)
--text-margin-top-space-11var(--space-11)
--text-margin-top-space-13var(--space-13)
--text-padding-top-space-7var(--space-7)
--text-border-top-rule-heavyvar(--rule-heavy)
--text-font-size-fs-h2var(--fs-h2)
--text-border-top-saffronvar(--saffron)
--text-margin-top-space-9var(--space-9)
--text-margin-bottom-space-4var(--space-4)
--text-font-size-fs-h3var(--fs-h3)
--text-font-type-figurevar(--type-figure)
--text-margin-space-4var(--space-4)
--text-font-type-labelvar(--type-label)
--text-color-field-fg-2var(--field-fg-2)
--text-color-threadvar(--thread)
--text-border-top-threadvar(--thread)

Layout

AspectValue
max70 characters (--w-text)
breakpointsRequired review at 390, 768, 1024 and 1440 px; execution is not implied by this declaration; sizes are fluid from 16 to 18 px.
wrappingtext-wrap: pretty; Japanese breaks with line-break strict.
textExpansionNo fixed heights anywhere, so 40% longer pseudo-localised text simply adds lines.

Spacing and rhythm

AspectValue
internalLine height 1.6 (body), 1.4 (lede).
external--space-6 between paragraphs.
rhythmInside a section's copy column.

Motion

AspectValue
NoneText is read, not watched.

Runtime and reuse

  1. Render-only element; mount any registered child enhancements separately. Preserve required Site CSS, fonts, responsive and locale rules from nativeElement.

Accessibility passport

AspectValue
roleparagraph
nameNone needed
keyboardNot interactive.
focusNot focusable.
screenReaderRead in order.
contrastInk on cotton 15.9:1; --ink-2 8.6:1; field text 7:1 or better.
targetNot a target.

Content

SlotLengthVoice
html4 sentences per paragraphPlain words, short sentences, British spelling, no hype (voice rules in apps/showcase/site/loom/content)

Good: “A design system lasts when the organisation knows how to run it.”

Bad: “Our cutting-edge AI-powered platform revolutionises design.”

Japanese: Text comes from the page content; Japanese strings are reviewed per page (apps/showcase/site/loom/locales). Awaiting native review, as the banner on every Japanese page says.

Icons and illustrations

None: this element uses no icon or illustration of its own.

Decisions and exceptions

Usage

236 uses across the built pages (measured by npm run site:system).

Tests

AspectValue
unittests/unit/site-system.test.ts: renders every do and don't example through the registry and checks the classes it owns
visualNot yet: there are no screenshot baselines; the Library page is checked for sideways scroll at 1440 px by tests/site/system.spec.ts
a11ytests/site/system.spec.ts: axe (0 serious or critical) on the element's Library page in light and dark
parityscripts/site/system/check.ts: Library examples are rendered by the same render function the site imports

Figma

not-yet: The Loom Site Figma library is the last stage of the plan; this element is not mapped yet.

Open in Storybook

Start with a conversation about your system.

We read your system, show you what we found, and agree with your team what to fix first.