UI kit
Every token in theme.json — colour, type, spacing, radius, layout, motion — shown twice over: as live output, and as the property and value that produced it. Plus one instance of each core block the theme styles. If something looks wrong here it is wrong everywhere.
The body and UI face on this page is Proxima Nova, served from the client’s Adobe Fonts kit — the real brand face, not the stand-in this page used to carry. One thing to check before trusting a capture: the kit is remote and domain-allowlisted, so a host that is not on the web project falls back to a system sans silently. If the body text below looks like Arial or DejaVu Sans, the fonts did not load and nothing on this page is typography evidence.
How to read this page
- Name — the design label, as written in
theme.json. This is what a designer calls it. - Slug — what you type in the editor or in block markup:
fontSize: "body-lg". - Custom property — what WordPress emits into the page, and what CSS consumes.
- Value — the resolved value. Read live from
theme.jsonon every request, never retyped, so this page cannot drift from the theme.
SCSS does not use these properties directly: assets/scss/_variables.scss aliases each one to a short --chn-* name and component styles reference the alias. That alias layer is hand-written, so it is not listed here — read it there, in one place, rather than in two.
Colour
Swatches
Properties, values and contrast
| Name | Slug | Custom property | Value | Contrast vs page ground |
|---|---|---|---|---|
| Dark / Deepest | dark-deepest | --wp--preset--color--dark-deepest | #0c0b0b | 1.07:1 · fails AA |
| Dark / Primary | dark-primary | --wp--preset--color--dark-primary | #151414 | the page ground itself |
| Dark / Elevated | dark-elevated | --wp--preset--color--dark-elevated | #201e1d | 1.11:1 · fails AA |
| Dark / Medium | dark-medium | --wp--preset--color--dark-medium | #2e2c27 | 1.32:1 · fails AA |
| Dark / Border | dark-border | --wp--preset--color--dark-border | #2e2b29 | 1.31:1 · fails AA |
| Dark / Gray Gold | dark-gray-gold | --wp--preset--color--dark-gray-gold | #695f4f | 2.93:1 · fails AA |
| Gold / Primary | gold-primary | --wp--preset--color--gold-primary | #c4b072 | 8.58:1 · AA at any size |
| Gold / Deep | gold-deep | --wp--preset--color--gold-deep | #94834e | 4.92:1 · AA at any size |
| Gold / Light | gold-light | --wp--preset--color--gold-light | #d9cda0 | 11.55:1 · AA at any size |
| Light / Light | light | --wp--preset--color--light | #e1dac2 | 13.14:1 · AA at any size |
| Light / Off White 85 | off-white-85 | --wp--preset--color--off-white-85 | #cfcfcf | 11.80:1 · AA at any size |
Recap
| Status | Token or property | theme.json path | Value | Where it stands |
|---|---|---|---|---|
| ☑ Defined | Palette | settings.color.palette | 11 tokens | Every token from the approved design file |
| ☑ Defined | Page ground | styles.color.background | var(--wp--preset--color--dark-primary) | The colour every ratio on this page is measured against |
| ☑ Defined | Page text | styles.color.text | var(--wp--preset--color--off-white-85) | The default foreground, inherited by everything that does not override it |
| ⚠ Known gap | Link colour | styles.elements.link.color.text | — not set — | Links are underlined and otherwise indistinguishable from body copy. WCAG 1.4.1 forbids colour as the only cue, which the underline satisfies — but a link that never differs in colour is still a decision nobody made |
| ☐ Open decision | Link hover colour | styles.elements.link.:hover.color.text | — not set — | The hover state drops the underline. With no colour change, hover removes the only cue a link had |
| ⚠ Known gap | Grounds with no AA-safe foreground | — | — | dark-gray-gold — best available is light at 4.48:1 — normal-size text on these is a defect, not a judgement call |
| ☐ Open decision | Semantic roles | no path — the shape is undecided | — not set — | Which token is the primary CTA, which is a section ground, which is a border. The palette names values, not roles, so every use is a judgement call — and theme.json has no path for a role, which is why this row has none |
Type
Families
Handgloves — The quick brown fox jumps over the lazy dog
Handgloves — The quick brown fox jumps over the lazy dog
Handgloves — The quick brown fox jumps over the lazy dog
| Name | Slug | Custom property | Stack | Faces |
|---|---|---|---|---|
| Display | display | --wp--preset--font-family--display | Forum, Georgia, 'Times New Roman', serif | 2 bundled (latin, latin-ext) |
| Body & UI | body | --wp--preset--font-family--body | 'proxima-nova', system-ui, -apple-system, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif | system stack — no bundled face |
| Quote | quote | --wp--preset--font-family--quote | 'EB Garamond', Georgia, 'Times New Roman', serif | 2 bundled (latin, latin-ext) |
Headings — h1 to h6
Real heading elements, so what you see is the element style itself and not a paragraph dressed up as one. Only h1, h2 and h3 are designed. The design defines three heading styles, so theme.json styles three elements; h4–h6 below are the browser’s own scale inheriting the body face, and they are not brand output. Nothing should reach for them until the design says what they are.
The specimen below is deliberately this page’s second h1 — a heading specimen has to be a real h1 to be worth anything. That is defensible on an internal reference page and nowhere else: do not copy a second h1 into a module or a client page.
Handgloves
Handgloves
Handgloves
Handgloves
Handgloves
Handgloves
Paragraph sizes
Each named size applied to a p, labelled with its slug, its custom property and its value. Core’s own small, medium, large and x-large are not in this theme — a stray reference to one silently resolves to a core default rather than erroring, which is the more expensive kind of mistake.
Handgloves
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
Handgloves
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
Handgloves
Size properties, values and metrics
| Name | Slug | Custom property | Size | Line height | Letter spacing |
|---|---|---|---|---|---|
| Display | display | --wp--preset--font-size--display | clamp(4rem, 2.84rem + 4.762vw, 7.125rem) | 0.9 | — |
| Display Small | display-sm | --wp--preset--font-size--display-sm | 4rem | 1.3 | — |
| Display Extra Small | display-xs | --wp--preset--font-size--display-xs | 2.25rem | 0.9 | — |
| Section Heading | heading-2 | --wp--preset--font-size--heading-2 | 2.25rem | 1.1 | 0.06em |
| Subheading | heading-3 | --wp--preset--font-size--heading-3 | 1.5rem | 1.6 | — |
| Lead Large | body-xl | --wp--preset--font-size--body-xl | 1.3125rem | 1.5 | — |
| Lead | body-lg | --wp--preset--font-size--body-lg | 1.25rem | 1.5 | — |
| Body | body | --wp--preset--font-size--body | 1rem | 1.5 | — |
| Body Small | body-sm | --wp--preset--font-size--body-sm | 0.875rem | 1.45 | — |
| Caption | caption | --wp--preset--font-size--caption | 0.75rem | 1.4 | — |
| Meta | meta | --wp--preset--font-size--meta | 0.6875rem | 1.2 | 0.1em |
| Button | button | --wp--preset--font-size--button | 0.875rem | 1 | 0.1em |
| Quote | quote | --wp--preset--font-size--quote | 1.6875rem | 1.45 | — |
settings.custom.text, emitted as --wp--custom--text--{slug}--line-height and --letter-spacing. A block reaches them through the matching type style in styles/ — the specimens above are rendered that way, which is why they carry their leading and tracking and a bare size pick does not. An em dash means the style does not track — which is not the same as 0 being specified. The Size column is the value each step takes at and above the 48rem breakpoint; below it the root font-size is viewport-derived, so every step takes a different value from assets/scss/_token-breakpoints.scss and the sizes here are not what a phone renders. That root is a rem + vw hybrid so the browser font-size preference still moves type, but it moves it by 23% at a 24px default rather than the 200% WCAG 1.4.4 asks for — so text resize is mitigated below 48rem, not satisfied, and that remainder is not yet accepted.Element styles
| Element | Declared in theme.json |
|---|---|
h1 | typography.fontFamily: var(--wp--preset--font-family--display)typography.fontSize: var(--wp--preset--font-size--display)typography.fontWeight: 400typography.lineHeight: var(--wp--custom--text--display--line-height)typography.textTransform: uppercase |
h2 | typography.fontSize: var(--wp--preset--font-size--heading-2)typography.fontWeight: 400typography.letterSpacing: var(--wp--custom--text--heading-2--letter-spacing)typography.lineHeight: var(--wp--custom--text--heading-2--line-height)typography.textTransform: uppercase |
h3 | typography.fontSize: var(--wp--preset--font-size--heading-3)typography.fontWeight: 400typography.lineHeight: var(--wp--custom--text--heading-3--line-height) |
h4 | — none — |
h5 | — none — |
h6 | — none — |
p (root) | fontFamily: var(--wp--preset--font-family--body)fontSize: var(--wp--preset--font-size--body)lineHeight: var(--wp--custom--text--body--line-height) |
a (link) | :hover.typography.textDecoration: nonetypography.textDecoration: underline |
Recap
| Status | Token or property | theme.json path | Value | Where it stands |
|---|---|---|---|---|
| ☑ Defined | Families | settings.typography.fontFamilies | 3 roles | 4 font faces bundled and self-hosted |
| ☑ Defined | The body and UI face | settings.typography.fontFamilies[slug=body].fontFamily | 'proxima-nova', system-ui, -apple-system, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif | Proxima Nova, the real brand face, from the client's Adobe Fonts kit — it replaced the Figtree stand-in and carries no fontFace here because Adobe's licence permits delivery only from their service. Two things it brought with it are still open: Adobe serves it font-display: auto rather than swap, which is a setting on their web project and not overridable from our CSS; and whether the kit is in scope for Consent Studio is unresolved (TRD open item 5), which now matters because the request ships on every page |
| ☑ Defined | Sizes | settings.typography.fontSizes | 13 sizes | One per named design style |
| ☑ Defined | Metrics | settings.custom.text | 13 styles | line height on 13 styles, letter spacing on 3 — an absent tracking value means the style does not track, which is not the same as 0 |
| ☑ Defined | h1 element style | styles.elements.h1 | typography.fontFamily: var(--wp--preset--font-family--display)typography.fontSize: var(--wp--preset--font-size--display)typography.fontWeight: 400typography.lineHeight: var(--wp--custom--text--display--line-height)typography.textTransform: uppercase | Declared from the approved design |
| ☑ Defined | h2 element style | styles.elements.h2 | typography.fontSize: var(--wp--preset--font-size--heading-2)typography.fontWeight: 400typography.letterSpacing: var(--wp--custom--text--heading-2--letter-spacing)typography.lineHeight: var(--wp--custom--text--heading-2--line-height)typography.textTransform: uppercase | Declared from the approved design |
| ☑ Defined | h3 element style | styles.elements.h3 | typography.fontSize: var(--wp--preset--font-size--heading-3)typography.fontWeight: 400typography.lineHeight: var(--wp--custom--text--heading-3--line-height) | Declared from the approved design |
| ⚠ Known gap | h4 element style | styles.elements.h4 | — not set — | Falls through to the browser scale in the body face. The design defines three heading styles, so do not invent this one — and do not reach for the level to get a size |
| ⚠ Known gap | h5 element style | styles.elements.h5 | — not set — | Falls through to the browser scale in the body face. The design defines three heading styles, so do not invent this one — and do not reach for the level to get a size |
| ⚠ Known gap | h6 element style | styles.elements.h6 | — not set — | Falls through to the browser scale in the body face. The design defines three heading styles, so do not invent this one — and do not reach for the level to get a size |
| ☑ Defined | Root paragraph style | styles.typography | fontFamily: var(--wp--preset--font-family--body)fontSize: var(--wp--preset--font-size--body)lineHeight: var(--wp--custom--text--body--line-height) | What an unclassed p inherits |
| ☐ Open decision | Non-latin coverage | — | — | latin and latin-ext only. Several of the languages under discussion have no glyph coverage at all in the bundled faces — an i18n delivery question rather than a token one, but it does not stop being true here |
Buttons and variants
Every CTA on this site is the native wp-block-button, so these are all the shapes one can take. Nothing here is a bespoke component, per docs/wordpress.md §4.
| Element | Declared in theme.json |
|---|---|
button | border.color: var(--wp--preset--color--gold-light)border.radius: 0border.style: solidborder.width: 1pxcolor.background: transparentcolor.text: var(--wp--preset--color--gold-light)spacing.padding.bottom: var(--wp--preset--spacing--md)spacing.padding.left: var(--wp--preset--spacing--xl)spacing.padding.right: var(--wp--preset--spacing--xl)spacing.padding.top: var(--wp--preset--spacing--md)typography.fontFamily: var(--wp--preset--font-family--body)typography.fontSize: var(--wp--preset--font-size--button)typography.fontWeight: 500typography.letterSpacing: var(--wp--custom--text--button--letter-spacing)typography.lineHeight: var(--wp--custom--text--button--line-height)typography.textTransform: uppercase |
Default — no colour tokens defined
That grey is core’s, not the brand’s. styles.elements.button sets typography only, so an uncoloured button falls back to WordPress’s default #32373c on white — a colour in no palette on this project. The fix is a design decision about the primary CTA, not a value to invent here, so it stays visible until it is ruled.
Palette fills
| Fill | Background | Text | Contrast |
|---|---|---|---|
| Gold primary | gold-primary · #c4b072 | dark-primary · #151414 | 8.58:1 · AA at any size |
| Gold deep | gold-deep · #94834e | dark-deepest · #0c0b0b | 5.26:1 · AA at any size |
| Light | light · #e1dac2 | dark-primary · #151414 | 13.14:1 · AA at any size |
Palette outlines
Radius variants
Width variants
Two things these specimens cannot show. No href: every button here is deliberately link-less, because a specimen pointing at # is a dead link that a keyboard or screen-reader user still has to tab through — the real link under Links and lists is where focus behaviour is demonstrated. No states: hover, focus and disabled are not in theme.json either, and are as undefined as the fill colour.
Recap
| Status | Token or property | theme.json path | Value | Where it stands |
|---|---|---|---|---|
| ☑ Defined | Typography | styles.elements.button.typography | fontFamily: var(--wp--preset--font-family--body)fontSize: var(--wp--preset--font-size--button)fontWeight: 500letterSpacing: var(--wp--custom--text--button--letter-spacing)lineHeight: var(--wp--custom--text--button--line-height)textTransform: uppercase | The only thing the design settles about a button |
| ☑ Defined | Fill colour | styles.elements.button.color.background | transparent | Undeclared, so core's #32373c wins — a colour in no palette on this project. Every CTA has to carry its own fill today, and two authors will pick differently |
| ☑ Defined | Text colour | styles.elements.button.color.text | var(--wp--preset--color--gold-light) | Undeclared, so core's #fff wins. The pairing that ships by default is therefore nobody's decision |
| ☑ Defined | Border | styles.elements.button.border | color: var(--wp--preset--color--gold-light)radius: 0style: solidwidth: 1px | No width, colour or style. The outline variants above get their border from core's block style, not from a token |
| ☑ Defined | Radius | styles.elements.button.border.radius | 0 | A square CTA is the default. Which of the three radius tokens a button takes is undecided — the variants above are candidates, not a decision |
| ⚠ Known gap | Hover state | styles.elements.button.:hover | — not set — | No hover treatment at all. On a pointer device the button is inert-looking until it is clicked |
| ⚠ Known gap | Focus state | styles.elements.button.:focus | — not set — | The global focus ring in _base.scss is the only thing keeping the button keyboard-visible — which satisfies WCAG 2.4.7 by backstop rather than by design |
| ☐ Open decision | Active state | styles.elements.button.:active | — not set — | No pressed feedback |
| ☑ Defined | Palette pairings shown above | — | — | all three clear AA; the tightest is 5.26:1 |
| ☐ Open decision | Which variant is primary | — | — | The design has not named a primary CTA, so nothing here is the button — they are the shapes one could be |
Spacing
Design tokens
The whole of what the design defines, each bar exactly the height of its token.
| Name | Slug | Custom property | Value |
|---|---|---|---|
| SM | sm | --wp--preset--spacing--sm | 0.5rem |
| MD | md | --wp--preset--spacing--md | 1rem |
| XL | xl | --wp--preset--spacing--xl | 2rem |
var(--wp--preset--spacing--md), so it is the vertical rhythm of this page. Root padding is clamp(1.25rem, 4.4444vw, 4rem) — a clamp between the mobile and desktop gutters rather than a step on the scale.⚠ The scale stops there, and the gap is known. There is no lg and no section-padding token at all, while the approved frames pad their sections by five values that are not in the collection. Do not invent an lg and do not hard-code a section pad around it — raise it.
The generated fallback scale
| Slug | Custom property | Value |
|---|---|---|
20 | --wp--preset--spacing--20 | 0.44rem |
30 | --wp--preset--spacing--30 | 0.67rem |
40 | --wp--preset--spacing--40 | 1rem |
50 | --wp--preset--spacing--50 | 1.5rem |
60 | --wp--preset--spacing--60 | 2.25rem |
70 | --wp--preset--spacing--70 | 3.38rem |
80 | --wp--preset--spacing--80 | 5.06rem |
Recap
| Status | Token or property | theme.json path | Value | Where it stands |
|---|---|---|---|---|
| ☑ Defined | sm step | settings.spacing.spacingSizes[slug=sm].size | 0.5rem | From the approved design |
| ☑ Defined | md step | settings.spacing.spacingSizes[slug=md].size | 1rem | From the approved design |
| ☐ Open decision | lg step | settings.spacing.spacingSizes[slug=lg].size | — not set — | Absent, and absent on purpose: adding it is a design decision about the section rhythm, not a gap to fill locally. The path is what it would be, since it would join the existing scale |
| ☑ Defined | xl step | settings.spacing.spacingSizes[slug=xl].size | 2rem | From the approved design |
| ☑ Defined | Global block gap | styles.spacing.blockGap | var(--wp--preset--spacing--md) | The vertical rhythm of every stacked block, including this page |
| ☑ Defined | Root gutter | styles.spacing.padding.left | clamp(1.25rem, 4.4444vw, 4rem) | A clamp between the mobile and desktop frames rather than a step on the scale |
| ⚠ Known gap | Section padding | no path — the shape is undecided | — not set — | No token at any size, and no path either — the approved desktop frames pad sections by five different values and stack children on a sixth, none of them in the collection, so there is nothing yet to name. Every section built today hard-codes a pad or invents one |
| ☑ Defined | The generated fallback scale | settings.spacing.spacingScale | default.increment: 1.5default.mediumStep: 1.5default.operator: *default.steps: 7default.unit: rem | Declared, and NOT a design token. It generates 7 extra steps because core's fallback templates and the editor UI need a scale; they look like tokens in that UI and are not |
Radius
| Token | Custom property | Value |
|---|---|---|
md | --wp--custom--radius--md | 0.5rem |
pill | --wp--custom--radius--pill | 999rem |
sm | --wp--custom--radius--sm | 0.25rem |
Recap
| Status | Token or property | theme.json path | Value | Where it stands |
|---|---|---|---|---|
| ☑ Defined | sm | settings.custom.radius.sm | 0.25rem | From the approved design |
| ☑ Defined | md | settings.custom.radius.md | 0.5rem | From the approved design |
| ☐ Open decision | lg | settings.custom.radius.lg | — not set — | Not defined. Listed because a component scale usually grows one — if a design calls for it, this is where it goes, and until then nothing should approximate it |
| ☑ Defined | pill | settings.custom.radius.pill | 999rem | From the approved design |
| ☐ Open decision | full | settings.custom.radius.full | — not set — | Not defined. Listed because a component scale usually grows one — if a design calls for it, this is where it goes, and until then nothing should approximate it |
| ☐ Open decision | Which component takes which | — | — | Undecided. Nothing in the design maps a radius to a component, so a card, a button and an image could each end up with a different one by accident |
| ⚠ Known gap | Editor exposure | — | — | Radius lives in settings.custom, not in a preset, so an editor gets no control for it and cannot pick the token by name — only a developer can apply one |
Layout widths
| Name | theme.json path | Custom property | Value |
|---|---|---|---|
| Content | settings.layout.contentSize | --wp--style--global--content-size | 44.4444rem |
| Wide | settings.layout.wideSize | --wp--style--global--wide-size | 68.8889rem |
| Media (media) | settings.custom.width.media | --wp--custom--width--media | 60rem |
| Root gutter | styles.spacing.padding.left / .right | --wp--style--root--padding-left / -right | clamp(1.25rem, 4.4444vw, 4rem) |
Recap
| Status | Token or property | theme.json path | Value | Where it stands |
|---|---|---|---|---|
| ☑ Declared · not approved | Content width | settings.layout.contentSize | 44.4444rem | The default measure — what an unaligned block gets |
| ☑ Declared · not approved | Wide width | settings.layout.wideSize | 68.8889rem | What alignwide gets. Both are live in the editor |
| ☑ Declared · not approved | Media width | settings.custom.width.media | 60rem | The 16:9 livestream and trailer embed. No specimen on this page — there is no designed module to hang it on yet |
| ☑ Declared · not approved | Root gutter | styles.spacing.padding.left | clamp(1.25rem, 4.4444vw, 4rem) | The page edge inset, and the reason alignwide lands where it does |
| ☐ Open decision | Breakpoints | no path — the shape is undecided | — not set — | Not in theme.json at all — WordPress has no path for them, so they live as SCSS mixins in _breakpoints.scss, and that scale is a proposal rather than a ratified standard. Nothing on this page can show them |
| ⚠ Known gap | Provenance | — | — | Layout was not tokenised in the design file. Every value above was measured off the approved desktop frame, which makes these the tokens most likely to move when the design is revisited |
Motion
| Token | Custom property | Value |
|---|---|---|
duration | --wp--custom--motion--duration | 0.3s |
ease | --wp--custom--motion--ease | cubic-bezier(0.4, 0, 0.2, 1) |
Recap
| Status | Token or property | theme.json path | Value | Where it stands |
|---|---|---|---|---|
| ☑ Declared · not approved | Duration | settings.custom.motion.duration | 0.3s | Declared, but this value did not come from the design — it is the scaffold's guess, carried forward so motion has one source rather than none |
| ☑ Declared · not approved | Easing | settings.custom.motion.ease | cubic-bezier(0.4, 0, 0.2, 1) | Same: a plausible curve nobody approved |
| ☐ Open decision | A slow duration for larger moves | settings.custom.motion.duration-slow | — not set — | Not defined. One duration cannot serve both a hover tint and a section reveal, so this is the first token motion work will reach for |
| ☐ Open decision | Entrance easing | settings.custom.motion.ease-out | — not set — | Not defined. A single symmetric curve is the giveaway that no motion spec exists |
| ☐ Open decision | A motion spec | — | — | No durations, easings or triggers anywhere on record. Mobile performance is a named client success criterion, which makes this the token layer's highest-consequence gap |
| ☑ Defined | Reduced-motion backstop | — | — | _base.scss cancels animation and transition globally under prefers-reduced-motion, so a block that forgets the mixin still degrades |
Core blocks
One instance of each core primitive the theme styles. Per docs/wordpress.md §4 these are what a module composes from — never a hand-rolled parallel component.
Links and lists
Body copy with an inline link back to the front page, underlined by default and losing the underline on hover. Tab to it to see the focus ring, which is never removed.
- Colour, type, spacing, radius, layout and motion come from
theme.json. - SCSS reads them through the
--chn-*alias layer, never as raw values. - Breakpoints come from mixins; a raw
@mediaquery is a defect.
- Create a page with the slug
ui-kit. templates/page-ui-kit.htmlbinds to that slug on its own — nothing to select.- The page’s own content still renders, below, so notes can be added without touching the theme.
Quotations
Tokens are the contract. A screenshot is only evidence of what the tokens produced.
docs/wordpress.md §4–5
Never report that tests pass. Report what you actually ran.
docs/wordpress.md §5
Disclosure
What this page is not
It is not the kitchen-sink accessibility page described in docs/wordpress.md §6, which harvests every theme block from real published content for a single axe run. And it is not a designed module: nothing here is an approved composition, only the raw material one would be built from.
Code
.chn-example {
color: var(--chn-gold-primary);
padding-block: var(--chn-space-xl);
border-radius: var(--chn-radius-md);
}
Recap
| Status | Token or property | theme.json path | Value | Where it stands |
|---|---|---|---|---|
| ☑ Defined | Primitives styled and rendering | — | — | Buttons, links, lists, quote, pullquote, table, details, separator, code — each one an instance on this page, so a change to any of them shows up here first |
| ☐ Open decision | Core block style overrides | styles.blocks | — not set — | Nothing declared. Every core-block correction so far is SCSS in assets/scss/blocks/ rather than theme.json — which is the right place for the contrast fixes the dark ground needs, but it does mean the editor sees them only through the canvas stylesheet |
| ⚠ Known gap | Primitives with no specimen | — | — | Image, gallery, embed, cover and navigation. Each needs real media or a real menu, and inventing either would make this page lie about what the site has |
| ☐ Open decision | An axe run against this URL | — | — | Not done. There is no a11y tooling in the repo and no CI gate, so the accessibility of this page is a construction claim (tier 1), not a measurement (tier 2) — and "zero violations" is only ever a claim about the pages actually audited |
| ⚠ Known gap | Neighbour-dependent findings | — | — | Heading order and landmark counts read oddly here by design: this page carries two h1s and stacks specimens out of their real layout. Read those on a real page, never on this one |
Where the values live
The map from a token layer to the theme.json path that defines it and the property it emits. This is the one table on the page that is hand-written, because it describes shape rather than values — the shape is WordPress’s, not this project’s.
| Token layer | theme.json path | Emitted property |
|---|---|---|
| Colour | settings.color.palette | --wp--preset--color--{slug} |
| Type sizes | settings.typography.fontSizes | --wp--preset--font-size--{slug} |
| Type families | settings.typography.fontFamilies | --wp--preset--font-family--{slug} |
| Type metrics | settings.custom.text | --wp--custom--text--{slug}--line-height |
| Spacing | settings.spacing.spacingSizes | --wp--preset--spacing--{slug} |
| Radius | settings.custom.radius | --wp--custom--radius--{slug} |
| Motion | settings.custom.motion | --wp--custom--motion--{slug} |
| Layout | settings.layout | --wp--style--global--content-size, --wp--style--global--wide-size |
| Element styles | styles.elements.{element} | :root :where(…) rules, not properties |
Theme blocks
The theme ships one block of its own so far, acf/placeholder-slot, and it is deliberately absent from this page. It is an ACF block, ACF Pro is not in the local plugin baseline, and every render.php here returns early without it — so an instance would render nothing and read as a broken kit rather than a missing plugin. Add it here in the same change that adds ACF Pro locally.
Recap
| Status | Token or property | theme.json path | Value | Where it stands |
|---|---|---|---|---|
| ☑ Defined | acf/placeholder-slot | — | — | Registers and renders — but only where ACF Pro is active, which the local stack is not |
| ⚠ Known gap | A specimen on this page | — | — | Blocked on the plugin baseline, not on the block. Add the instance in the same change that adds ACF Pro locally, or the kit shows an empty div and reads as broken |
| ☐ Open decision | Per-module slot specs | — | — | Dimensions, load behaviour and expected content for each of the launch slots are undecided — which is exactly why they are block fields rather than constants |
| ☐ Open decision | Every other module | — | — | Nothing else is built. A designed module is the next thing this page should grow a section for — and when it does, it belongs on the kitchen-sink page too |