Replacement for the 2020 article. This revision focuses on consumer-flow purpose (what the user is trying to do) and semantic meaning (what the content is), and translates that into speech, fontography and typography tokens that can be used consistently across products. discussion | git
Companion specs:
cem-colors) — text contrast requirementscem-dimension) — reading rhythm validationcem-coupling) — label sizing in compact modescem-shape) — text container shapingcem-stroke) — text decoration, underlinescem-timing) — text transition timing
Typography is a high-leverage part of semantic theming: it shapes comprehension, scanning efficiency, and decision-making. Yet most systems treat it as “choose a font and a scale”. In consumer-facing products, this is insufficient.
We need a semantic way to express typography so that:
Typography decisions should be driven by two orthogonal dimensions:
The 2020 set covered the first five categories; this revision also adds Data, because consumer “scan/compare/decide” flows rely heavily on numeric alignment and stable rendering.
Fontography tokens describe the font assets and their feature policies.
Typography tokens describe how text is laid out and perceived.
Voice tokens describe prominence (how strongly content “speaks”) in a way that can be projected into:
The critical rule: voice is modality-independent semantics; ink and speech are projections of voice.
Tokens should communicate intent (reading, data, tag) rather than implementation details (Roboto 14px).
Humans recognize a limited number of distinct variations reliably. Prefer a compact set (e.g., 7 steps) for weight, size, and spacing.
Default tokens must work with user scaling and accessibility settings.
rem for sizing.A semantic role must behave consistently across languages and glyph coverage.
Numbers and identifiers require predictable alignment and glyph selection.
These values are safe defaults. Brands override families first; products override density next.
:root {
/* =========================
* 1) Fontography — semantic families
* (consumer meaning first)
* ========================= */
/* Rule: font family stacks are theme-invariant (light/dark/contrast).
* Override families only for brand, platform, or locale coverage.
*/
/* Long-form reading / comprehension */
--cem-fontography-reading-family: "Roboto", "Source Sans Pro",
system-ui, -apple-system, "Segoe UI", "Helvetica Neue", Arial,
"Noto Sans", "Liberation Sans", sans-serif;
/* UI labels / navigation / compact scanning */
--cem-fontography-ui-family: var(--cem-fontography-reading-family);
/* Code / scripts */
--cem-fontography-script-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas,
"Liberation Mono", "Courier New", "Noto Sans Mono", monospace;
/* Initialism / condensed emphasis (optional override) */
--cem-fontography-initialism-family: "Barlow Semi Condensed", "Roboto Condensed", "Arial Narrow",
var(--cem-fontography-ui-family);
/* Brand / display: visually distinctive from the default reading/UI sans stack. */
--cem-fontography-brand-family: "Fraunces", "Playfair Display", Georgia, "Times New Roman", serif;
/* =========================
* 2) Thickness — 7-step bounded scale
* (aligns with theme-data.xhtml “Thickness” concept)
* ========================= */
--cem-thickness-xx-light: 100;
--cem-thickness-x-light: 200;
--cem-thickness-light: 300;
--cem-thickness-normal: 400;
--cem-thickness-bold: 700;
--cem-thickness-x-bold: 800;
--cem-thickness-xx-bold: 900;
/* =========================
* 3) Typography — 7-step size scale (rem-based)
* ========================= *
* Rule: size scale is theme-invariant. Contrast modes adjust ink/decoration, not the global scale.
*/
--cem-typography-size-xxs: 0.75rem;
--cem-typography-size-xs: 0.8125rem;
--cem-typography-size-s: 0.875rem;
--cem-typography-size-m: 1rem;
--cem-typography-size-l: 1.125rem;
--cem-typography-size-xl: 1.375rem;
--cem-typography-size-xxl: 1.75rem;
/* =========================
* 4) Typography — line-height primitives
* ========================= */
--cem-typography-line-height-reading: 1.55;
--cem-typography-line-height-ui: 1.2;
--cem-typography-line-height-script: 1.4;
--cem-typography-line-height-badge: 1;
/* =========================
* 5) Typography — tracking / casing primitives
* ========================= */
--cem-typography-letter-spacing-reading: normal;
--cem-typography-letter-spacing-ui: 0.01em;
--cem-typography-letter-spacing-caps: 0.08em;
/* =========================
* 6) Typography — feature policies
* ========================= */
--cem-typography-feature-numeric-data: tabular-nums lining-nums;
--cem-typography-feature-ligatures-script: none;
--cem-typography-feature-optical-sizing: auto;
/* =========================
* 7) Typography — reading ergonomics
* ========================= */
--cem-typography-reading-measure-max: 65ch;
--cem-typography-reading-paragraph-gap: 0.75em;
/* =========================
* 8) Voice — cross-modal prominence
* (same semantics for ink + speech)
* ========================= */
/* Ink projection (font weight / icon stroke strength)
* All 7 thickness levels used for distinct voice-to-weight mapping:
* whisper(100) → soft(200) → gentle(300) → regular(400) → firm(700) → strong(800) → loud(900)
*/
--cem-voice-whisper-ink-thickness: var(--cem-thickness-xx-light);
--cem-voice-soft-ink-thickness: var(--cem-thickness-x-light);
--cem-voice-gentle-ink-thickness: var(--cem-thickness-light);
--cem-voice-regular-ink-thickness: var(--cem-thickness-normal);
--cem-voice-firm-ink-thickness: var(--cem-thickness-bold);
--cem-voice-strong-ink-thickness: var(--cem-thickness-x-bold);
--cem-voice-loud-ink-thickness: var(--cem-thickness-xx-bold);
/* Icon stroke multiplier projection (optional; for stroke-based icon sets) */
--cem-voice-whisper-icon-stroke-multiplier: 0.90;
--cem-voice-soft-icon-stroke-multiplier: 0.95;
--cem-voice-gentle-icon-stroke-multiplier: 1.00;
--cem-voice-regular-icon-stroke-multiplier: 1.00;
--cem-voice-firm-icon-stroke-multiplier: 1.10;
--cem-voice-strong-icon-stroke-multiplier: 1.20;
--cem-voice-loud-icon-stroke-multiplier: 1.30;
/* Speech projection (product read-aloud; not screen-reader control) */
--cem-voice-whisper-speech-volume: 0.65;
--cem-voice-soft-speech-volume: 0.75;
--cem-voice-gentle-speech-volume: 0.85;
--cem-voice-regular-speech-volume: 1.00;
--cem-voice-firm-speech-volume: 1.00;
--cem-voice-strong-speech-volume: 1.00;
--cem-voice-loud-speech-volume: 1.00;
--cem-voice-whisper-speech-rate: 1.00;
--cem-voice-soft-speech-rate: 1.00;
--cem-voice-gentle-speech-rate: 1.00;
--cem-voice-regular-speech-rate: 1.00;
--cem-voice-firm-speech-rate: 0.98;
--cem-voice-strong-speech-rate: 0.96;
--cem-voice-loud-speech-rate: 0.94;
--cem-voice-whisper-speech-pitch: 0.95;
--cem-voice-soft-speech-pitch: 0.98;
--cem-voice-gentle-speech-pitch: 1.00;
--cem-voice-regular-speech-pitch: 1.00;
--cem-voice-firm-speech-pitch: 1.03;
--cem-voice-strong-speech-pitch: 1.06;
--cem-voice-loud-speech-pitch: 1.10;
/* SSML emphasis (optional; if your TTS engine supports SSML) */
--cem-voice-whisper-ssml-emphasis: reduced;
--cem-voice-soft-ssml-emphasis: reduced;
--cem-voice-gentle-ssml-emphasis: moderate;
--cem-voice-regular-ssml-emphasis: moderate;
--cem-voice-firm-ssml-emphasis: moderate;
--cem-voice-strong-ssml-emphasis: strong;
--cem-voice-loud-ssml-emphasis: strong;
/* =========================
* Semantic endpoints
* (consumer meaning visible at the front of the name)
* ========================= */
/* Reading */
--cem-typography-reading-font-family: var(--cem-fontography-reading-family);
--cem-typography-reading-font-size: var(--cem-typography-size-m);
--cem-typography-reading-line-height: var(--cem-typography-line-height-reading);
--cem-typography-reading-letter-spacing: var(--cem-typography-letter-spacing-reading);
--cem-typography-reading-font-weight: var(--cem-voice-regular-ink-thickness);
--cem-typography-reading-speech-volume: var(--cem-voice-regular-speech-volume);
--cem-typography-reading-speech-rate: var(--cem-voice-regular-speech-rate);
--cem-typography-reading-speech-pitch: var(--cem-voice-regular-speech-pitch);
--cem-typography-reading-ssml-emphasis: var(--cem-voice-regular-ssml-emphasis);
/* UI */
--cem-typography-ui-font-family: var(--cem-fontography-ui-family);
--cem-typography-ui-font-size: var(--cem-typography-size-m);
--cem-typography-ui-line-height: var(--cem-typography-line-height-ui);
--cem-typography-ui-letter-spacing: var(--cem-typography-letter-spacing-ui);
--cem-typography-ui-font-weight: var(--cem-voice-gentle-ink-thickness);
--cem-typography-ui-speech-volume: var(--cem-voice-gentle-speech-volume);
--cem-typography-ui-speech-rate: var(--cem-voice-gentle-speech-rate);
--cem-typography-ui-speech-pitch: var(--cem-voice-gentle-speech-pitch);
--cem-typography-ui-ssml-emphasis: var(--cem-voice-gentle-ssml-emphasis);
/* Tag */
--cem-typography-tag-font-family: var(--cem-fontography-ui-family);
--cem-typography-tag-font-size: var(--cem-typography-size-s);
--cem-typography-tag-line-height: var(--cem-typography-line-height-ui);
--cem-typography-tag-letter-spacing: var(--cem-typography-letter-spacing-ui);
--cem-typography-tag-font-weight: var(--cem-voice-firm-ink-thickness);
--cem-typography-tag-speech-volume: var(--cem-voice-firm-speech-volume);
--cem-typography-tag-speech-rate: var(--cem-voice-firm-speech-rate);
--cem-typography-tag-speech-pitch: var(--cem-voice-firm-speech-pitch);
--cem-typography-tag-ssml-emphasis: var(--cem-voice-firm-ssml-emphasis);
/* Script */
--cem-typography-script-font-family: var(--cem-fontography-script-family);
--cem-typography-script-font-size: var(--cem-typography-size-s);
--cem-typography-script-line-height: var(--cem-typography-line-height-script);
--cem-typography-script-letter-spacing: normal;
--cem-typography-script-font-weight: var(--cem-voice-regular-ink-thickness);
--cem-typography-script-font-variant-ligatures: var(--cem-typography-feature-ligatures-script);
--cem-typography-script-speech-volume: var(--cem-voice-regular-speech-volume);
--cem-typography-script-speech-rate: var(--cem-voice-gentle-speech-rate);
--cem-typography-script-speech-pitch: var(--cem-voice-gentle-speech-pitch);
--cem-typography-script-ssml-emphasis: var(--cem-voice-gentle-ssml-emphasis);
/* Data */
--cem-typography-data-font-family: var(--cem-fontography-ui-family);
--cem-typography-data-font-size: var(--cem-typography-size-m);
--cem-typography-data-line-height: var(--cem-typography-line-height-ui);
--cem-typography-data-letter-spacing: var(--cem-typography-letter-spacing-ui);
--cem-typography-data-font-weight: var(--cem-voice-regular-ink-thickness);
--cem-typography-data-font-variant-numeric: var(--cem-typography-feature-numeric-data);
--cem-typography-data-speech-volume: var(--cem-voice-regular-speech-volume);
--cem-typography-data-speech-rate: var(--cem-voice-firm-speech-rate);
--cem-typography-data-speech-pitch: var(--cem-voice-regular-speech-pitch);
--cem-typography-data-ssml-emphasis: var(--cem-voice-regular-ssml-emphasis);
/* Initialism */
--cem-typography-initialism-font-family: var(--cem-fontography-initialism-family);
--cem-typography-initialism-font-size: var(--cem-typography-size-s);
--cem-typography-initialism-line-height: var(--cem-typography-line-height-badge);
--cem-typography-initialism-letter-spacing: var(--cem-typography-letter-spacing-caps);
--cem-typography-initialism-font-weight: var(--cem-voice-firm-ink-thickness);
--cem-typography-initialism-text-transform: uppercase;
--cem-typography-initialism-speech-volume: var(--cem-voice-firm-speech-volume);
--cem-typography-initialism-speech-rate: var(--cem-voice-firm-speech-rate);
--cem-typography-initialism-speech-pitch: var(--cem-voice-firm-speech-pitch);
--cem-typography-initialism-ssml-emphasis: var(--cem-voice-firm-ssml-emphasis);
/* Iconized */
--cem-typography-iconized-font-family: var(--cem-fontography-initialism-family);
--cem-typography-iconized-font-size: calc(var(--cem-typography-size-m) * 2);
--cem-typography-iconized-line-height: var(--cem-typography-line-height-badge);
--cem-typography-iconized-letter-spacing: var(--cem-typography-letter-spacing-caps);
--cem-typography-iconized-font-weight: var(--cem-voice-strong-ink-thickness);
--cem-typography-iconized-text-transform: uppercase;
--cem-typography-iconized-speech-volume: var(--cem-voice-strong-speech-volume);
--cem-typography-iconized-speech-rate: var(--cem-voice-strong-speech-rate);
--cem-typography-iconized-speech-pitch: var(--cem-voice-strong-speech-pitch);
--cem-typography-iconized-ssml-emphasis: var(--cem-voice-strong-ssml-emphasis);
/* Brand / Display */
--cem-typography-brand-font-family: var(--cem-fontography-brand-family);
--cem-typography-brand-font-size: var(--cem-typography-size-xxl);
--cem-typography-brand-line-height: 1.1;
--cem-typography-brand-letter-spacing: normal;
--cem-typography-brand-font-weight: var(--cem-voice-strong-ink-thickness);
--cem-typography-brand-speech-volume: var(--cem-voice-strong-speech-volume);
--cem-typography-brand-speech-rate: var(--cem-voice-strong-speech-rate);
--cem-typography-brand-speech-pitch: var(--cem-voice-strong-speech-pitch);
--cem-typography-brand-ssml-emphasis: var(--cem-voice-strong-ssml-emphasis);
}
Themes should not swap font families or rescale the type ramp. Instead, they project semantics into ink (weight/stroke) and decoration (outlines/underlines), keeping layout stable.
Dark theme: slightly lighter ink weight to compensate for perceived boldness on dark backgrounds.
:root[data-cem-theme="dark"] {
/* Keep families and size scale unchanged; only adjust ink projection. */
--cem-voice-whisper-ink-thickness: 100;
--cem-voice-soft-ink-thickness: 180;
--cem-voice-gentle-ink-thickness: 280;
--cem-voice-regular-ink-thickness: 350; /* ≈ 400 but lighter */
--cem-voice-firm-ink-thickness: 650; /* ≈ 700 but lighter */
--cem-voice-strong-ink-thickness: 750; /* ≈ 800 but lighter */
--cem-voice-loud-ink-thickness: 850; /* ≈ 900 but lighter */
}
High-contrast theme: preserve sizes; increase ink and add non-color cues where needed.
:root[data-cem-theme="contrast"] {
/* Prefer stronger ink steps (or nearest available weights for non-variable fonts). */
--cem-voice-gentle-ink-thickness: 400;
--cem-voice-regular-ink-thickness: 500;
--cem-voice-firm-ink-thickness: 750;
--cem-voice-strong-ink-thickness: 850;
/* Optional: add decoration cues at component level (not shown here). */
}
This section defines what developers apply. Each role is a stable semantic endpoint, with minimal knobs.
Naming guideline: roles should describe meaning/purpose, not placement. Prefer
reading,data,tagoverbody2,subtitle.
| Used for | . |
|----------------------------------------------------------------|-------------- -----------------------|
| explanations, help text, descriptions, articles, long content |
|
Behavior:
.cem-typography-reading {
font-family: var(--cem-typography-reading-font-family);
font-size: var(--cem-typography-reading-font-size);
line-height: var(--cem-typography-reading-line-height);
letter-spacing: var(--cem-typography-reading-letter-spacing);
font-weight: var(--cem-typography-reading-font-weight);
font-optical-sizing: var(--cem-typography-feature-optical-sizing);
max-inline-size: var(--cem-typography-reading-measure-max);
}
.cem-typography-reading p {
margin-block: 0 var(--cem-typography-reading-paragraph-gap);
}
| Used for | . |
|---|---|
| navigation, button labels, form labels, menus, secondary text | ![]() |
Behavior:
.cem-typography-ui {
font-family: var(--cem-typography-ui-font-family);
font-size: var(--cem-typography-ui-font-size);
line-height: var(--cem-typography-ui-line-height);
letter-spacing: var(--cem-typography-ui-letter-spacing);
font-weight: var(--cem-typography-ui-font-weight);
font-optical-sizing: var(--cem-typography-feature-optical-sizing);
}
| Used for | . |
|---|---|
| compact labels, chips, metadata, status tags | ![]() |
Behavior:
.cem-typography-tag {
font-family: var(--cem-typography-tag-font-family);
font-size: var(--cem-typography-tag-font-size);
line-height: var(--cem-typography-tag-line-height);
letter-spacing: var(--cem-typography-tag-letter-spacing);
font-weight: var(--cem-typography-tag-font-weight);
}
| Used for | . |
|---|---|
| code blocks, commands, identifiers that must be copy-safe | ![]() |
Behavior:
.cem-typography-script {
font-family: var(--cem-typography-script-font-family);
font-size: var(--cem-typography-script-font-size);
line-height: var(--cem-typography-script-line-height);
letter-spacing: var(--cem-typography-script-letter-spacing);
font-weight: var(--cem-typography-script-font-weight);
font-variant-ligatures: var(--cem-typography-script-font-variant-ligatures);
}
Used for:
Reason:
Behavior:
.cem-typography-data {
font-family: var(--cem-typography-data-font-family);
font-size: var(--cem-typography-data-font-size);
line-height: var(--cem-typography-data-line-height);
letter-spacing: var(--cem-typography-data-letter-spacing);
font-weight: var(--cem-typography-data-font-weight);
font-variant-numeric: var(--cem-typography-data-font-variant-numeric);
}
| Used for | . |
|---|---|
| acronyms, avatar initials, short codes meant to be “badge-like” | ![]() |
Reason:
"Barlow Semi Condensed" and "Roboto Condensed" provide the intended condensed sans-serif styling when web fonts are
available."Arial Narrow" is the closest browser-safe / system fallback for a condensed sans-serif when those web fonts are not
loaded.Impact is also commonly available and compressed, but it is intentionally not in the default stack because its very
heavy display weight is better reserved for high-impact headings or explicit brand/display overrides.Behavior:
.cem-typography-initialism {
font-family: var(--cem-typography-initialism-font-family);
font-size: var(--cem-typography-initialism-font-size);
line-height: var(--cem-typography-initialism-line-height);
letter-spacing: var(--cem-typography-initialism-letter-spacing);
font-weight: var(--cem-typography-initialism-font-weight);
text-transform: var(--cem-typography-initialism-text-transform);
}
| Used for | . |
|---|---|
| letter-as-icon (monograms, single-letter pictograms) |
Behavior:
.cem-typography-iconized {
font-family: var(--cem-typography-iconized-font-family);
font-size: var(--cem-typography-iconized-font-size);
line-height: var(--cem-typography-iconized-line-height);
letter-spacing: var(--cem-typography-iconized-letter-spacing);
font-weight: var(--cem-typography-iconized-font-weight);
text-transform: var(--cem-typography-iconized-text-transform);
}
Used for:
Behavior:
.cem-typography-brand {
font-family: var(--cem-typography-brand-font-family);
font-size: var(--cem-typography-brand-font-size);
line-height: var(--cem-typography-brand-line-height);
letter-spacing: var(--cem-typography-brand-letter-spacing);
font-weight: var(--cem-typography-brand-font-weight);
}
Use this table as a decision shortcut.
| Consumer flow purpose | Dominant typography role(s) | Default voice level |
|---|---|---|
| Orient / Navigate | UI, Tag, Initialism | gentle → firm |
| Scan / Compare | Data, UI, Tag | regular → firm |
| Read / Learn | Reading | regular |
| Act | UI (often bold), Tag (when actions are chip-like) | firm |
| Confirm / Reflect | Reading (explanations), Data (metrics), Tag (status) | regular → firm |
Typography must respond to accessibility settings and product density.
If you need an explicit density switch, add one semantic knob:
:root {
--cem-typography-density: comfortable; /* compact | comfortable */
}
In compact density, prefer smaller sizes for UI and tags while keeping Reading stable.
1rem.1.45.rem so user scaling works.rem) and density tokens.--cem-voice-*-ink-thickness) and non-color cues
(underlines, outlines, separators) to avoid layout shifts.Semantic tokens must include fallback coverage.
Guidelines:
Screen readers primarily follow HTML semantics and ARIA, not CSS typography. Do not rely on voice tokens to control assistive technology output.
Voice tokens are designed to provide consistent prominence across:
--cem-voice-*-ink-thickness and optional --cem-voice-*-icon-stroke-multiplier.--cem-typography-*-speech-* tokens as inputs to your TTS layer.This example reads the active typography role’s speech tokens from computed style and applies them to a TTS utterance.
function cemSpeak( el, text )
{
const cs = getComputedStyle( el );
// Choose one: read from the role tokens applied to the element.
const rate = parseFloat( cs.getPropertyValue( '--cem-typography-reading-speech-rate' ) ) || 1;
const pitch = parseFloat( cs.getPropertyValue( '--cem-typography-reading-speech-pitch' ) ) || 1;
const volume = parseFloat( cs.getPropertyValue( '--cem-typography-reading-speech-volume' ) ) || 1;
const utter = new SpeechSynthesisUtterance( text );
utter.rate = rate;
utter.pitch = pitch;
utter.volume = volume;
speechSynthesis.speak( utter );
}
Start with these semantic roles:
Add Brand/Iconized only when a real use-case exists.
These tables are the machine-readable contract consumed by cem-voice-fonts-typography.html. They mirror the
canonical declarations in §5.2 and §6, and add the dark / contrast ink-thickness projections from §5.3.
| Token | Value | Description | tier |
|---|---|---|---|
--cem-fontography-reading-family |
"Roboto", "Source Sans Pro", system-ui, -apple-system, "Segoe UI", "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif |
Long-form reading family stack | required |
--cem-fontography-ui-family |
var(--cem-fontography-reading-family) |
UI labels / navigation / compact scanning | required |
--cem-fontography-script-family |
ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", "Noto Sans Mono", monospace |
Code / monospaced scripts | required |
--cem-fontography-initialism-family |
"Barlow Semi Condensed", "Roboto Condensed", "Arial Narrow", var(--cem-fontography-ui-family) |
Initialism / condensed emphasis | recommended |
--cem-fontography-brand-family |
"Fraunces", "Playfair Display", Georgia, "Times New Roman", serif |
Brand / display family | recommended |
| Token | Value | Description | tier |
|---|---|---|---|
--cem-thickness-xx-light |
100 |
Hairline weight | required |
--cem-thickness-x-light |
200 |
Extra-light weight | required |
--cem-thickness-light |
300 |
Light weight | required |
--cem-thickness-normal |
400 |
Normal/regular weight | required |
--cem-thickness-bold |
700 |
Bold weight | required |
--cem-thickness-x-bold |
800 |
Extra-bold weight | required |
--cem-thickness-xx-bold |
900 |
Heaviest weight | required |
| Token | Value | Description | tier |
|---|---|---|---|
--cem-typography-size-xxs |
0.75rem |
Smallest UI text (12px @16px root) | required |
--cem-typography-size-xs |
0.8125rem |
Compact UI text (13px) | required |
--cem-typography-size-s |
0.875rem |
Small UI text (14px) | required |
--cem-typography-size-m |
1rem |
Default reading/UI size (16px) | required |
--cem-typography-size-l |
1.125rem |
Large emphasis (18px) | required |
--cem-typography-size-xl |
1.375rem |
Sub-headline (22px) | required |
--cem-typography-size-xxl |
1.75rem |
Headline / brand size (28px) | required |
| Token | Value | Description | tier |
|---|---|---|---|
--cem-typography-line-height-reading |
1.55 |
Long-form reading line-height | required |
--cem-typography-line-height-ui |
1.2 |
UI label / navigation line-height | required |
--cem-typography-line-height-script |
1.4 |
Code / script line-height | required |
--cem-typography-line-height-badge |
1 |
Single-line badge / initialism line-height | required |
| Token | Value | Description | tier |
|---|---|---|---|
--cem-typography-letter-spacing-reading |
normal |
Default reading tracking | required |
--cem-typography-letter-spacing-ui |
0.01em |
UI / navigation tracking | required |
--cem-typography-letter-spacing-caps |
0.08em |
Caps / initialism tracking | required |
| Token | Value | Description | tier |
|---|---|---|---|
--cem-typography-feature-numeric-data |
tabular-nums lining-nums |
Numeric features for data role | required |
--cem-typography-feature-ligatures-script |
none |
Ligature policy for code / script role | required |
--cem-typography-feature-optical-sizing |
auto |
Optical-sizing default (variable fonts) | required |
| Token | Value | Description | tier |
|---|---|---|---|
--cem-typography-reading-measure-max |
65ch |
Max measure for reading flows | required |
--cem-typography-reading-paragraph-gap |
0.75em |
Paragraph rhythm for reading flows | required |
7 voices × 6 channels. ink-thickness is required (drives weight); other channels are recommended (drive icon
stroke and TTS prosody).
| Token | Value | Description | tier |
|---|---|---|---|
--cem-voice-whisper-ink-thickness |
var(--cem-thickness-xx-light) |
Whisper voice → 100 | required |
--cem-voice-soft-ink-thickness |
var(--cem-thickness-x-light) |
Soft voice → 200 | required |
--cem-voice-gentle-ink-thickness |
var(--cem-thickness-light) |
Gentle voice → 300 | required |
--cem-voice-regular-ink-thickness |
var(--cem-thickness-normal) |
Regular voice → 400 | required |
--cem-voice-firm-ink-thickness |
var(--cem-thickness-bold) |
Firm voice → 700 | required |
--cem-voice-strong-ink-thickness |
var(--cem-thickness-x-bold) |
Strong voice → 800 | required |
--cem-voice-loud-ink-thickness |
var(--cem-thickness-xx-bold) |
Loud voice → 900 | required |
| Token | Value | Description | tier |
|---|---|---|---|
--cem-voice-whisper-icon-stroke-multiplier |
0.90 |
Whisper icon-stroke multiplier | recommended |
--cem-voice-soft-icon-stroke-multiplier |
0.95 |
Soft icon-stroke multiplier | recommended |
--cem-voice-gentle-icon-stroke-multiplier |
1.00 |
Gentle icon-stroke multiplier | recommended |
--cem-voice-regular-icon-stroke-multiplier |
1.00 |
Regular icon-stroke multiplier | recommended |
--cem-voice-firm-icon-stroke-multiplier |
1.10 |
Firm icon-stroke multiplier | recommended |
--cem-voice-strong-icon-stroke-multiplier |
1.20 |
Strong icon-stroke multiplier | recommended |
--cem-voice-loud-icon-stroke-multiplier |
1.30 |
Loud icon-stroke multiplier | recommended |
| Token | Value | Description | tier |
|---|---|---|---|
--cem-voice-whisper-speech-volume |
0.65 |
Whisper TTS volume | recommended |
--cem-voice-soft-speech-volume |
0.75 |
Soft TTS volume | recommended |
--cem-voice-gentle-speech-volume |
0.85 |
Gentle TTS volume | recommended |
--cem-voice-regular-speech-volume |
1.00 |
Regular TTS volume | recommended |
--cem-voice-firm-speech-volume |
1.00 |
Firm TTS volume | recommended |
--cem-voice-strong-speech-volume |
1.00 |
Strong TTS volume | recommended |
--cem-voice-loud-speech-volume |
1.00 |
Loud TTS volume | recommended |
| Token | Value | Description | tier |
|---|---|---|---|
--cem-voice-whisper-speech-rate |
1.00 |
Whisper TTS rate | recommended |
--cem-voice-soft-speech-rate |
1.00 |
Soft TTS rate | recommended |
--cem-voice-gentle-speech-rate |
1.00 |
Gentle TTS rate | recommended |
--cem-voice-regular-speech-rate |
1.00 |
Regular TTS rate | recommended |
--cem-voice-firm-speech-rate |
0.98 |
Firm TTS rate | recommended |
--cem-voice-strong-speech-rate |
0.96 |
Strong TTS rate | recommended |
--cem-voice-loud-speech-rate |
0.94 |
Loud TTS rate | recommended |
| Token | Value | Description | tier |
|---|---|---|---|
--cem-voice-whisper-speech-pitch |
0.95 |
Whisper TTS pitch | recommended |
--cem-voice-soft-speech-pitch |
0.98 |
Soft TTS pitch | recommended |
--cem-voice-gentle-speech-pitch |
1.00 |
Gentle TTS pitch | recommended |
--cem-voice-regular-speech-pitch |
1.00 |
Regular TTS pitch | recommended |
--cem-voice-firm-speech-pitch |
1.03 |
Firm TTS pitch | recommended |
--cem-voice-strong-speech-pitch |
1.06 |
Strong TTS pitch | recommended |
--cem-voice-loud-speech-pitch |
1.10 |
Loud TTS pitch | recommended |
| Token | Value | Description | tier |
|---|---|---|---|
--cem-voice-whisper-ssml-emphasis |
reduced |
Whisper SSML emphasis | recommended |
--cem-voice-soft-ssml-emphasis |
reduced |
Soft SSML emphasis | recommended |
--cem-voice-gentle-ssml-emphasis |
moderate |
Gentle SSML emphasis | recommended |
--cem-voice-regular-ssml-emphasis |
moderate |
Regular SSML emphasis | recommended |
--cem-voice-firm-ssml-emphasis |
moderate |
Firm SSML emphasis | recommended |
--cem-voice-strong-ssml-emphasis |
strong |
Strong SSML emphasis | recommended |
--cem-voice-loud-ssml-emphasis |
strong |
Loud SSML emphasis | recommended |
Dark mode lightens ink to compensate for perceived boldness on dark backgrounds. Contrast mode strengthens ink where AA contrast benefits.
| Token | Dark value | Description |
|---|---|---|
--cem-voice-whisper-ink-thickness |
100 |
Whisper (unchanged) |
--cem-voice-soft-ink-thickness |
180 |
Soft (slightly lighter than 200) |
--cem-voice-gentle-ink-thickness |
280 |
Gentle (slightly lighter than 300) |
--cem-voice-regular-ink-thickness |
350 |
Regular (lighter than 400) |
--cem-voice-firm-ink-thickness |
650 |
Firm (lighter than 700) |
--cem-voice-strong-ink-thickness |
750 |
Strong (lighter than 800) |
--cem-voice-loud-ink-thickness |
850 |
Loud (lighter than 900) |
| Token | Contrast value | Description |
|---|---|---|
--cem-voice-gentle-ink-thickness |
400 |
Gentle bumped to normal |
--cem-voice-regular-ink-thickness |
500 |
Regular bumped |
--cem-voice-firm-ink-thickness |
750 |
Firm bumped |
--cem-voice-strong-ink-thickness |
850 |
Strong bumped |
8 role × ~9-10 properties = 76 tokens. Each row is (token, value); tier is required for the cross-product
contract because every role declares every property listed below. Special role-specific properties
(font-variant-ligatures, font-variant-numeric, text-transform) appear only on the role that uses them.
| Token | Value | tier |
|---|---|---|
--cem-typography-reading-font-family |
var(--cem-fontography-reading-family) |
required |
--cem-typography-reading-font-size |
var(--cem-typography-size-m) |
required |
--cem-typography-reading-line-height |
var(--cem-typography-line-height-reading) |
required |
--cem-typography-reading-letter-spacing |
var(--cem-typography-letter-spacing-reading) |
required |
--cem-typography-reading-font-weight |
var(--cem-voice-regular-ink-thickness) |
required |
--cem-typography-reading-speech-volume |
var(--cem-voice-regular-speech-volume) |
required |
--cem-typography-reading-speech-rate |
var(--cem-voice-regular-speech-rate) |
required |
--cem-typography-reading-speech-pitch |
var(--cem-voice-regular-speech-pitch) |
required |
--cem-typography-reading-ssml-emphasis |
var(--cem-voice-regular-ssml-emphasis) |
required |
--cem-typography-ui-font-family |
var(--cem-fontography-ui-family) |
required |
--cem-typography-ui-font-size |
var(--cem-typography-size-m) |
required |
--cem-typography-ui-line-height |
var(--cem-typography-line-height-ui) |
required |
--cem-typography-ui-letter-spacing |
var(--cem-typography-letter-spacing-ui) |
required |
--cem-typography-ui-font-weight |
var(--cem-voice-gentle-ink-thickness) |
required |
--cem-typography-ui-speech-volume |
var(--cem-voice-gentle-speech-volume) |
required |
--cem-typography-ui-speech-rate |
var(--cem-voice-gentle-speech-rate) |
required |
--cem-typography-ui-speech-pitch |
var(--cem-voice-gentle-speech-pitch) |
required |
--cem-typography-ui-ssml-emphasis |
var(--cem-voice-gentle-ssml-emphasis) |
required |
--cem-typography-tag-font-family |
var(--cem-fontography-ui-family) |
required |
--cem-typography-tag-font-size |
var(--cem-typography-size-s) |
required |
--cem-typography-tag-line-height |
var(--cem-typography-line-height-ui) |
required |
--cem-typography-tag-letter-spacing |
var(--cem-typography-letter-spacing-ui) |
required |
--cem-typography-tag-font-weight |
var(--cem-voice-firm-ink-thickness) |
required |
--cem-typography-tag-speech-volume |
var(--cem-voice-firm-speech-volume) |
required |
--cem-typography-tag-speech-rate |
var(--cem-voice-firm-speech-rate) |
required |
--cem-typography-tag-speech-pitch |
var(--cem-voice-firm-speech-pitch) |
required |
--cem-typography-tag-ssml-emphasis |
var(--cem-voice-firm-ssml-emphasis) |
required |
--cem-typography-script-font-family |
var(--cem-fontography-script-family) |
required |
--cem-typography-script-font-size |
var(--cem-typography-size-s) |
required |
--cem-typography-script-line-height |
var(--cem-typography-line-height-script) |
required |
--cem-typography-script-letter-spacing |
normal |
required |
--cem-typography-script-font-weight |
var(--cem-voice-regular-ink-thickness) |
required |
--cem-typography-script-font-variant-ligatures |
var(--cem-typography-feature-ligatures-script) |
required |
--cem-typography-script-speech-volume |
var(--cem-voice-regular-speech-volume) |
required |
--cem-typography-script-speech-rate |
var(--cem-voice-gentle-speech-rate) |
required |
--cem-typography-script-speech-pitch |
var(--cem-voice-gentle-speech-pitch) |
required |
--cem-typography-script-ssml-emphasis |
var(--cem-voice-gentle-ssml-emphasis) |
required |
--cem-typography-data-font-family |
var(--cem-fontography-ui-family) |
required |
--cem-typography-data-font-size |
var(--cem-typography-size-m) |
required |
--cem-typography-data-line-height |
var(--cem-typography-line-height-ui) |
required |
--cem-typography-data-letter-spacing |
var(--cem-typography-letter-spacing-ui) |
required |
--cem-typography-data-font-weight |
var(--cem-voice-regular-ink-thickness) |
required |
--cem-typography-data-font-variant-numeric |
var(--cem-typography-feature-numeric-data) |
required |
--cem-typography-data-speech-volume |
var(--cem-voice-regular-speech-volume) |
required |
--cem-typography-data-speech-rate |
var(--cem-voice-firm-speech-rate) |
required |
--cem-typography-data-speech-pitch |
var(--cem-voice-regular-speech-pitch) |
required |
--cem-typography-data-ssml-emphasis |
var(--cem-voice-regular-ssml-emphasis) |
required |
--cem-typography-initialism-font-family |
var(--cem-fontography-initialism-family) |
required |
--cem-typography-initialism-font-size |
var(--cem-typography-size-s) |
required |
--cem-typography-initialism-line-height |
var(--cem-typography-line-height-badge) |
required |
--cem-typography-initialism-letter-spacing |
var(--cem-typography-letter-spacing-caps) |
required |
--cem-typography-initialism-font-weight |
var(--cem-voice-firm-ink-thickness) |
required |
--cem-typography-initialism-text-transform |
uppercase |
required |
--cem-typography-initialism-speech-volume |
var(--cem-voice-firm-speech-volume) |
required |
--cem-typography-initialism-speech-rate |
var(--cem-voice-firm-speech-rate) |
required |
--cem-typography-initialism-speech-pitch |
var(--cem-voice-firm-speech-pitch) |
required |
--cem-typography-initialism-ssml-emphasis |
var(--cem-voice-firm-ssml-emphasis) |
required |
--cem-typography-iconized-font-family |
var(--cem-fontography-initialism-family) |
required |
--cem-typography-iconized-font-size |
calc(var(--cem-typography-size-m) * 2) |
required |
--cem-typography-iconized-line-height |
var(--cem-typography-line-height-badge) |
required |
--cem-typography-iconized-letter-spacing |
var(--cem-typography-letter-spacing-caps) |
required |
--cem-typography-iconized-font-weight |
var(--cem-voice-strong-ink-thickness) |
required |
--cem-typography-iconized-text-transform |
uppercase |
required |
--cem-typography-iconized-speech-volume |
var(--cem-voice-strong-speech-volume) |
required |
--cem-typography-iconized-speech-rate |
var(--cem-voice-strong-speech-rate) |
required |
--cem-typography-iconized-speech-pitch |
var(--cem-voice-strong-speech-pitch) |
required |
--cem-typography-iconized-ssml-emphasis |
var(--cem-voice-strong-ssml-emphasis) |
required |
--cem-typography-brand-font-family |
var(--cem-fontography-brand-family) |
required |
--cem-typography-brand-font-size |
var(--cem-typography-size-xxl) |
required |
--cem-typography-brand-line-height |
1.1 |
required |
--cem-typography-brand-letter-spacing |
normal |
required |
--cem-typography-brand-font-weight |
var(--cem-voice-strong-ink-thickness) |
required |
--cem-typography-brand-speech-volume |
var(--cem-voice-strong-speech-volume) |
required |
--cem-typography-brand-speech-rate |
var(--cem-voice-strong-speech-rate) |
required |
--cem-typography-brand-speech-pitch |
var(--cem-voice-strong-speech-pitch) |
required |
--cem-typography-brand-ssml-emphasis |
var(--cem-voice-strong-ssml-emphasis) |
required |
| Source table | Section | Description |
|---|---|---|
cem-typography-fontography |
§12.1 | 5 family stacks (reading/ui/script/initialism/brand) |
cem-typography-thickness |
§12.1 | 7-step weight scale (--cem-thickness-*) |
cem-typography-size |
§12.1 | 7-step rem-based size scale |
cem-typography-line-height |
§12.1 | 4 line-height primitives (reading/ui/script/badge) |
cem-typography-letter-spacing |
§12.1 | 3 tracking primitives (reading/ui/caps) |
cem-typography-feature |
§12.1 | 3 feature policies (numeric-data, ligatures-script, optical-sizing) |
cem-typography-reading-ergonomics |
§12.1 | 2 reading ergonomics (measure-max, paragraph-gap) |
cem-typography-voice-ink-thickness |
§12.2 | 7 voice → ink-thickness (required) |
cem-typography-voice-icon-stroke-multiplier |
§12.2 | 7 voice → icon-stroke multipliers |
cem-typography-voice-speech-volume |
§12.2 | 7 voice → TTS volume |
cem-typography-voice-speech-rate |
§12.2 | 7 voice → TTS rate |
cem-typography-voice-speech-pitch |
§12.2 | 7 voice → TTS pitch |
cem-typography-voice-ssml-emphasis |
§12.2 | 7 voice → SSML emphasis |
cem-typography-voice-ink-thickness-dark |
§12.3 | Dark theme overrides for voice ink-thickness (override-only) |
cem-typography-voice-ink-thickness-contrast |
§12.3 | Contrast theme overrides for voice ink-thickness (override-only) |
cem-typography-roles |
§12.4 | 76 semantic role endpoint tokens |
Generator derivation rules:
This revision replaces the “typography as style” mindset with typography as semantics, and introduces voice as a cross-modal axis:
The result is a token set that stays understandable to consumers of the design system, stable across brand changes, and reusable across visual and vocal presentations.