@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.
Files changed (185) hide show
  1. package/.claude/settings.local.json +18 -0
  2. package/.gitattributes +4 -0
  3. package/.github/workflows/deploy.yml +59 -0
  4. package/.idea/copilot.data.migration.agent.xml +6 -0
  5. package/.idea/copilot.data.migration.ask.xml +6 -0
  6. package/.idea/copilot.data.migration.ask2agent.xml +6 -0
  7. package/.idea/copilot.data.migration.edit.xml +6 -0
  8. package/.idea/custom-element-dist.iml +2 -0
  9. package/.storybook/main.ts +20 -17
  10. package/.storybook/preview.ts +23 -23
  11. package/.yarn/install-state.gz +0 -0
  12. package/.yarnrc.yml +1 -0
  13. package/README.md +6 -4
  14. package/coverage/block-navigation.js +1 -1
  15. package/coverage/coverage-final.json +4 -3
  16. package/coverage/index.html +34 -19
  17. package/coverage/sorter.js +21 -7
  18. package/coverage/src/custom-element/coverage.svg +1 -1
  19. package/coverage/src/custom-element/custom-element.js/coverage.svg +1 -1
  20. package/coverage/src/custom-element/custom-element.js.html +448 -391
  21. package/coverage/src/custom-element/http-request.js/coverage.svg +1 -1
  22. package/coverage/src/custom-element/http-request.js.html +38 -17
  23. package/coverage/src/custom-element/index.html +26 -26
  24. package/coverage/src/custom-element/local-storage.js.html +1 -1
  25. package/coverage/src/custom-element/location-element.js.html +1 -1
  26. package/coverage/src/custom-element/module-url.js.html +1 -1
  27. package/coverage/src/index.html +1 -1
  28. package/coverage/src/material/theme/colors.js/coverage.svg +10 -0
  29. package/coverage/src/material/theme/colors.js.html +217 -0
  30. package/coverage/src/material/theme/coverage.svg +10 -0
  31. package/coverage/src/material/theme/index.html +116 -0
  32. package/coverage/src/mocks/handlers.ts.html +1 -1
  33. package/coverage/src/mocks/index.html +1 -1
  34. package/coverage/src/stories/frame.canvas.ts.html +1 -1
  35. package/coverage/src/stories/http-request.stories.ts.html +1 -1
  36. package/coverage/src/stories/index.html +1 -1
  37. package/coverage/src/stories/testStoryBook.ts.html +12 -12
  38. package/coverage/src/sum.ts.html +1 -1
  39. package/dist/custom-element-Bssk9jRy.cjs +97 -0
  40. package/dist/{custom-element-WnOqmEOe.js → custom-element-BzDjIYMe.js} +193 -183
  41. package/dist/custom-element-bundle.cjs +1 -1
  42. package/dist/custom-element-bundle.js +3 -3
  43. package/dist/demo/a.html +10 -3
  44. package/dist/demo/a.svg +26 -26
  45. package/dist/demo/html-template.html +4 -3
  46. package/dist/demo/s.xml +1 -75
  47. package/dist/demo/s.xslt +351 -72
  48. package/dist/demo/s1.xml +3706 -0
  49. package/dist/http-request-DSaowcG1.cjs +1 -0
  50. package/dist/{http-request-BOvP4KTl.js → http-request-DTCzZ1gc.js} +15 -9
  51. package/dist/mockServiceWorker.js +105 -63
  52. package/package.json +5 -4
  53. package/public/demo/a.html +10 -3
  54. package/public/demo/a.svg +26 -26
  55. package/public/demo/html-template.html +4 -3
  56. package/public/demo/s.xml +1 -75
  57. package/public/demo/s.xslt +351 -72
  58. package/public/demo/s1.xml +3706 -0
  59. package/public/mockServiceWorker.js +105 -63
  60. package/src/custom-element/custom-element.js +28 -9
  61. package/src/custom-element/demo/a.html +10 -3
  62. package/src/custom-element/demo/a.svg +26 -26
  63. package/src/custom-element/demo/html-template.html +4 -3
  64. package/src/custom-element/demo/s.xml +1 -75
  65. package/src/custom-element/demo/s.xslt +351 -72
  66. package/src/custom-element/demo/s1.xml +3706 -0
  67. package/src/custom-element/http-request.js +7 -0
  68. package/src/custom-element/ide/customData-dce.json +123 -0
  69. package/src/custom-element/ide/web-types-dce.json +128 -1
  70. package/src/custom-element/ide/web-types-xsl.json +1 -1
  71. package/src/material/angular.css +987 -987
  72. package/src/material/components/action.html +262 -0
  73. package/src/material/components/autocomplete.html +167 -239
  74. package/src/material/components/badge.html +238 -239
  75. package/src/material/components/dropdown.html +0 -1
  76. package/src/material/components/icon-link.html +160 -161
  77. package/src/material/components/icon.html +251 -252
  78. package/src/material/components/input.html +569 -570
  79. package/src/material/components/menu.html +235 -236
  80. package/src/material/components.html +157 -158
  81. package/src/material/demo.css +36 -36
  82. package/src/material/index.html +109 -110
  83. package/src/material/material.css +356 -356
  84. package/src/material/theme/Base-Principles.md +339 -0
  85. package/src/material/theme/README.md +298 -18
  86. package/src/material/theme/UI Domain Model in web applications.svg +1 -0
  87. package/src/material/theme/User Semantic Theme tokens.svg +1 -0
  88. package/src/material/theme/action-pending-poc.html +62 -0
  89. package/src/material/theme/actions-color.html +141 -0
  90. package/src/material/theme/colors-light.html +631 -0
  91. package/src/material/theme/colors-native.html +51 -0
  92. package/src/material/theme/colors-poc.html +66 -0
  93. package/src/material/theme/colors.html +297 -0
  94. package/src/material/theme/colors.js +44 -0
  95. package/src/material/theme/consumer-theme.css +745 -0
  96. package/src/material/theme/semantic.css +132 -132
  97. package/src/material/theme/style-bug.html +123 -0
  98. package/src/material/theme/theme-data.css +43 -0
  99. package/src/material/theme/theme-data.xhtml +2926 -0
  100. package/src/material/theme/todo.md +274 -0
  101. package/src/material/theme/tokens/action-colors.png +0 -0
  102. package/src/material/theme/tokens/cem-article-illustration-4x1-letterbox-2000x500.png +0 -0
  103. package/src/material/theme/tokens/cem-breakpoints.md +519 -0
  104. package/src/material/theme/tokens/cem-colors.md +715 -0
  105. package/src/material/theme/tokens/cem-consumerflow-typography-matrix.svg +198 -0
  106. package/src/material/theme/tokens/cem-coupling.md +372 -0
  107. package/src/material/theme/tokens/cem-data-vs-reading-numerals.svg +164 -0
  108. package/src/material/theme/tokens/cem-dimension.md +625 -0
  109. package/src/material/theme/tokens/cem-layering.md +562 -0
  110. package/src/material/theme/tokens/cem-m3-parity.md +343 -0
  111. package/src/material/theme/tokens/cem-responsive.md +238 -0
  112. package/src/material/theme/tokens/cem-shape.md +691 -0
  113. package/src/material/theme/tokens/cem-stroke-density-illustration-4to1-v3.svg +102 -0
  114. package/src/material/theme/tokens/cem-stroke.md +480 -0
  115. package/src/material/theme/tokens/cem-timing.md +198 -0
  116. package/src/material/theme/tokens/cem-typography-model-stack.svg +64 -0
  117. package/src/material/theme/tokens/cem-voice-fonts-typography.md +718 -0
  118. package/src/material/theme/tokens/cem-voice-ladder.svg +91 -0
  119. package/src/material/theme/tokens/chips.png +0 -0
  120. package/src/material/theme/tokens/columns-page.png +0 -0
  121. package/src/material/theme/tokens/initials.png +0 -0
  122. package/src/material/theme/tokens/nav-buttons.png +0 -0
  123. package/src/material/theme/tokens/script.png +0 -0
  124. package/src/material/theme/tokens/sufler.png +0 -0
  125. package/src/material/theme/tokens/typography-icons.png +0 -0
  126. package/src/mocks/versions.mock.ts +1 -1
  127. package/src/stories/__screenshots__/dom-merge.test.stories.ts/dom-merge-dom-merge-OrderPreservingOn2ndTransform-1.png +0 -0
  128. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-MultipleIfOrderingWorkaround-1.png +0 -0
  129. package/src/stories/dom-merge.test.stories.ts +25 -1
  130. package/src/stories/xslt-conditionals.test.stories.ts +492 -0
  131. package/src/stories/xslt-for-each.test.stories.ts +336 -0
  132. package/src/stories/xslt-if.test.stories.ts +89 -0
  133. package/storybook-static/assets/{Color-F6OSRLHC-Cbp293x2.js → Color-F6OSRLHC-DeDlDLjU.js} +1 -1
  134. package/storybook-static/assets/{Configure-BrFr4SLE.js → Configure-CH_tIP5N.js} +1 -1
  135. package/storybook-static/assets/{DocsRenderer-CFRXHY34-DhHzJiIO.js → DocsRenderer-CFRXHY34-Bc9EPsUI.js} +2 -2
  136. package/storybook-static/assets/{attributes.test.stories-Gg9LQTEK.js → attributes.test.stories-BtamFQkF.js} +1 -1
  137. package/storybook-static/assets/{css.test.stories-B_3ltOrx.js → css.test.stories-BfNxLgwr.js} +1 -1
  138. package/storybook-static/assets/{custom-element-CPnvJnn8.js → custom-element-CnmjNo0g.js} +6 -6
  139. package/storybook-static/assets/{dom-merge.test.stories-nQxcgLoM.js → dom-merge.test.stories-DxnitrLK.js} +47 -6
  140. package/storybook-static/assets/entry-preview-BNCt9WBs.js +26 -0
  141. package/storybook-static/assets/{entry-preview-docs-Dwczwtsc.js → entry-preview-docs-CbF8-81D.js} +2 -2
  142. package/storybook-static/assets/{external-template.test.stories-DZ-rjnfd.js → external-template.test.stories-BTsww7B0.js} +1 -1
  143. package/storybook-static/assets/{form.test.stories-DQhPYtMj.js → form.test.stories-DNJFtPJb.js} +1 -1
  144. package/storybook-static/assets/{frame.canvas-ClTqYyMN.js → frame.canvas-E5n9h6j1.js} +1 -1
  145. package/storybook-static/assets/{handlers-CLkps6Nz.js → handlers-Dvg8CAeR.js} +1 -1
  146. package/storybook-static/assets/http-request-BWeEEBkP.js +1 -0
  147. package/storybook-static/assets/{http-request.stories-jo0f73nw.js → http-request.stories-DgrBNle8.js} +1 -1
  148. package/storybook-static/assets/{iframe-CZwRpnn9.js → iframe-DiVWehoI.js} +11 -11
  149. package/storybook-static/assets/{index-Dr4PwNfd.js → index-CGuyH0k-.js} +87 -87
  150. package/storybook-static/assets/{index-CJQtnF9V.js → index-CdEbhcV9.js} +1 -1
  151. package/storybook-static/assets/index-DO1nmyvI.js +11 -0
  152. package/storybook-static/assets/{index-B68YUdzy.js → index-w6iX3YlR.js} +3 -3
  153. package/storybook-static/assets/{local-storage.test.stories-uA5EKRPf.js → local-storage.test.stories-Hwq80yUr.js} +1 -1
  154. package/storybook-static/assets/{location-element.test.stories-Cu-6Elcg.js → location-element.test.stories-mEhZzm7x.js} +1 -1
  155. package/storybook-static/assets/{module-url.test.stories-CD_wusXQ.js → module-url.test.stories-Bj46iT0V.js} +1 -1
  156. package/storybook-static/assets/{preview-CuCH40jj.js → preview-BjbXcJci.js} +2 -2
  157. package/storybook-static/assets/{preview-BFlNN3Wj.js → preview-Bn8igYMp.js} +1 -1
  158. package/storybook-static/assets/{preview-Cm4PPhHS.js → preview-CfuT8gak.js} +1 -1
  159. package/storybook-static/assets/{set-url.test.stories-CY7B9BVZ.js → set-url.test.stories-hzxLcqmm.js} +1 -1
  160. package/storybook-static/assets/{slice-events.test.stories-BVnPXm6e.js → slice-events.test.stories-DVyXFRU1.js} +1 -1
  161. package/storybook-static/assets/{slots.test.stories-Dxsa9KdA.js → slots.test.stories-CS544nS4.js} +1 -1
  162. package/storybook-static/assets/{version-select.test.stories-Buga1PAa.js → version-select.test.stories-D36nfYBq.js} +1 -1
  163. package/storybook-static/assets/xslt-conditionals.test.stories-BS1PTIHe.js +633 -0
  164. package/storybook-static/assets/xslt-for-each.test.stories-CtPS20RK.js +329 -0
  165. package/storybook-static/assets/xslt-if.test.stories-DcHrAMSY.js +71 -0
  166. package/storybook-static/demo/a.html +10 -3
  167. package/storybook-static/demo/a.svg +26 -26
  168. package/storybook-static/demo/html-template.html +4 -3
  169. package/storybook-static/demo/s.xml +1 -75
  170. package/storybook-static/demo/s.xslt +351 -72
  171. package/storybook-static/demo/s1.xml +3706 -0
  172. package/storybook-static/iframe.html +2 -2
  173. package/storybook-static/index.json +1 -1
  174. package/storybook-static/mockServiceWorker.js +105 -63
  175. package/storybook-static/project.json +1 -1
  176. package/storybook-static/sb-addons/essentials-controls-1/manager-bundle.js +69 -66
  177. package/storybook-static/sb-addons/essentials-docs-3/manager-bundle.js +62 -59
  178. package/dist/custom-element-6slVaFEs.cjs +0 -97
  179. package/dist/http-request-DPrY7mGh.cjs +0 -1
  180. package/storybook-static/assets/attributes.test.stories-CzWkKw0e.js +0 -1
  181. package/storybook-static/assets/entry-preview-DHVXbf3x.js +0 -26
  182. package/storybook-static/assets/external-template.test.stories-BivZqBTp.js +0 -1
  183. package/storybook-static/assets/http-request-DNq59pnj.js +0 -1
  184. package/storybook-static/assets/index-BwkS7JH_.js +0 -8
  185. 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
+ ![Sufler reading the text with various font sizes](./cem-article-illustration-4x1-letterbox-2000x500.png)
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
+ ![CEM Typography Model stack diagram with ontography, Typography, and Voice](./cem-typography-model-stack.svg)
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
+ ![cem-voice-ladder.svg](./cem-voice-ladder.svg)
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
+ ![Consumer flow → semantic typography roles → default voice](./cem-consumerflow-typography-matrix.svg)
423
+
424
+ ### 6.1 Reading
425
+
426
+ | Used for | . |
427
+ |----------------------------------------------------------------|-------------- -----------------------|
428
+ | explanations, help text, descriptions, articles, long content | ![2 column page in opened book](./columns-page.png) |
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 | ![navigation buttons image](./nav-buttons.png) |
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 | ![chips example image](./chips.png) |
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 | ![script example image](./script.png) |
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
+ ![script example image](./cem-data-vs-reading-numerals.svg)
532
+
533
+ ### 6.6 Initialism
534
+
535
+ | Used for | . |
536
+ |-----------------------------------------------------------------|--------------------------------------------------|
537
+ | acronyms, avatar initials, short codes meant to be “badge-like” | ![initials button example image](./initials.png) |
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) | ![initials button example image](./typography-icons.png) |
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.