@epa-wg/custom-element-dist 0.0.33 → 0.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +18 -0
- package/.gitattributes +4 -0
- package/.github/workflows/deploy.yml +59 -0
- package/.idea/copilot.data.migration.agent.xml +6 -0
- package/.idea/copilot.data.migration.ask.xml +6 -0
- package/.idea/copilot.data.migration.ask2agent.xml +6 -0
- package/.idea/copilot.data.migration.edit.xml +6 -0
- package/.idea/custom-element-dist.iml +2 -0
- package/.storybook/main.ts +20 -17
- package/.storybook/preview.ts +23 -23
- package/.yarn/install-state.gz +0 -0
- package/.yarnrc.yml +1 -0
- package/README.md +6 -4
- package/coverage/block-navigation.js +1 -1
- package/coverage/coverage-final.json +4 -3
- package/coverage/index.html +34 -19
- package/coverage/sorter.js +21 -7
- package/coverage/src/custom-element/coverage.svg +1 -1
- package/coverage/src/custom-element/custom-element.js/coverage.svg +1 -1
- package/coverage/src/custom-element/custom-element.js.html +448 -391
- package/coverage/src/custom-element/http-request.js/coverage.svg +1 -1
- package/coverage/src/custom-element/http-request.js.html +38 -17
- package/coverage/src/custom-element/index.html +26 -26
- package/coverage/src/custom-element/local-storage.js.html +1 -1
- package/coverage/src/custom-element/location-element.js.html +1 -1
- package/coverage/src/custom-element/module-url.js.html +1 -1
- package/coverage/src/index.html +1 -1
- package/coverage/src/material/theme/colors.js/coverage.svg +10 -0
- package/coverage/src/material/theme/colors.js.html +217 -0
- package/coverage/src/material/theme/coverage.svg +10 -0
- package/coverage/src/material/theme/index.html +116 -0
- package/coverage/src/mocks/handlers.ts.html +1 -1
- package/coverage/src/mocks/index.html +1 -1
- package/coverage/src/stories/frame.canvas.ts.html +1 -1
- package/coverage/src/stories/http-request.stories.ts.html +1 -1
- package/coverage/src/stories/index.html +1 -1
- package/coverage/src/stories/testStoryBook.ts.html +12 -12
- package/coverage/src/sum.ts.html +1 -1
- package/dist/custom-element-Bssk9jRy.cjs +97 -0
- package/dist/{custom-element-WnOqmEOe.js → custom-element-BzDjIYMe.js} +193 -183
- package/dist/custom-element-bundle.cjs +1 -1
- package/dist/custom-element-bundle.js +3 -3
- package/dist/demo/a.html +10 -3
- package/dist/demo/a.svg +26 -26
- package/dist/demo/html-template.html +4 -3
- package/dist/demo/s.xml +1 -75
- package/dist/demo/s.xslt +351 -72
- package/dist/demo/s1.xml +3706 -0
- package/dist/http-request-DSaowcG1.cjs +1 -0
- package/dist/{http-request-BOvP4KTl.js → http-request-DTCzZ1gc.js} +15 -9
- package/dist/mockServiceWorker.js +105 -63
- package/package.json +5 -4
- package/public/demo/a.html +10 -3
- package/public/demo/a.svg +26 -26
- package/public/demo/html-template.html +4 -3
- package/public/demo/s.xml +1 -75
- package/public/demo/s.xslt +351 -72
- package/public/demo/s1.xml +3706 -0
- package/public/mockServiceWorker.js +105 -63
- package/src/custom-element/custom-element.js +28 -9
- package/src/custom-element/demo/a.html +10 -3
- package/src/custom-element/demo/a.svg +26 -26
- package/src/custom-element/demo/html-template.html +4 -3
- package/src/custom-element/demo/s.xml +1 -75
- package/src/custom-element/demo/s.xslt +351 -72
- package/src/custom-element/demo/s1.xml +3706 -0
- package/src/custom-element/http-request.js +7 -0
- package/src/custom-element/ide/customData-dce.json +123 -0
- package/src/custom-element/ide/web-types-dce.json +128 -1
- package/src/custom-element/ide/web-types-xsl.json +1 -1
- package/src/material/angular.css +987 -987
- package/src/material/components/action.html +262 -0
- package/src/material/components/autocomplete.html +167 -239
- package/src/material/components/badge.html +238 -239
- package/src/material/components/dropdown.html +0 -1
- package/src/material/components/icon-link.html +160 -161
- package/src/material/components/icon.html +251 -252
- package/src/material/components/input.html +569 -570
- package/src/material/components/menu.html +235 -236
- package/src/material/components.html +157 -158
- package/src/material/demo.css +36 -36
- package/src/material/index.html +109 -110
- package/src/material/material.css +356 -356
- package/src/material/theme/Base-Principles.md +339 -0
- package/src/material/theme/README.md +298 -18
- package/src/material/theme/UI Domain Model in web applications.svg +1 -0
- package/src/material/theme/User Semantic Theme tokens.svg +1 -0
- package/src/material/theme/action-pending-poc.html +62 -0
- package/src/material/theme/actions-color.html +141 -0
- package/src/material/theme/colors-light.html +631 -0
- package/src/material/theme/colors-native.html +51 -0
- package/src/material/theme/colors-poc.html +66 -0
- package/src/material/theme/colors.html +297 -0
- package/src/material/theme/colors.js +44 -0
- package/src/material/theme/consumer-theme.css +745 -0
- package/src/material/theme/semantic.css +132 -132
- package/src/material/theme/style-bug.html +123 -0
- package/src/material/theme/theme-data.css +43 -0
- package/src/material/theme/theme-data.xhtml +2926 -0
- package/src/material/theme/todo.md +274 -0
- package/src/material/theme/tokens/action-colors.png +0 -0
- package/src/material/theme/tokens/cem-article-illustration-4x1-letterbox-2000x500.png +0 -0
- package/src/material/theme/tokens/cem-breakpoints.md +519 -0
- package/src/material/theme/tokens/cem-colors.md +715 -0
- package/src/material/theme/tokens/cem-consumerflow-typography-matrix.svg +198 -0
- package/src/material/theme/tokens/cem-coupling.md +372 -0
- package/src/material/theme/tokens/cem-data-vs-reading-numerals.svg +164 -0
- package/src/material/theme/tokens/cem-dimension.md +625 -0
- package/src/material/theme/tokens/cem-layering.md +562 -0
- package/src/material/theme/tokens/cem-m3-parity.md +343 -0
- package/src/material/theme/tokens/cem-responsive.md +238 -0
- package/src/material/theme/tokens/cem-shape.md +691 -0
- package/src/material/theme/tokens/cem-stroke-density-illustration-4to1-v3.svg +102 -0
- package/src/material/theme/tokens/cem-stroke.md +480 -0
- package/src/material/theme/tokens/cem-timing.md +198 -0
- package/src/material/theme/tokens/cem-typography-model-stack.svg +64 -0
- package/src/material/theme/tokens/cem-voice-fonts-typography.md +718 -0
- package/src/material/theme/tokens/cem-voice-ladder.svg +91 -0
- package/src/material/theme/tokens/chips.png +0 -0
- package/src/material/theme/tokens/columns-page.png +0 -0
- package/src/material/theme/tokens/initials.png +0 -0
- package/src/material/theme/tokens/nav-buttons.png +0 -0
- package/src/material/theme/tokens/script.png +0 -0
- package/src/material/theme/tokens/sufler.png +0 -0
- package/src/material/theme/tokens/typography-icons.png +0 -0
- package/src/mocks/versions.mock.ts +1 -1
- package/src/stories/__screenshots__/dom-merge.test.stories.ts/dom-merge-dom-merge-OrderPreservingOn2ndTransform-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-MultipleIfOrderingWorkaround-1.png +0 -0
- package/src/stories/dom-merge.test.stories.ts +25 -1
- package/src/stories/xslt-conditionals.test.stories.ts +492 -0
- package/src/stories/xslt-for-each.test.stories.ts +336 -0
- package/src/stories/xslt-if.test.stories.ts +89 -0
- package/storybook-static/assets/{Color-F6OSRLHC-Cbp293x2.js → Color-F6OSRLHC-DeDlDLjU.js} +1 -1
- package/storybook-static/assets/{Configure-BrFr4SLE.js → Configure-CH_tIP5N.js} +1 -1
- package/storybook-static/assets/{DocsRenderer-CFRXHY34-DhHzJiIO.js → DocsRenderer-CFRXHY34-Bc9EPsUI.js} +2 -2
- package/storybook-static/assets/{attributes.test.stories-Gg9LQTEK.js → attributes.test.stories-BtamFQkF.js} +1 -1
- package/storybook-static/assets/{css.test.stories-B_3ltOrx.js → css.test.stories-BfNxLgwr.js} +1 -1
- package/storybook-static/assets/{custom-element-CPnvJnn8.js → custom-element-CnmjNo0g.js} +6 -6
- package/storybook-static/assets/{dom-merge.test.stories-nQxcgLoM.js → dom-merge.test.stories-DxnitrLK.js} +47 -6
- package/storybook-static/assets/entry-preview-BNCt9WBs.js +26 -0
- package/storybook-static/assets/{entry-preview-docs-Dwczwtsc.js → entry-preview-docs-CbF8-81D.js} +2 -2
- package/storybook-static/assets/{external-template.test.stories-DZ-rjnfd.js → external-template.test.stories-BTsww7B0.js} +1 -1
- package/storybook-static/assets/{form.test.stories-DQhPYtMj.js → form.test.stories-DNJFtPJb.js} +1 -1
- package/storybook-static/assets/{frame.canvas-ClTqYyMN.js → frame.canvas-E5n9h6j1.js} +1 -1
- package/storybook-static/assets/{handlers-CLkps6Nz.js → handlers-Dvg8CAeR.js} +1 -1
- package/storybook-static/assets/http-request-BWeEEBkP.js +1 -0
- package/storybook-static/assets/{http-request.stories-jo0f73nw.js → http-request.stories-DgrBNle8.js} +1 -1
- package/storybook-static/assets/{iframe-CZwRpnn9.js → iframe-DiVWehoI.js} +11 -11
- package/storybook-static/assets/{index-Dr4PwNfd.js → index-CGuyH0k-.js} +87 -87
- package/storybook-static/assets/{index-CJQtnF9V.js → index-CdEbhcV9.js} +1 -1
- package/storybook-static/assets/index-DO1nmyvI.js +11 -0
- package/storybook-static/assets/{index-B68YUdzy.js → index-w6iX3YlR.js} +3 -3
- package/storybook-static/assets/{local-storage.test.stories-uA5EKRPf.js → local-storage.test.stories-Hwq80yUr.js} +1 -1
- package/storybook-static/assets/{location-element.test.stories-Cu-6Elcg.js → location-element.test.stories-mEhZzm7x.js} +1 -1
- package/storybook-static/assets/{module-url.test.stories-CD_wusXQ.js → module-url.test.stories-Bj46iT0V.js} +1 -1
- package/storybook-static/assets/{preview-CuCH40jj.js → preview-BjbXcJci.js} +2 -2
- package/storybook-static/assets/{preview-BFlNN3Wj.js → preview-Bn8igYMp.js} +1 -1
- package/storybook-static/assets/{preview-Cm4PPhHS.js → preview-CfuT8gak.js} +1 -1
- package/storybook-static/assets/{set-url.test.stories-CY7B9BVZ.js → set-url.test.stories-hzxLcqmm.js} +1 -1
- package/storybook-static/assets/{slice-events.test.stories-BVnPXm6e.js → slice-events.test.stories-DVyXFRU1.js} +1 -1
- package/storybook-static/assets/{slots.test.stories-Dxsa9KdA.js → slots.test.stories-CS544nS4.js} +1 -1
- package/storybook-static/assets/{version-select.test.stories-Buga1PAa.js → version-select.test.stories-D36nfYBq.js} +1 -1
- package/storybook-static/assets/xslt-conditionals.test.stories-BS1PTIHe.js +633 -0
- package/storybook-static/assets/xslt-for-each.test.stories-CtPS20RK.js +329 -0
- package/storybook-static/assets/xslt-if.test.stories-DcHrAMSY.js +71 -0
- package/storybook-static/demo/a.html +10 -3
- package/storybook-static/demo/a.svg +26 -26
- package/storybook-static/demo/html-template.html +4 -3
- package/storybook-static/demo/s.xml +1 -75
- package/storybook-static/demo/s.xslt +351 -72
- package/storybook-static/demo/s1.xml +3706 -0
- package/storybook-static/iframe.html +2 -2
- package/storybook-static/index.json +1 -1
- package/storybook-static/mockServiceWorker.js +105 -63
- package/storybook-static/project.json +1 -1
- package/storybook-static/sb-addons/essentials-controls-1/manager-bundle.js +69 -66
- package/storybook-static/sb-addons/essentials-docs-3/manager-bundle.js +62 -59
- package/dist/custom-element-6slVaFEs.cjs +0 -97
- package/dist/http-request-DPrY7mGh.cjs +0 -1
- package/storybook-static/assets/attributes.test.stories-CzWkKw0e.js +0 -1
- package/storybook-static/assets/entry-preview-DHVXbf3x.js +0 -26
- package/storybook-static/assets/external-template.test.stories-BivZqBTp.js +0 -1
- package/storybook-static/assets/http-request-DNq59pnj.js +0 -1
- package/storybook-static/assets/index-BwkS7JH_.js +0 -8
- package/storybook-static/assets/module-url.test.stories-CTjUAk3J.js +0 -1
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
# Semantic Theming Voice and Fonts in Typography (CEM) — 2025 Revision
|
|
2
|
+
|
|
3
|
+
> Replacement for the [2020 article](https://blog.firsov.net/2020/08/semantic-theming-fonts-in-typography.html).
|
|
4
|
+
> This revision focuses on **consumer-flow purpose** (what the user is trying to do) and **semantic meaning**
|
|
5
|
+
> (what the content *is*), and translates that into **speech**, **fontography** and **typography** tokens
|
|
6
|
+
> that can be used consistently across products.
|
|
7
|
+
[discussion](https://github.com/EPA-WG/custom-element-dist/discussions/21) |
|
|
8
|
+
[git](https://github.com/EPA-WG/custom-element-dist/blob/develop/src/material/theme/tokens/cem-voice-fonts-typography.md)
|
|
9
|
+
|
|
10
|
+
**Companion specs:**
|
|
11
|
+
- **D0. Color (Emotional Palette)** ([`cem-colors.md`](./cem-colors.md)) — text contrast requirements
|
|
12
|
+
- **D1. Space & Rhythm** ([`cem-dimension.md`](./cem-dimension.md)) — reading rhythm validation
|
|
13
|
+
- **D2. Coupling & Compactness** ([`cem-coupling.md`](./cem-coupling.md)) — label sizing in compact modes
|
|
14
|
+
- **D3. Shape — Bend** ([`cem-shape.md`](./cem-shape.md)) — text container shaping
|
|
15
|
+
- **D5. Stroke & Separation** ([`cem-stroke.md`](./cem-stroke.md)) — text decoration, underlines
|
|
16
|
+
- **D7. Time & Motion** ([`cem-timing.md`](./cem-timing.md)) — text transition timing
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
## 1. Problem statement
|
|
22
|
+
|
|
23
|
+
Typography is a high-leverage part of semantic theming: it shapes comprehension, scanning efficiency,
|
|
24
|
+
and decision-making. Yet most systems treat it as “choose a font and a scale”. In consumer-facing products,
|
|
25
|
+
this is insufficient.
|
|
26
|
+
|
|
27
|
+
We need a **semantic** way to express typography so that:
|
|
28
|
+
|
|
29
|
+
- The same user intent produces the same typographic behavior across the product.
|
|
30
|
+
- Tokens are understandable by *consumers of a design system* (engineers, designers, product owners).
|
|
31
|
+
- Tokens remain stable even when brands change (typefaces can change without changing intent).
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 2. CEM lens: consumer flow and meaning
|
|
36
|
+
|
|
37
|
+
Typography decisions should be driven by two orthogonal dimensions:
|
|
38
|
+
|
|
39
|
+
1) **Consumer flow purpose** — what the user is doing at that moment:
|
|
40
|
+
|
|
41
|
+
- **Orient / Navigate** (find where you are)
|
|
42
|
+
- **Scan / Compare** (quickly evaluate options and differences)
|
|
43
|
+
- **Read / Learn** (sustained comprehension)
|
|
44
|
+
- **Act** (commit an action: click, submit, approve)
|
|
45
|
+
- **Confirm / Reflect** (understand results, status, and next steps)
|
|
46
|
+
|
|
47
|
+
2) **Semantic meaning of content** — what the content *is*:
|
|
48
|
+
|
|
49
|
+
- **Reading** (prose, explanations)
|
|
50
|
+
- **Script** (code, commands)
|
|
51
|
+
- **Initialism** (acronyms, avatar initials)
|
|
52
|
+
- **Iconized** (letter-as-icon)
|
|
53
|
+
- **Tag** (labels and compact descriptors)
|
|
54
|
+
- **Data** (numbers, measurements, identifiers)
|
|
55
|
+
|
|
56
|
+
The 2020 set covered the first five categories; this revision also adds **Data**,
|
|
57
|
+
because consumer “scan/compare/decide” flows rely heavily on numeric alignment and stable rendering.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 3. Definitions
|
|
62
|
+
|
|
63
|
+
### 3.1 Fontography vs Typography vs Voice
|
|
64
|
+
|
|
65
|
+
- **Fontography tokens** describe the *font assets* and their feature policies.
|
|
66
|
+
- Families, fallbacks, optical sizing, ligature policy, numeric features.
|
|
67
|
+
|
|
68
|
+
- **Typography tokens** describe how text is *laid out and perceived*.
|
|
69
|
+
- Size scale, line height, letter spacing, casing rules, measure (line length), paragraph rhythm.
|
|
70
|
+
|
|
71
|
+
- **Voice tokens** describe *prominence* (how strongly content “speaks”) in a way that can be projected into:
|
|
72
|
+
- **Ink channel (visual):** font weight and icon stroke thickness.
|
|
73
|
+
- **Speech channel (vocal):** prosody for product “read aloud” (rate/pitch/volume) and optional SSML emphasis.
|
|
74
|
+
|
|
75
|
+
The critical rule: **voice is modality-independent semantics**; ink and speech are projections of voice.
|
|
76
|
+

|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 4. Principles
|
|
81
|
+
|
|
82
|
+
### P1. Semantic intent first
|
|
83
|
+
|
|
84
|
+
Tokens should communicate intent (reading, data, tag) rather than implementation details (Roboto 14px).
|
|
85
|
+
|
|
86
|
+
### P2. Bounded variation
|
|
87
|
+
|
|
88
|
+
Humans recognize a limited number of distinct variations reliably. Prefer a compact set (e.g., 7 steps) for weight,
|
|
89
|
+
size, and spacing.
|
|
90
|
+
|
|
91
|
+
### P3. Accessibility by construction
|
|
92
|
+
|
|
93
|
+
Default tokens must work with user scaling and accessibility settings.
|
|
94
|
+
|
|
95
|
+
- Use `rem` for sizing.
|
|
96
|
+
- Preserve readable line-height for prose.
|
|
97
|
+
- Avoid micro text for critical content.
|
|
98
|
+
|
|
99
|
+
### P4. Internationalization and fallback are first-class
|
|
100
|
+
|
|
101
|
+
A semantic role must behave consistently across languages and glyph coverage.
|
|
102
|
+
|
|
103
|
+
### P5. Data is a distinct semantic
|
|
104
|
+
|
|
105
|
+
Numbers and identifiers require predictable alignment and glyph selection.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 5. Token model
|
|
110
|
+
|
|
111
|
+
### 5.1 Token groups
|
|
112
|
+
|
|
113
|
+
1) **Fontography families (semantic aliases)**
|
|
114
|
+
2) **Thickness scale (bounded)**
|
|
115
|
+
3) **Typography size scale (bounded)**
|
|
116
|
+
4) **Typography line-height scale (role-based)**
|
|
117
|
+
5) **Typography tracking/casing policies**
|
|
118
|
+
6) **Typography feature policies** (numerics, ligatures, optical sizing)
|
|
119
|
+
7) **Typography reading ergonomics** (measure and paragraph rhythm)
|
|
120
|
+
8) **Voice semantics (cross-modal prominence)** mapped to:
|
|
121
|
+
- Ink thickness (text weight / icon stroke)
|
|
122
|
+
- Speech prosody (rate/pitch/volume) and optional SSML emphasis
|
|
123
|
+
|
|
124
|
+
### 5.2 Canonical tokens (CSS custom properties)
|
|
125
|
+
|
|
126
|
+
> These values are safe defaults. Brands override families first; products override density next.
|
|
127
|
+
|
|
128
|
+
```css
|
|
129
|
+
:root {
|
|
130
|
+
/* =========================
|
|
131
|
+
* 1) Fontography — semantic families
|
|
132
|
+
* (consumer meaning first)
|
|
133
|
+
* ========================= */
|
|
134
|
+
|
|
135
|
+
/* Rule: font family stacks are theme-invariant (light/dark/contrast).
|
|
136
|
+
* Override families only for brand, platform, or locale coverage.
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
/* Long-form reading / comprehension */
|
|
140
|
+
--cem-fontography-reading-family: "Roboto", "Source Sans Pro",
|
|
141
|
+
system-ui, -apple-system, "Segoe UI", "Helvetica Neue", Arial,
|
|
142
|
+
"Noto Sans", "Liberation Sans", sans-serif;
|
|
143
|
+
|
|
144
|
+
/* UI labels / navigation / compact scanning */
|
|
145
|
+
--cem-fontography-ui-family: var(--cem-fontography-reading-family);
|
|
146
|
+
|
|
147
|
+
/* Code / scripts */
|
|
148
|
+
--cem-fontography-script-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas,
|
|
149
|
+
"Liberation Mono", "Courier New", "Noto Sans Mono", monospace;
|
|
150
|
+
|
|
151
|
+
/* Initialism / condensed emphasis (optional override) */
|
|
152
|
+
--cem-fontography-initialism-family: "Barlow Semi Condensed", "Roboto Condensed",
|
|
153
|
+
var(--cem-fontography-ui-family);
|
|
154
|
+
|
|
155
|
+
/* Brand / display (optional; alias until a brand face is chosen) */
|
|
156
|
+
--cem-fontography-brand-family: var(--cem-fontography-reading-family);
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
/* =========================
|
|
160
|
+
* 2) Thickness — 7-step bounded scale
|
|
161
|
+
* (aligns with theme-data.xhtml “Thickness” concept)
|
|
162
|
+
* ========================= */
|
|
163
|
+
--cem-thickness-xx-light: 100;
|
|
164
|
+
--cem-thickness-x-light: 200;
|
|
165
|
+
--cem-thickness-light: 300;
|
|
166
|
+
--cem-thickness-normal: 400;
|
|
167
|
+
--cem-thickness-bold: 700;
|
|
168
|
+
--cem-thickness-x-bold: 800;
|
|
169
|
+
--cem-thickness-xx-bold: 900;
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
/* =========================
|
|
173
|
+
* 3) Typography — 7-step size scale (rem-based)
|
|
174
|
+
* ========================= *
|
|
175
|
+
* Rule: size scale is theme-invariant. Contrast modes adjust ink/decoration, not the global scale.
|
|
176
|
+
*/
|
|
177
|
+
--cem-typography-size-xxs: 0.75rem;
|
|
178
|
+
--cem-typography-size-xs: 0.8125rem;
|
|
179
|
+
--cem-typography-size-s: 0.875rem;
|
|
180
|
+
--cem-typography-size-m: 1rem;
|
|
181
|
+
--cem-typography-size-l: 1.125rem;
|
|
182
|
+
--cem-typography-size-xl: 1.375rem;
|
|
183
|
+
--cem-typography-size-xxl: 1.75rem;
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
/* =========================
|
|
187
|
+
* 4) Typography — line-height primitives
|
|
188
|
+
* ========================= */
|
|
189
|
+
--cem-typography-line-height-reading: 1.55;
|
|
190
|
+
--cem-typography-line-height-ui: 1.2;
|
|
191
|
+
--cem-typography-line-height-script: 1.4;
|
|
192
|
+
--cem-typography-line-height-badge: 1;
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
/* =========================
|
|
196
|
+
* 5) Typography — tracking / casing primitives
|
|
197
|
+
* ========================= */
|
|
198
|
+
--cem-typography-letter-spacing-reading: normal;
|
|
199
|
+
--cem-typography-letter-spacing-ui: 0.01em;
|
|
200
|
+
--cem-typography-letter-spacing-caps: 0.08em;
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
/* =========================
|
|
204
|
+
* 6) Typography — feature policies
|
|
205
|
+
* ========================= */
|
|
206
|
+
--cem-typography-feature-numeric-data: tabular-nums lining-nums;
|
|
207
|
+
--cem-typography-feature-ligatures-script: none;
|
|
208
|
+
--cem-typography-feature-optical-sizing: auto;
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
/* =========================
|
|
212
|
+
* 7) Typography — reading ergonomics
|
|
213
|
+
* ========================= */
|
|
214
|
+
--cem-typography-reading-measure-max: 65ch;
|
|
215
|
+
--cem-typography-reading-paragraph-gap: 0.75em;
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
/* =========================
|
|
219
|
+
* 8) Voice — cross-modal prominence
|
|
220
|
+
* (same semantics for ink + speech)
|
|
221
|
+
* ========================= */
|
|
222
|
+
|
|
223
|
+
/* Ink projection (font weight / icon stroke strength)
|
|
224
|
+
* All 7 thickness levels used for distinct voice-to-weight mapping:
|
|
225
|
+
* whisper(100) → soft(200) → gentle(300) → regular(400) → firm(700) → strong(800) → loud(900)
|
|
226
|
+
*/
|
|
227
|
+
--cem-voice-whisper-ink-thickness: var(--cem-thickness-xx-light);
|
|
228
|
+
--cem-voice-soft-ink-thickness: var(--cem-thickness-x-light);
|
|
229
|
+
--cem-voice-gentle-ink-thickness: var(--cem-thickness-light);
|
|
230
|
+
--cem-voice-regular-ink-thickness: var(--cem-thickness-normal);
|
|
231
|
+
--cem-voice-firm-ink-thickness: var(--cem-thickness-bold);
|
|
232
|
+
--cem-voice-strong-ink-thickness: var(--cem-thickness-x-bold);
|
|
233
|
+
--cem-voice-loud-ink-thickness: var(--cem-thickness-xx-bold);
|
|
234
|
+
|
|
235
|
+
/* Icon stroke multiplier projection (optional; for stroke-based icon sets) */
|
|
236
|
+
--cem-voice-whisper-icon-stroke-multiplier: 0.90;
|
|
237
|
+
--cem-voice-soft-icon-stroke-multiplier: 0.95;
|
|
238
|
+
--cem-voice-gentle-icon-stroke-multiplier: 1.00;
|
|
239
|
+
--cem-voice-regular-icon-stroke-multiplier: 1.00;
|
|
240
|
+
--cem-voice-firm-icon-stroke-multiplier: 1.10;
|
|
241
|
+
--cem-voice-strong-icon-stroke-multiplier: 1.20;
|
|
242
|
+
--cem-voice-loud-icon-stroke-multiplier: 1.30;
|
|
243
|
+
|
|
244
|
+
/* Speech projection (product read-aloud; not screen-reader control) */
|
|
245
|
+
--cem-voice-whisper-speech-volume: 0.65;
|
|
246
|
+
--cem-voice-soft-speech-volume: 0.75;
|
|
247
|
+
--cem-voice-gentle-speech-volume: 0.85;
|
|
248
|
+
--cem-voice-regular-speech-volume: 1.00;
|
|
249
|
+
--cem-voice-firm-speech-volume: 1.00;
|
|
250
|
+
--cem-voice-strong-speech-volume: 1.00;
|
|
251
|
+
--cem-voice-loud-speech-volume: 1.00;
|
|
252
|
+
|
|
253
|
+
--cem-voice-whisper-speech-rate: 1.00;
|
|
254
|
+
--cem-voice-soft-speech-rate: 1.00;
|
|
255
|
+
--cem-voice-gentle-speech-rate: 1.00;
|
|
256
|
+
--cem-voice-regular-speech-rate: 1.00;
|
|
257
|
+
--cem-voice-firm-speech-rate: 0.98;
|
|
258
|
+
--cem-voice-strong-speech-rate: 0.96;
|
|
259
|
+
--cem-voice-loud-speech-rate: 0.94;
|
|
260
|
+
|
|
261
|
+
--cem-voice-whisper-speech-pitch: 0.95;
|
|
262
|
+
--cem-voice-soft-speech-pitch: 0.98;
|
|
263
|
+
--cem-voice-gentle-speech-pitch: 1.00;
|
|
264
|
+
--cem-voice-regular-speech-pitch: 1.00;
|
|
265
|
+
--cem-voice-firm-speech-pitch: 1.03;
|
|
266
|
+
--cem-voice-strong-speech-pitch: 1.06;
|
|
267
|
+
--cem-voice-loud-speech-pitch: 1.10;
|
|
268
|
+
|
|
269
|
+
/* SSML emphasis (optional; if your TTS engine supports SSML) */
|
|
270
|
+
--cem-voice-whisper-ssml-emphasis: reduced;
|
|
271
|
+
--cem-voice-soft-ssml-emphasis: reduced;
|
|
272
|
+
--cem-voice-gentle-ssml-emphasis: moderate;
|
|
273
|
+
--cem-voice-regular-ssml-emphasis: moderate;
|
|
274
|
+
--cem-voice-firm-ssml-emphasis: moderate;
|
|
275
|
+
--cem-voice-strong-ssml-emphasis: strong;
|
|
276
|
+
--cem-voice-loud-ssml-emphasis: strong;
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
/* =========================
|
|
280
|
+
* Semantic endpoints
|
|
281
|
+
* (consumer meaning visible at the front of the name)
|
|
282
|
+
* ========================= */
|
|
283
|
+
|
|
284
|
+
/* Reading */
|
|
285
|
+
--cem-typography-reading-font-family: var(--cem-fontography-reading-family);
|
|
286
|
+
--cem-typography-reading-font-size: var(--cem-typography-size-m);
|
|
287
|
+
--cem-typography-reading-line-height: var(--cem-typography-line-height-reading);
|
|
288
|
+
--cem-typography-reading-letter-spacing: var(--cem-typography-letter-spacing-reading);
|
|
289
|
+
--cem-typography-reading-font-weight: var(--cem-voice-regular-ink-thickness);
|
|
290
|
+
--cem-typography-reading-speech-volume: var(--cem-voice-regular-speech-volume);
|
|
291
|
+
--cem-typography-reading-speech-rate: var(--cem-voice-regular-speech-rate);
|
|
292
|
+
--cem-typography-reading-speech-pitch: var(--cem-voice-regular-speech-pitch);
|
|
293
|
+
--cem-typography-reading-ssml-emphasis: var(--cem-voice-regular-ssml-emphasis);
|
|
294
|
+
|
|
295
|
+
/* UI */
|
|
296
|
+
--cem-typography-ui-font-family: var(--cem-fontography-ui-family);
|
|
297
|
+
--cem-typography-ui-font-size: var(--cem-typography-size-m);
|
|
298
|
+
--cem-typography-ui-line-height: var(--cem-typography-line-height-ui);
|
|
299
|
+
--cem-typography-ui-letter-spacing: var(--cem-typography-letter-spacing-ui);
|
|
300
|
+
--cem-typography-ui-font-weight: var(--cem-voice-gentle-ink-thickness);
|
|
301
|
+
--cem-typography-ui-speech-volume: var(--cem-voice-gentle-speech-volume);
|
|
302
|
+
--cem-typography-ui-speech-rate: var(--cem-voice-gentle-speech-rate);
|
|
303
|
+
--cem-typography-ui-speech-pitch: var(--cem-voice-gentle-speech-pitch);
|
|
304
|
+
--cem-typography-ui-ssml-emphasis: var(--cem-voice-gentle-ssml-emphasis);
|
|
305
|
+
|
|
306
|
+
/* Tag */
|
|
307
|
+
--cem-typography-tag-font-family: var(--cem-fontography-ui-family);
|
|
308
|
+
--cem-typography-tag-font-size: var(--cem-typography-size-s);
|
|
309
|
+
--cem-typography-tag-line-height: var(--cem-typography-line-height-ui);
|
|
310
|
+
--cem-typography-tag-letter-spacing: var(--cem-typography-letter-spacing-ui);
|
|
311
|
+
--cem-typography-tag-font-weight: var(--cem-voice-firm-ink-thickness);
|
|
312
|
+
--cem-typography-tag-speech-volume: var(--cem-voice-firm-speech-volume);
|
|
313
|
+
--cem-typography-tag-speech-rate: var(--cem-voice-firm-speech-rate);
|
|
314
|
+
--cem-typography-tag-speech-pitch: var(--cem-voice-firm-speech-pitch);
|
|
315
|
+
--cem-typography-tag-ssml-emphasis: var(--cem-voice-firm-ssml-emphasis);
|
|
316
|
+
|
|
317
|
+
/* Script */
|
|
318
|
+
--cem-typography-script-font-family: var(--cem-fontography-script-family);
|
|
319
|
+
--cem-typography-script-font-size: var(--cem-typography-size-s);
|
|
320
|
+
--cem-typography-script-line-height: var(--cem-typography-line-height-script);
|
|
321
|
+
--cem-typography-script-letter-spacing: normal;
|
|
322
|
+
--cem-typography-script-font-weight: var(--cem-voice-regular-ink-thickness);
|
|
323
|
+
--cem-typography-script-font-variant-ligatures: var(--cem-typography-feature-ligatures-script);
|
|
324
|
+
--cem-typography-script-speech-volume: var(--cem-voice-regular-speech-volume);
|
|
325
|
+
--cem-typography-script-speech-rate: var(--cem-voice-gentle-speech-rate);
|
|
326
|
+
--cem-typography-script-speech-pitch: var(--cem-voice-gentle-speech-pitch);
|
|
327
|
+
--cem-typography-script-ssml-emphasis: var(--cem-voice-gentle-ssml-emphasis);
|
|
328
|
+
|
|
329
|
+
/* Data */
|
|
330
|
+
--cem-typography-data-font-family: var(--cem-fontography-ui-family);
|
|
331
|
+
--cem-typography-data-font-size: var(--cem-typography-size-m);
|
|
332
|
+
--cem-typography-data-line-height: var(--cem-typography-line-height-ui);
|
|
333
|
+
--cem-typography-data-letter-spacing: var(--cem-typography-letter-spacing-ui);
|
|
334
|
+
--cem-typography-data-font-weight: var(--cem-voice-regular-ink-thickness);
|
|
335
|
+
--cem-typography-data-font-variant-numeric: var(--cem-typography-feature-numeric-data);
|
|
336
|
+
--cem-typography-data-speech-volume: var(--cem-voice-regular-speech-volume);
|
|
337
|
+
--cem-typography-data-speech-rate: var(--cem-voice-firm-speech-rate);
|
|
338
|
+
--cem-typography-data-speech-pitch: var(--cem-voice-regular-speech-pitch);
|
|
339
|
+
--cem-typography-data-ssml-emphasis: var(--cem-voice-regular-ssml-emphasis);
|
|
340
|
+
|
|
341
|
+
/* Initialism */
|
|
342
|
+
--cem-typography-initialism-font-family: var(--cem-fontography-initialism-family);
|
|
343
|
+
--cem-typography-initialism-font-size: var(--cem-typography-size-s);
|
|
344
|
+
--cem-typography-initialism-line-height: var(--cem-typography-line-height-badge);
|
|
345
|
+
--cem-typography-initialism-letter-spacing: var(--cem-typography-letter-spacing-caps);
|
|
346
|
+
--cem-typography-initialism-font-weight: var(--cem-voice-firm-ink-thickness);
|
|
347
|
+
--cem-typography-initialism-text-transform: uppercase;
|
|
348
|
+
--cem-typography-initialism-speech-volume: var(--cem-voice-firm-speech-volume);
|
|
349
|
+
--cem-typography-initialism-speech-rate: var(--cem-voice-firm-speech-rate);
|
|
350
|
+
--cem-typography-initialism-speech-pitch: var(--cem-voice-firm-speech-pitch);
|
|
351
|
+
--cem-typography-initialism-ssml-emphasis: var(--cem-voice-firm-ssml-emphasis);
|
|
352
|
+
|
|
353
|
+
/* Iconized */
|
|
354
|
+
--cem-typography-iconized-font-family: var(--cem-fontography-initialism-family);
|
|
355
|
+
--cem-typography-iconized-font-size: calc(var(--cem-typography-size-m) * 2);
|
|
356
|
+
--cem-typography-iconized-line-height: var(--cem-typography-line-height-badge);
|
|
357
|
+
--cem-typography-iconized-letter-spacing: var(--cem-typography-letter-spacing-caps);
|
|
358
|
+
--cem-typography-iconized-font-weight: var(--cem-voice-strong-ink-thickness);
|
|
359
|
+
--cem-typography-iconized-text-transform: uppercase;
|
|
360
|
+
--cem-typography-iconized-speech-volume: var(--cem-voice-strong-speech-volume);
|
|
361
|
+
--cem-typography-iconized-speech-rate: var(--cem-voice-strong-speech-rate);
|
|
362
|
+
--cem-typography-iconized-speech-pitch: var(--cem-voice-strong-speech-pitch);
|
|
363
|
+
--cem-typography-iconized-ssml-emphasis: var(--cem-voice-strong-ssml-emphasis);
|
|
364
|
+
|
|
365
|
+
/* Brand / Display */
|
|
366
|
+
--cem-typography-brand-font-family: var(--cem-fontography-brand-family);
|
|
367
|
+
--cem-typography-brand-font-size: var(--cem-typography-size-xxl);
|
|
368
|
+
--cem-typography-brand-line-height: 1.1;
|
|
369
|
+
--cem-typography-brand-letter-spacing: normal;
|
|
370
|
+
--cem-typography-brand-font-weight: var(--cem-voice-strong-ink-thickness);
|
|
371
|
+
--cem-typography-brand-speech-volume: var(--cem-voice-strong-speech-volume);
|
|
372
|
+
--cem-typography-brand-speech-rate: var(--cem-voice-strong-speech-rate);
|
|
373
|
+
--cem-typography-brand-speech-pitch: var(--cem-voice-strong-speech-pitch);
|
|
374
|
+
--cem-typography-brand-ssml-emphasis: var(--cem-voice-strong-ssml-emphasis);
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### 5.3 Theme projections (dark and contrast)
|
|
379
|
+
|
|
380
|
+
Themes should *not* swap font families or rescale the type ramp. Instead, they project semantics into
|
|
381
|
+
**ink** (weight/stroke) and **decoration** (outlines/underlines), keeping layout stable.
|
|
382
|
+
|
|
383
|
+
**Dark theme:** slightly lighter ink weight to compensate for perceived boldness on dark backgrounds.
|
|
384
|
+
|
|
385
|
+
```css
|
|
386
|
+
:root[data-cem-theme="dark"] {
|
|
387
|
+
/* Keep families and size scale unchanged; only adjust ink projection. */
|
|
388
|
+
--cem-voice-whisper-ink-thickness: 100;
|
|
389
|
+
--cem-voice-soft-ink-thickness: 180;
|
|
390
|
+
--cem-voice-gentle-ink-thickness: 280;
|
|
391
|
+
--cem-voice-regular-ink-thickness: 350; /* ≈ 400 but lighter */
|
|
392
|
+
--cem-voice-firm-ink-thickness: 650; /* ≈ 700 but lighter */
|
|
393
|
+
--cem-voice-strong-ink-thickness: 750; /* ≈ 800 but lighter */
|
|
394
|
+
--cem-voice-loud-ink-thickness: 850; /* ≈ 900 but lighter */
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+

|
|
398
|
+
|
|
399
|
+
**High-contrast theme:** preserve sizes; increase ink and add non-color cues where needed.
|
|
400
|
+
|
|
401
|
+
```css
|
|
402
|
+
:root[data-cem-theme="contrast"] {
|
|
403
|
+
/* Prefer stronger ink steps (or nearest available weights for non-variable fonts). */
|
|
404
|
+
--cem-voice-gentle-ink-thickness: 400;
|
|
405
|
+
--cem-voice-regular-ink-thickness: 500;
|
|
406
|
+
--cem-voice-firm-ink-thickness: 750;
|
|
407
|
+
--cem-voice-strong-ink-thickness: 850;
|
|
408
|
+
|
|
409
|
+
/* Optional: add decoration cues at component level (not shown here). */
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## 6. Semantic typography roles
|
|
416
|
+
|
|
417
|
+
This section defines *what developers apply*. Each role is a stable semantic endpoint, with minimal knobs.
|
|
418
|
+
|
|
419
|
+
> Naming guideline: roles should describe **meaning/purpose**, not placement. Prefer `reading`, `data`, `tag` over
|
|
420
|
+
`body2`, `subtitle`.
|
|
421
|
+
|
|
422
|
+

|
|
423
|
+
|
|
424
|
+
### 6.1 Reading
|
|
425
|
+
|
|
426
|
+
| Used for | . |
|
|
427
|
+
|----------------------------------------------------------------|-------------- -----------------------|
|
|
428
|
+
| explanations, help text, descriptions, articles, long content |  |
|
|
429
|
+
|
|
430
|
+
Behavior:
|
|
431
|
+
|
|
432
|
+
```css
|
|
433
|
+
.cem-typography-reading {
|
|
434
|
+
font-family: var(--cem-typography-reading-font-family);
|
|
435
|
+
font-size: var(--cem-typography-reading-font-size);
|
|
436
|
+
line-height: var(--cem-typography-reading-line-height);
|
|
437
|
+
letter-spacing: var(--cem-typography-reading-letter-spacing);
|
|
438
|
+
font-weight: var(--cem-typography-reading-font-weight);
|
|
439
|
+
|
|
440
|
+
font-optical-sizing: var(--cem-typography-feature-optical-sizing);
|
|
441
|
+
max-inline-size: var(--cem-typography-reading-measure-max);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.cem-typography-reading p {
|
|
445
|
+
margin-block: 0 var(--cem-typography-reading-paragraph-gap);
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### 6.2 UI (scan/navigate)
|
|
450
|
+
|
|
451
|
+
| Used for | . |
|
|
452
|
+
|---------------------------------------------------------------|------------------------------------------------|
|
|
453
|
+
| navigation, button labels, form labels, menus, secondary text |  |
|
|
454
|
+
|
|
455
|
+
Behavior:
|
|
456
|
+
|
|
457
|
+
```css
|
|
458
|
+
.cem-typography-ui {
|
|
459
|
+
font-family: var(--cem-typography-ui-font-family);
|
|
460
|
+
font-size: var(--cem-typography-ui-font-size);
|
|
461
|
+
line-height: var(--cem-typography-ui-line-height);
|
|
462
|
+
letter-spacing: var(--cem-typography-ui-letter-spacing);
|
|
463
|
+
font-weight: var(--cem-typography-ui-font-weight);
|
|
464
|
+
|
|
465
|
+
font-optical-sizing: var(--cem-typography-feature-optical-sizing);
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### 6.3 Tag
|
|
470
|
+
|
|
471
|
+
| Used for | . |
|
|
472
|
+
|----------------------------------------------|-------------------------------------|
|
|
473
|
+
| compact labels, chips, metadata, status tags |  |
|
|
474
|
+
|
|
475
|
+
Behavior:
|
|
476
|
+
|
|
477
|
+
```css
|
|
478
|
+
.cem-typography-tag {
|
|
479
|
+
font-family: var(--cem-typography-tag-font-family);
|
|
480
|
+
font-size: var(--cem-typography-tag-font-size);
|
|
481
|
+
line-height: var(--cem-typography-tag-line-height);
|
|
482
|
+
letter-spacing: var(--cem-typography-tag-letter-spacing);
|
|
483
|
+
font-weight: var(--cem-typography-tag-font-weight);
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### 6.4 Script
|
|
488
|
+
|
|
489
|
+
| Used for | . |
|
|
490
|
+
|-----------------------------------------------------------|---------------------------------------|
|
|
491
|
+
| code blocks, commands, identifiers that must be copy-safe |  |
|
|
492
|
+
|
|
493
|
+
Behavior:
|
|
494
|
+
|
|
495
|
+
```css
|
|
496
|
+
.cem-typography-script {
|
|
497
|
+
font-family: var(--cem-typography-script-font-family);
|
|
498
|
+
font-size: var(--cem-typography-script-font-size);
|
|
499
|
+
line-height: var(--cem-typography-script-line-height);
|
|
500
|
+
letter-spacing: var(--cem-typography-script-letter-spacing);
|
|
501
|
+
font-weight: var(--cem-typography-script-font-weight);
|
|
502
|
+
|
|
503
|
+
font-variant-ligatures: var(--cem-typography-script-font-variant-ligatures);
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### 6.5 Data (new)
|
|
508
|
+
|
|
509
|
+
Used for:
|
|
510
|
+
|
|
511
|
+
- numbers in tables, prices, measurements, timestamps, IDs
|
|
512
|
+
|
|
513
|
+
Reason:
|
|
514
|
+
|
|
515
|
+
- numeric alignment is crucial in scan/compare flows; use **tabular numerals**.
|
|
516
|
+
|
|
517
|
+
Behavior:
|
|
518
|
+
|
|
519
|
+
```css
|
|
520
|
+
.cem-typography-data {
|
|
521
|
+
font-family: var(--cem-typography-data-font-family);
|
|
522
|
+
font-size: var(--cem-typography-data-font-size);
|
|
523
|
+
line-height: var(--cem-typography-data-line-height);
|
|
524
|
+
letter-spacing: var(--cem-typography-data-letter-spacing);
|
|
525
|
+
font-weight: var(--cem-typography-data-font-weight);
|
|
526
|
+
|
|
527
|
+
font-variant-numeric: var(--cem-typography-data-font-variant-numeric);
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+

|
|
532
|
+
|
|
533
|
+
### 6.6 Initialism
|
|
534
|
+
|
|
535
|
+
| Used for | . |
|
|
536
|
+
|-----------------------------------------------------------------|--------------------------------------------------|
|
|
537
|
+
| acronyms, avatar initials, short codes meant to be “badge-like” |  |
|
|
538
|
+
|
|
539
|
+
Behavior:
|
|
540
|
+
|
|
541
|
+
```css
|
|
542
|
+
.cem-typography-initialism {
|
|
543
|
+
font-family: var(--cem-typography-initialism-font-family);
|
|
544
|
+
font-size: var(--cem-typography-initialism-font-size);
|
|
545
|
+
line-height: var(--cem-typography-initialism-line-height);
|
|
546
|
+
letter-spacing: var(--cem-typography-initialism-letter-spacing);
|
|
547
|
+
font-weight: var(--cem-typography-initialism-font-weight);
|
|
548
|
+
|
|
549
|
+
text-transform: var(--cem-typography-initialism-text-transform);
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### 6.7 Iconized
|
|
554
|
+
|
|
555
|
+
| Used for | . |
|
|
556
|
+
|------------------------------------------------------|----------------------------------------------------------|
|
|
557
|
+
| letter-as-icon (monograms, single-letter pictograms) |  |
|
|
558
|
+
|
|
559
|
+
Behavior:
|
|
560
|
+
|
|
561
|
+
```css
|
|
562
|
+
.cem-typography-iconized {
|
|
563
|
+
font-family: var(--cem-typography-iconized-font-family);
|
|
564
|
+
font-size: var(--cem-typography-iconized-font-size);
|
|
565
|
+
line-height: var(--cem-typography-iconized-line-height);
|
|
566
|
+
letter-spacing: var(--cem-typography-iconized-letter-spacing);
|
|
567
|
+
font-weight: var(--cem-typography-iconized-font-weight);
|
|
568
|
+
|
|
569
|
+
text-transform: var(--cem-typography-iconized-text-transform);
|
|
570
|
+
}
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### 6.8 Brand / Display (optional)
|
|
574
|
+
|
|
575
|
+
Used for:
|
|
576
|
+
|
|
577
|
+
- marketing headers, hero blocks, brand moments
|
|
578
|
+
|
|
579
|
+
Behavior:
|
|
580
|
+
|
|
581
|
+
```css
|
|
582
|
+
.cem-typography-brand {
|
|
583
|
+
font-family: var(--cem-typography-brand-font-family);
|
|
584
|
+
font-size: var(--cem-typography-brand-font-size);
|
|
585
|
+
line-height: var(--cem-typography-brand-line-height);
|
|
586
|
+
letter-spacing: var(--cem-typography-brand-letter-spacing);
|
|
587
|
+
font-weight: var(--cem-typography-brand-font-weight);
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## 7. Consumer-flow mapping (how to choose roles)
|
|
594
|
+
|
|
595
|
+
Use this table as a decision shortcut.
|
|
596
|
+
|
|
597
|
+
| Consumer flow purpose | Dominant typography role(s) | Default voice level |
|
|
598
|
+
|-----------------------|------------------------------------------------------|---------------------|
|
|
599
|
+
| Orient / Navigate | UI, Tag, Initialism | gentle → firm |
|
|
600
|
+
| Scan / Compare | Data, UI, Tag | regular → firm |
|
|
601
|
+
| Read / Learn | Reading | regular |
|
|
602
|
+
| Act | UI (often bold), Tag (when actions are chip-like) | firm |
|
|
603
|
+
| Confirm / Reflect | Reading (explanations), Data (metrics), Tag (status) | regular → firm |
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## 8. Density and accessibility modes
|
|
608
|
+
|
|
609
|
+
Typography must respond to accessibility settings and product density.
|
|
610
|
+
|
|
611
|
+
### 8.1 Density tokens (optional extension)
|
|
612
|
+
|
|
613
|
+
If you need an explicit density switch, add one semantic knob:
|
|
614
|
+
|
|
615
|
+
```css
|
|
616
|
+
:root {
|
|
617
|
+
--cem-typography-density: comfortable; /* compact | comfortable */
|
|
618
|
+
}
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
In compact density, prefer smaller sizes for UI and tags while keeping Reading stable.
|
|
622
|
+
|
|
623
|
+
### 8.2 Minimums
|
|
624
|
+
|
|
625
|
+
- Keep critical UI actions at `1rem`.
|
|
626
|
+
- Avoid reducing Reading line-height below `1.45`.
|
|
627
|
+
- Use `rem` so user scaling works.
|
|
628
|
+
|
|
629
|
+
### 8.3 Contrast modes
|
|
630
|
+
|
|
631
|
+
- **Do not** change font families as part of a contrast mode.
|
|
632
|
+
- **Do not** rescale the global type ramp for contrast modes; rely on user text scaling (`rem`) and density tokens.
|
|
633
|
+
- Contrast modes project primarily into **ink** (voice → `--cem-voice-*-ink-thickness`) and **non-color cues**
|
|
634
|
+
(underlines, outlines, separators) to avoid layout shifts.
|
|
635
|
+
|
|
636
|
+
---
|
|
637
|
+
|
|
638
|
+
## 9. Internationalization and fallback
|
|
639
|
+
|
|
640
|
+
Semantic tokens must include fallback coverage.
|
|
641
|
+
|
|
642
|
+
Guidelines:
|
|
643
|
+
|
|
644
|
+
- Always include a broad Unicode fallback (e.g., Noto Sans / Noto Sans Mono).
|
|
645
|
+
- Prefer font stacks that preserve x-height and metrics consistency.
|
|
646
|
+
- Validate all semantic roles on the languages you ship.
|
|
647
|
+
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
## 10. Practical implementation notes
|
|
651
|
+
|
|
652
|
+
### 10.1 Design tokens vs component tokens
|
|
653
|
+
|
|
654
|
+
- **Design tokens** define the semantic roles (this document).
|
|
655
|
+
- **Component tokens** map roles onto components (e.g., Button label uses UI; Table cells use Data).
|
|
656
|
+
|
|
657
|
+
### 10.2 Voice vs screen readers vs product read-aloud
|
|
658
|
+
|
|
659
|
+
**Screen readers** primarily follow HTML semantics and ARIA, not CSS typography. Do not rely on voice tokens to control
|
|
660
|
+
assistive technology output.
|
|
661
|
+
|
|
662
|
+
**Voice tokens** are designed to provide consistent prominence across:
|
|
663
|
+
|
|
664
|
+
- **Ink (visual):** use `--cem-voice-*-ink-thickness` and optional `--cem-voice-*-icon-stroke-multiplier`.
|
|
665
|
+
- **Product “read aloud”:** use `--cem-typography-*-speech-*` tokens as inputs to your TTS layer.
|
|
666
|
+
|
|
667
|
+
### 10.3 Example: SpeechSynthesis integration
|
|
668
|
+
|
|
669
|
+
This example reads the active typography role’s speech tokens from computed style and applies them to a TTS utterance.
|
|
670
|
+
|
|
671
|
+
```js
|
|
672
|
+
function cemSpeak( el, text )
|
|
673
|
+
{
|
|
674
|
+
const cs = getComputedStyle( el );
|
|
675
|
+
|
|
676
|
+
// Choose one: read from the role tokens applied to the element.
|
|
677
|
+
const rate = parseFloat( cs.getPropertyValue( '--cem-typography-reading-speech-rate' ) ) || 1;
|
|
678
|
+
const pitch = parseFloat( cs.getPropertyValue( '--cem-typography-reading-speech-pitch' ) ) || 1;
|
|
679
|
+
const volume = parseFloat( cs.getPropertyValue( '--cem-typography-reading-speech-volume' ) ) || 1;
|
|
680
|
+
|
|
681
|
+
const utter = new SpeechSynthesisUtterance( text );
|
|
682
|
+
utter.rate = rate;
|
|
683
|
+
utter.pitch = pitch;
|
|
684
|
+
utter.volume = volume;
|
|
685
|
+
|
|
686
|
+
speechSynthesis.speak( utter );
|
|
687
|
+
}
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
### 10.4 Don’t over-tokenize
|
|
691
|
+
|
|
692
|
+
Start with these semantic roles:
|
|
693
|
+
|
|
694
|
+
- Reading
|
|
695
|
+
- UI
|
|
696
|
+
- Tag
|
|
697
|
+
- Data
|
|
698
|
+
- Script
|
|
699
|
+
- Initialism
|
|
700
|
+
|
|
701
|
+
Add Brand/Iconized only when a real use-case exists.
|
|
702
|
+
|
|
703
|
+
---
|
|
704
|
+
|
|
705
|
+
## 11. Summary
|
|
706
|
+
|
|
707
|
+
This revision replaces the “typography as style” mindset with **typography as semantics**, and introduces **voice** as a
|
|
708
|
+
cross-modal axis:
|
|
709
|
+
|
|
710
|
+
- **Fontography** provides stable intent-driven families and feature policies.
|
|
711
|
+
- **Typography** defines bounded, accessible, i18n-friendly layout behavior.
|
|
712
|
+
- **Voice** provides modality-independent prominence mapped to:
|
|
713
|
+
- ink thickness (text weight / icon stroke)
|
|
714
|
+
- speech prosody (rate/pitch/volume) and optional SSML emphasis
|
|
715
|
+
- A dedicated **Data** semantic completes the consumer scan/compare flow.
|
|
716
|
+
|
|
717
|
+
The result is a token set that stays understandable to consumers of the design system, stable across brand changes, and
|
|
718
|
+
reusable across visual and vocal presentations.
|