01
Components.
The parts every page is built from, live. Scroll to see them move; switch theme to see the same part in another initiative's look.
02Live
The expressive parts.
Each is shown on a ground it belongs on, with its entry from KIT.md beneath. Every one finishes in its end state with reduced motion or the motion toggle on.
Initiatives assemble from proven parts and build only the slice that sets them apart.
Filling lead (7.24): <FillLead text="..." />
Filling lead (7.24): <FillLead text="..." />
A v2-lead whose words fill grey to ink as it is read, finishing as its last line
reaches 30% from the top. One per band, on paper or mist. Motion off: ink.
Built once, inherited by every initiative.
Typed line (7.33): <TypedLine text="..." />, v2-typed
Typed line (7.33): <TypedLine text="..." />, v2-typed
A short line, a tagline or a strapline, that types itself in character by character with a
caret (v2-typed-w holds each word's characters; v2-typed-sr carries the real text for
screen readers). Inside a pin pass w={{ a, b }} to type across that slice of the pin; on its
own it scrubs itself as it crosses the screen, like a filling lead; load (v2-typed-load)
types it once on arrival, for a hero line (never the H1). Use it for lines of a few words: a
paragraph should fill (<FillLead>), not type. Finished with motion off, reduced motion and
no script. Added for the Hub (Gideon, 8 October 2026: a page of words needs to feel alive).
The initiative designs what makes it different.
Statement (7.29): v2-statement, v2-mark
Statement (7.29): v2-statement, v2-mark
Section 5 above.
spec to shipsignal to scale
Strike and replace (7.31): v2-sr, v2-sr-from, v2-sr-to
Strike and replace (7.31): v2-sr, v2-sr-from, v2-sr-to
One claim struck through and its replacement rising beneath, at the statement size. Put
a scrub on the parent (data-scrub="drift" in a normal band; a pin's own progress inside
a pin) and a v2-seg window on each line; the replacement also takes v2-rise. On ink
and forest the bar and the replacement are house green; on light grounds both are ink.
<p className="v2-sr" data-scrub="drift">
<s className="v2-sr-from v2-seg" style={{ "--a": 0.22, "--b": 0.42 } as CSSProperties}>from building software</s>
<span className="v2-sr-to v2-seg v2-rise" style={{ "--a": 0.34, "--b": 0.52 } as CSSProperties}>to building the right solution</span>
</p>
Use <s>: the struck claim is no longer accurate, which is what the element means.
Act, think and sense.
Named and lit (7.32): v2-lit, v2-lit-fill
Named and lit (7.32): v2-lit, v2-lit-fill
When a line names a part of the picture, the part turns house green as the line is read.
Give the part v2-seg with the same window as its line. v2-lit turns text green (ink
and forest only; set --lit-from for the colour it starts from, default the label
colour). v2-lit-fill lights a chip or box as a fill, on any ground: green behind, ink on
it, the border following. At rest, finished, every named part is lit. A 5Di part lights in
the second highlight: set --lit-to: var(--house-2) on it (rulebook, "The second
highlight").
Put the line where the eye is. The reader watches the part that is changing, so its line goes beside or directly under it, never across the stage. Mark the part being named (the Foundry's chapter 02 uses a second green bar along the cell's foot) until the next.
123
UI components
158
capabilities
9
boxes
Stat row (7.27): <Stat value label>, v2-stats, v2-stats-5, v2-stat, v2-stat-n, v2-stat-l
Stat row (7.27): <Stat value label>, v2-stats, v2-stats-5, v2-stat, v2-stat-n, v2-stat-l
Space Mono numerals that count up once at the trigger line; the final value is in the
HTML. Four up, or five with v2-stats-5. Phones: two up.
Pill CTA (7.22): <Pill href>
Pill CTA (7.22): <Pill href>
The one primary action. v2-pill, v2-pill-label, v2-pill-ring. A house green pill, ink
text, the label and a ringed arrow side by side; the arrow nudges forward on hover or focus
and the pill gives on press. Ink on house green. Any ground. For a pill that is a <button>
(a play control), use the classes on the button and <PillRing> with your own glyph in a
74 by 74 box. Redrawn 10 October 2026 (Gideon), from a Uiverse button by alexmaracinaru; it
replaced the detached arrow that jumped across.
Burst (7.34): <Burst />, v2-burst
Burst (7.34): <Burst />, v2-burst
A small ornament: eight rays of three dots around an empty centre, house green. Sized by
font-size (it is 1em across), coloured by --burst (house green by default). On ink and
forest it may sit anywhere as a mark; on a light ground green is a fill only, so keep it a
decoration there, never the thing that carries meaning. On house green (g-house) it takes
ink, as the mark inverts there. It is its own .reveal, so wherever it sits it builds as it
reaches the trigger line: ring by ring from the centre out, each dot travelling out along its
ray, overshooting and falling back to the static shape (23 October 2026). No wrapper needed.
Added 10 October 2026 (Gideon).
Icon (rulebook 8): <Icon name>, v2-icon
Icon (rulebook 8): <Icon name>, v2-icon
Material Symbols Outlined, weight 300, from the approved subset in rulebook section 8 and
nothing else; ICONS holds the paths, IconName the names. Sizes 16, 20, 24 or 40, colour
currentColor, so it takes the text colour of whatever it sits in. Beside a label it is
aria-hidden; an icon on its own takes label, which becomes its accessible name. Gap to
its text: 8px at 16, 10px at 20, 12px at 24. A site lays out the icon and its text itself.
Moved into the kit 25 October 2026; hubiq.co.uk's StageIcon predates it and draws the same
four stage paths.
ATOMIQSITEIQMEDIQTENANTIQTRAFFIQ
Initiative names: v2-iname, v2-iq
Initiative names: v2-iname, v2-iq
A name as stem plus IQ: <span className="v2-iname">TENANT<span className="v2-iq">IQ</span></span>.
The IQ takes --ac only on ink or on hover.
The lattice builds from the base.
Lattice (7.26): <Lattice />, v2-lattice, v2-lattice-band
Lattice (7.26): <Lattice />, v2-lattice, v2-lattice-band
House green on a light ground as light: a dot field building from its base on scroll. On
the closing call only: <section className="v2-band g-grey-deep v2-lattice-band"> with
<Lattice /> first.
Initiatives assemble from proven parts and build only the slice that sets them apart.
Filling lead (7.24): <FillLead text="..." />
Filling lead (7.24): <FillLead text="..." />
A v2-lead whose words fill grey to ink as it is read, finishing as its last line
reaches 30% from the top. One per band, on paper or mist. Motion off: ink.
Built once, inherited by every initiative.
Typed line (7.33): <TypedLine text="..." />, v2-typed
Typed line (7.33): <TypedLine text="..." />, v2-typed
A short line, a tagline or a strapline, that types itself in character by character with a
caret (v2-typed-w holds each word's characters; v2-typed-sr carries the real text for
screen readers). Inside a pin pass w={{ a, b }} to type across that slice of the pin; on its
own it scrubs itself as it crosses the screen, like a filling lead; load (v2-typed-load)
types it once on arrival, for a hero line (never the H1). Use it for lines of a few words: a
paragraph should fill (<FillLead>), not type. Finished with motion off, reduced motion and
no script. Added for the Hub (Gideon, 8 October 2026: a page of words needs to feel alive).
The initiative designs what makes it different.
Statement (7.29): v2-statement, v2-mark
Statement (7.29): v2-statement, v2-mark
Section 5 above.
spec to shipsignal to scale
Strike and replace (7.31): v2-sr, v2-sr-from, v2-sr-to
Strike and replace (7.31): v2-sr, v2-sr-from, v2-sr-to
One claim struck through and its replacement rising beneath, at the statement size. Put
a scrub on the parent (data-scrub="drift" in a normal band; a pin's own progress inside
a pin) and a v2-seg window on each line; the replacement also takes v2-rise. On ink
and forest the bar and the replacement are house green; on light grounds both are ink.
<p className="v2-sr" data-scrub="drift">
<s className="v2-sr-from v2-seg" style={{ "--a": 0.22, "--b": 0.42 } as CSSProperties}>from building software</s>
<span className="v2-sr-to v2-seg v2-rise" style={{ "--a": 0.34, "--b": 0.52 } as CSSProperties}>to building the right solution</span>
</p>
Use <s>: the struck claim is no longer accurate, which is what the element means.
Act, think and sense.
Named and lit (7.32): v2-lit, v2-lit-fill
Named and lit (7.32): v2-lit, v2-lit-fill
When a line names a part of the picture, the part turns house green as the line is read.
Give the part v2-seg with the same window as its line. v2-lit turns text green (ink
and forest only; set --lit-from for the colour it starts from, default the label
colour). v2-lit-fill lights a chip or box as a fill, on any ground: green behind, ink on
it, the border following. At rest, finished, every named part is lit. A 5Di part lights in
the second highlight: set --lit-to: var(--house-2) on it (rulebook, "The second
highlight").
Put the line where the eye is. The reader watches the part that is changing, so its line goes beside or directly under it, never across the stage. Mark the part being named (the Foundry's chapter 02 uses a second green bar along the cell's foot) until the next.
123
UI components
158
capabilities
9
boxes
Stat row (7.27): <Stat value label>, v2-stats, v2-stats-5, v2-stat, v2-stat-n, v2-stat-l
Stat row (7.27): <Stat value label>, v2-stats, v2-stats-5, v2-stat, v2-stat-n, v2-stat-l
Space Mono numerals that count up once at the trigger line; the final value is in the
HTML. Four up, or five with v2-stats-5. Phones: two up.
Pill CTA (7.22): <Pill href>
Pill CTA (7.22): <Pill href>
The one primary action. v2-pill, v2-pill-label, v2-pill-ring. A house green pill, ink
text, the label and a ringed arrow side by side; the arrow nudges forward on hover or focus
and the pill gives on press. Ink on house green. Any ground. For a pill that is a <button>
(a play control), use the classes on the button and <PillRing> with your own glyph in a
74 by 74 box. Redrawn 10 October 2026 (Gideon), from a Uiverse button by alexmaracinaru; it
replaced the detached arrow that jumped across.
Burst (7.34): <Burst />, v2-burst
Burst (7.34): <Burst />, v2-burst
A small ornament: eight rays of three dots around an empty centre, house green. Sized by
font-size (it is 1em across), coloured by --burst (house green by default). On ink and
forest it may sit anywhere as a mark; on a light ground green is a fill only, so keep it a
decoration there, never the thing that carries meaning. On house green (g-house) it takes
ink, as the mark inverts there. It is its own .reveal, so wherever it sits it builds as it
reaches the trigger line: ring by ring from the centre out, each dot travelling out along its
ray, overshooting and falling back to the static shape (23 October 2026). No wrapper needed.
Added 10 October 2026 (Gideon).
Icon (rulebook 8): <Icon name>, v2-icon
Icon (rulebook 8): <Icon name>, v2-icon
Material Symbols Outlined, weight 300, from the approved subset in rulebook section 8 and
nothing else; ICONS holds the paths, IconName the names. Sizes 16, 20, 24 or 40, colour
currentColor, so it takes the text colour of whatever it sits in. Beside a label it is
aria-hidden; an icon on its own takes label, which becomes its accessible name. Gap to
its text: 8px at 16, 10px at 20, 12px at 24. A site lays out the icon and its text itself.
Moved into the kit 25 October 2026; hubiq.co.uk's StageIcon predates it and draws the same
four stage paths.
ATOMIQSITEIQMEDIQTENANTIQTRAFFIQ
Initiative names: v2-iname, v2-iq
Initiative names: v2-iname, v2-iq
A name as stem plus IQ: <span className="v2-iname">TENANT<span className="v2-iq">IQ</span></span>.
The IQ takes --ac only on ink or on hover.
The lattice builds from the base.
Lattice (7.26): <Lattice />, v2-lattice, v2-lattice-band
Lattice (7.26): <Lattice />, v2-lattice, v2-lattice-band
House green on a light ground as light: a dot field building from its base on scroll. On
the closing call only: <section className="v2-band g-grey-deep v2-lattice-band"> with
<Lattice /> first.
03Controls
Buttons, forms and toggles.
Each control reads its ground, so one set of rules serves every ground; here on paper and on ink, in each theme. Green is only ever a fill, with ink on it. An error is said in words, with an icon and a heavier border, never in a second colour.
Site head, in the HUBIQ theme
Fixed at the top of a real page; held in this box here. Narrow the window below 860px for the menu and drawer, and press Tab from the top of any page on this site for the skip link.
Motion toggle
This one is live: press it and everything on this site stops moving, and stays stopped on your next visit. The lost page is this site's own 404: try a page that is not there.
Controls (3.3.0): Controls.tsx, <PillButton>, <MotionToggle>, <SiteHead>, <Lost>
Added 26 October 2026, so no site builds its own again. Every control reads its ground's
roles, so one set of rules serves every ground. Green is only a fill, always with ink on it.
An error is said in words, with the error icon and a heavier border, never in a second
colour. Each ground also sets --focus, the ring colour: ink on light grounds, house green
on ink and forest. :where(.v2-page) :focus-visible gives anything in a v2 page without a
ring of its own that ring, at one class of weight, so every kit or site ring still wins.
| Part | Component | Classes | Use |
|---|---|---|---|
| Skip link | <SkipLink href> |
v2-skip |
First in the body, to <main id="main">. <SiteHead> renders it |
| Primary button | <Pill href>, <PillButton type onClick disabled ring> |
v2-pill |
The one primary on a band. PillButton is the <button> form, for a form's send |
| Secondary button | none: a <button> or <Link> with the class |
v2-btn, v2-btn-sm, v2-btn-icon |
Outline in the heading colour, fills on hover. v2-btn-icon is square for a lone icon and needs an aria-label. A third level is the text link, v2-textlink |
| Form | <form className="v2-form"> |
v2-form, v2-form-wide, v2-form-foot, v2-form-status, v2-form-trap |
Two columns, one below 720px. v2-form-wide spans both; the foot holds the send and a note; the status box replaces the form once sent (or says it failed); the trap is the honeypot |
| Field | <Field id label help error wide> |
v2-form-field, v2-form-label, v2-form-help, v2-form-error |
Label, control, help, error. The control carries the same id, aria-describedby naming the help and error, and aria-invalid when in error |
| Text, select, textarea | none: the element with the class | v2-input |
One class for all three. A select gets its chevron; a required select with an empty first option shows it in the label colour |
| Group of choices | <fieldset className="v2-form-set"> with <legend className="v2-form-label"> |
v2-form-set |
Checkboxes or radios under one question |
| Checkbox, radio | <Choice type name value checked onChange> |
v2-choice |
The native input, redrawn: checked fills house green with an ink mark and edge |
| Switch | <Switch on onChange> |
v2-switch, v2-switch-track |
A setting that applies at once (not a form answer). role="switch" |
| Segmented control | <Segmented label options value onChange> |
v2-segmented |
One view of several (Experience or Technology); the chosen one fills in the heading colour |
| Picks | <Picks label options on onToggle> |
v2-picks, v2-pick, v2-pick-n |
Filter chips, any number on; a count beside each name if given. Hide them with no script if they only filter |
| Motion toggle | <MotionToggle storageKey> |
v2-motion, v2-motion-dot |
WCAG 2.2.2's control. Writes data-motion="off" on <html>, pauses looping video, remembers the choice. Usually in the footer base line |
| Disclosure | <Disclosure summary open> |
v2-more, v2-more-body |
A native <details>: opens with no script, read by search engines. The body grows open where the browser can animate it |
| Site head | <SiteHead stem iq links drawer> |
v2-head, v2-head-in, v2-brand, v2-brand-iq, v2-head-nav, v2-head-link, v2-burger, v2-drawer, v2-drawer-in |
Wordmark, up to five links, a menu and drawer below 860px. Always on ink. A link's match lists other paths that light it; note is its mono line in the drawer. The live hubiq.co.uk header's look |
| Lost page | <Lost title links> |
v2-lost, v2-lost-links |
What app/not-found.tsx renders: one ink band, a sentence, the ways back |
A form, put together:
<form className="v2-form" onSubmit={send}>
<Field id="name" label="Name"><input id="name" className="v2-input" autoComplete="name" required /></Field>
<Field id="email" label="Email" error={bad && "That is not an email address."}>
<input id="email" type="email" className="v2-input" aria-invalid={bad} aria-describedby={bad ? "email-error" : undefined} required />
</Field>
<Field id="note" label="What would you like to talk about?" wide><textarea id="note" className="v2-input" /></Field>
<div className="v2-form-foot"><PillButton type="submit">Send</PillButton><span className="v2-small">We use your details only to reply.</span></div>
</form>
04Everything else
The full list.
6. Components
Each entry: what it is for, the markup, the grounds it works on, its motion and what it does on a phone (720px and below, one column).
Hero (v2-hero, v2-hero-lg)
The first band. <Band ground="paper" n="01" label="..." className="v2-hero" arrive={false} id="top">
with an <h1 className="v2-h1"> and a v2-hero-lede or v2-lead. v2-hero-lg sets the
H1 a size up (Our story). Any ground. Nothing on the headline moves.
Pill CTA (7.22): <Pill href>
The one primary action. v2-pill, v2-pill-label, v2-pill-ring. A house green pill, ink
text, the label and a ringed arrow side by side; the arrow nudges forward on hover or focus
and the pill gives on press. Ink on house green. Any ground. For a pill that is a <button>
(a play control), use the classes on the button and <PillRing> with your own glyph in a
74 by 74 box. Redrawn 10 October 2026 (Gideon), from a Uiverse button by alexmaracinaru; it
replaced the detached arrow that jumped across.
Icon (rulebook 8): <Icon name>, v2-icon
Material Symbols Outlined, weight 300, from the approved subset in rulebook section 8 and
nothing else; ICONS holds the paths, IconName the names. Sizes 16, 20, 24 or 40, colour
currentColor, so it takes the text colour of whatever it sits in. Beside a label it is
aria-hidden; an icon on its own takes label, which becomes its accessible name. Gap to
its text: 8px at 16, 10px at 20, 12px at 24. A site lays out the icon and its text itself.
Moved into the kit 25 October 2026; hubiq.co.uk's StageIcon predates it and draws the same
four stage paths.
Text link: v2-textlink
Every link that is not the one primary: underlined text, the underline drops on hover. Several together go in a v2-links row.
Filling lead (7.24): <FillLead text="..." />
A v2-lead whose words fill grey to ink as it is read, finishing as its last line
reaches 30% from the top. One per band, on paper or mist. Motion off: ink.
Display word and drift (7.25): v2-word, v2-word-1, v2-word-2, v2-drift, v2-stage, v2-figure
Poppins 800 decoration at --type-word, aria-hidden, drifting sideways as the band
crosses the screen. Put data-scrub="drift" on the band. v2-stage is the figure stage
with words above (-1) and below (-2); v2-figure holds a drawn figure in house green
(dark grounds). Its sentence must be real text nearby. Phones: no drift is needed; the
words sit centred.
Column cards (7.23): v2-cards, v2-cards-4, v2-card and parts
The columns are the cards. v2-card-n, v2-card-body, v2-card-name, v2-card-iq,
v2-card-sector, v2-card-desc (shown on hover where hovering exists), v2-card-stage,
v2-dot. Hover and focus invert to ink; the initiative colour appears on ink only.
v2-cards-4 starts four cards in the content columns. Light grounds. Phones: two up.
Initiative names: v2-iname, v2-iq
A name as stem plus IQ: <span className="v2-iname">TENANT<span className="v2-iq">IQ</span></span>.
The IQ takes --ac only on ink or on hover.
Rows: v2-rows, v2-row, v2-row-head, v2-row-block, v2-row-stage, v2-row-tag, v2-row-go
A list where the whole row is a link and inverts to ink on hover: head in two columns, two blocks of two. Light grounds. Phones: stacked.
Stat row (7.27): <Stat value label>, v2-stats, v2-stats-5, v2-stat, v2-stat-n, v2-stat-l
Space Mono numerals that count up once at the trigger line; the final value is in the
HTML. Four up, or five with v2-stats-5. Phones: two up.
Lattice (7.26): <Lattice />, v2-lattice, v2-lattice-band
House green on a light ground as light: a dot field building from its base on scroll. On
the closing call only: <section className="v2-band g-grey-deep v2-lattice-band"> with
<Lattice /> first.
Scroll story (7.28): v2-story-grid, v2-story-steps, v2-step, v2-step-n, v2-story-stage, v2-story-pin, v2-diagram, v2-d-fill, v2-d-line, v2-story-static, v2-story-thumb
A diagram pinned beside steps of text; each step's top crossing 55% of the viewport sets
data-focus on the element marked data-focus-host. Mark the story root data-story,
each step data-step="name". Diagram parts carry data-part; the dim rule is in the
kit, the highlight rules for a particular diagram's parts belong with that diagram (site
CSS). v2-story-static sets the same diagram statically with one highlight per thumb.
Phones: the diagram pins under the nav and the steps scroll beneath.
Pinned scrub (7.30): v2-pin, v2-pin-stage, v2-seg, v2-rise, v2-swap
A chapter told across a stretch of scroll: the band holds still while its parts build, scrubbed by the reader. See section 7 for the mechanics.
<section className="v2-band g-ink v2-pin" data-scrub="pin" style={{ "--len": 4 } as CSSProperties}>
<Lines tone="house" />
<div className="v2-pin-stage">
...
<p className="v2-h2 v2-seg v2-rise" style={{ "--a": 0.1, "--b": 0.25 } as CSSProperties}>Arrives over the first quarter</p>
</div>
</section>
Pinned only with motion on and above 720px; otherwise it is a normal band at its finished state with every word in order, which is the version to design first.
Statement (7.29): v2-statement, v2-mark
Section 5 above.
Strike and replace (7.31): v2-sr, v2-sr-from, v2-sr-to
One claim struck through and its replacement rising beneath, at the statement size. Put
a scrub on the parent (data-scrub="drift" in a normal band; a pin's own progress inside
a pin) and a v2-seg window on each line; the replacement also takes v2-rise. On ink
and forest the bar and the replacement are house green; on light grounds both are ink.
<p className="v2-sr" data-scrub="drift">
<s className="v2-sr-from v2-seg" style={{ "--a": 0.22, "--b": 0.42 } as CSSProperties}>from building software</s>
<span className="v2-sr-to v2-seg v2-rise" style={{ "--a": 0.34, "--b": 0.52 } as CSSProperties}>to building the right solution</span>
</p>
Use <s>: the struck claim is no longer accurate, which is what the element means.
Burst (7.34): <Burst />, v2-burst
A small ornament: eight rays of three dots around an empty centre, house green. Sized by
font-size (it is 1em across), coloured by --burst (house green by default). On ink and
forest it may sit anywhere as a mark; on a light ground green is a fill only, so keep it a
decoration there, never the thing that carries meaning. On house green (g-house) it takes
ink, as the mark inverts there. It is its own .reveal, so wherever it sits it builds as it
reaches the trigger line: ring by ring from the centre out, each dot travelling out along its
ray, overshooting and falling back to the static shape (23 October 2026). No wrapper needed.
Added 10 October 2026 (Gideon).
Typed line (7.33): <TypedLine text="..." />, v2-typed
A short line, a tagline or a strapline, that types itself in character by character with a
caret (v2-typed-w holds each word's characters; v2-typed-sr carries the real text for
screen readers). Inside a pin pass w={{ a, b }} to type across that slice of the pin; on its
own it scrubs itself as it crosses the screen, like a filling lead; load (v2-typed-load)
types it once on arrival, for a hero line (never the H1). Use it for lines of a few words: a
paragraph should fill (<FillLead>), not type. Finished with motion off, reduced motion and
no script. Added for the Hub (Gideon, 8 October 2026: a page of words needs to feel alive).
Named and lit (7.32): v2-lit, v2-lit-fill
When a line names a part of the picture, the part turns house green as the line is read.
Give the part v2-seg with the same window as its line. v2-lit turns text green (ink
and forest only; set --lit-from for the colour it starts from, default the label
colour). v2-lit-fill lights a chip or box as a fill, on any ground: green behind, ink on
it, the border following. At rest, finished, every named part is lit. A 5Di part lights in
the second highlight: set --lit-to: var(--house-2) on it (rulebook, "The second
highlight").
Put the line where the eye is. The reader watches the part that is changing, so its line goes beside or directly under it, never across the stage. Mark the part being named (the Foundry's chapter 02 uses a second green bar along the cell's foot) until the next.
Rail aside: <Rail aside>, v2-rail-aside
A small piece of wayfinding under the rail label, such as a progress figure. Never a second label or a heading.
Owed and interim slots: <Owed who>, <Interim>, v2-owed, v2-owed-who, v2-owed-what, v2-interim, v2-member-owed
A real heading over a visibly empty dashed body saying who owes what (Colin by default), and a marker for real copy in a provisional place. Both must be gone before launch.
Ruled blocks: v2-points, v2-list3, v2-steps, v2-ways, v2-split, v2-dims, v2-dims-k
Text blocks each headed by a hairline, in a grid: two up (v2-points, v2-ways), three
up (v2-list3, v2-steps, v2-split with a big mono figure), or a name-then-question
list (v2-dims). Any ground. Phones: one column.
Routes: v2-routes, v2-route, v2-route-to
Links to other sections, two up, each ruled, the destination underlining on hover.
Pull quote (7.19): v2-pq
<figure className="v2-pq"><blockquote>...</blockquote><figcaption>...</figcaption></figure>.
One per page, attributed. Quotation marks are drawn by CSS.
Still (7.20): v2-still
An atmosphere image in a fixed 21:9 frame, greyscale and darkened so nothing competes with house green.
Screens: v2-shots, v2-shot
Product screenshots two up, captioned, with a hairline frame.
People: v2-tribe, v2-member, v2-member-face
Equal cards for people or AI members, square photographs, no hierarchy. Four up, three at 1100px, two on phones.
Panels and facts: v2-panels, v2-panel, v2-kv, v2-chain
A bordered box, two up; inside, a key-value list (v2-kv), ruled between entries with
v2-chain.
Chips: v2-chips
Mono facts in pills. is-on fills the chosen ones house green.
On-page nav: v2-subnav
Pill links to the parts of a long page, ruled above.
Bars: v2-bars, v2-bar, v2-bar-k, v2-bar-track, v2-bar-n
Counts by category. A quantity, so bars are right; ink on light.
Footer (7.11): v2-foot, v2-foot-mark, v2-foot-cols, v2-foot-col, v2-foot-link, v2-foot-legal, v2-foot-base
On ink with house-green column rules; a green bullet grows in beside a link on hover. The footer's content is the site's own component.
Controls (3.3.0): Controls.tsx, <PillButton>, <MotionToggle>, <SiteHead>, <Lost>
Added 26 October 2026, so no site builds its own again. Every control reads its ground's
roles, so one set of rules serves every ground. Green is only a fill, always with ink on it.
An error is said in words, with the error icon and a heavier border, never in a second
colour. Each ground also sets --focus, the ring colour: ink on light grounds, house green
on ink and forest. :where(.v2-page) :focus-visible gives anything in a v2 page without a
ring of its own that ring, at one class of weight, so every kit or site ring still wins.
| Part | Component | Classes | Use |
|---|---|---|---|
| Skip link | <SkipLink href> |
v2-skip |
First in the body, to <main id="main">. <SiteHead> renders it |
| Primary button | <Pill href>, <PillButton type onClick disabled ring> |
v2-pill |
The one primary on a band. PillButton is the <button> form, for a form's send |
| Secondary button | none: a <button> or <Link> with the class |
v2-btn, v2-btn-sm, v2-btn-icon |
Outline in the heading colour, fills on hover. v2-btn-icon is square for a lone icon and needs an aria-label. A third level is the text link, v2-textlink |
| Form | <form className="v2-form"> |
v2-form, v2-form-wide, v2-form-foot, v2-form-status, v2-form-trap |
Two columns, one below 720px. v2-form-wide spans both; the foot holds the send and a note; the status box replaces the form once sent (or says it failed); the trap is the honeypot |
| Field | <Field id label help error wide> |
v2-form-field, v2-form-label, v2-form-help, v2-form-error |
Label, control, help, error. The control carries the same id, aria-describedby naming the help and error, and aria-invalid when in error |
| Text, select, textarea | none: the element with the class | v2-input |
One class for all three. A select gets its chevron; a required select with an empty first option shows it in the label colour |
| Group of choices | <fieldset className="v2-form-set"> with <legend className="v2-form-label"> |
v2-form-set |
Checkboxes or radios under one question |
| Checkbox, radio | <Choice type name value checked onChange> |
v2-choice |
The native input, redrawn: checked fills house green with an ink mark and edge |
| Switch | <Switch on onChange> |
v2-switch, v2-switch-track |
A setting that applies at once (not a form answer). role="switch" |
| Segmented control | <Segmented label options value onChange> |
v2-segmented |
One view of several (Experience or Technology); the chosen one fills in the heading colour |
| Picks | <Picks label options on onToggle> |
v2-picks, v2-pick, v2-pick-n |
Filter chips, any number on; a count beside each name if given. Hide them with no script if they only filter |
| Motion toggle | <MotionToggle storageKey> |
v2-motion, v2-motion-dot |
WCAG 2.2.2's control. Writes data-motion="off" on <html>, pauses looping video, remembers the choice. Usually in the footer base line |
| Disclosure | <Disclosure summary open> |
v2-more, v2-more-body |
A native <details>: opens with no script, read by search engines. The body grows open where the browser can animate it |
| Site head | <SiteHead stem iq links drawer> |
v2-head, v2-head-in, v2-brand, v2-brand-iq, v2-head-nav, v2-head-link, v2-burger, v2-drawer, v2-drawer-in |
Wordmark, up to five links, a menu and drawer below 860px. Always on ink. A link's match lists other paths that light it; note is its mono line in the drawer. The live hubiq.co.uk header's look |
| Lost page | <Lost title links> |
v2-lost, v2-lost-links |
What app/not-found.tsx renders: one ink band, a sentence, the ways back |
A form, put together:
<form className="v2-form" onSubmit={send}>
<Field id="name" label="Name"><input id="name" className="v2-input" autoComplete="name" required /></Field>
<Field id="email" label="Email" error={bad && "That is not an email address."}>
<input id="email" type="email" className="v2-input" aria-invalid={bad} aria-describedby={bad ? "email-error" : undefined} required />
</Field>
<Field id="note" label="What would you like to talk about?" wide><textarea id="note" className="v2-input" /></Field>
<div className="v2-form-foot"><PillButton type="submit">Send</PillButton><span className="v2-small">We use your details only to reply.</span></div>
</form>
Arrival: <Reveal />, reveal, arrive, arrive-group, rise
The house arrival, in the kit since 3.2.0 (it was each site's own). Mount <Reveal /> once
in the site's layout, and add the head script that puts js on <html> before first paint
(document.documentElement.classList.add("js")). <Band> adds reveal arrive to its
content: its children settle in, 70ms apart, as the band crosses a line 28% up from the
bottom of the screen. arrive-group on a grid lets its children carry the gesture; reveal rise arrives one element on its own. With no script, reduced motion or motion off, nothing
is hidden. A site that carried its own copy (hubiq-web-v2, atomiq-web) can delete it once
it wears 3.2.0.