@epa-wg/custom-element-dist 0.0.33 → 0.0.34

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 (175) hide show
  1. package/.claude/settings.local.json +18 -0
  2. package/.github/workflows/deploy.yml +59 -0
  3. package/.idea/copilot.data.migration.agent.xml +6 -0
  4. package/.idea/copilot.data.migration.ask.xml +6 -0
  5. package/.idea/copilot.data.migration.edit.xml +6 -0
  6. package/.idea/custom-element-dist.iml +2 -0
  7. package/.storybook/main.ts +20 -17
  8. package/.storybook/preview.ts +23 -23
  9. package/README.md +6 -4
  10. package/coverage/block-navigation.js +1 -1
  11. package/coverage/coverage-final.json +4 -3
  12. package/coverage/index.html +34 -19
  13. package/coverage/sorter.js +21 -7
  14. package/coverage/src/custom-element/coverage.svg +1 -1
  15. package/coverage/src/custom-element/custom-element.js/coverage.svg +1 -1
  16. package/coverage/src/custom-element/custom-element.js.html +435 -378
  17. package/coverage/src/custom-element/http-request.js/coverage.svg +1 -1
  18. package/coverage/src/custom-element/http-request.js.html +38 -17
  19. package/coverage/src/custom-element/index.html +26 -26
  20. package/coverage/src/custom-element/local-storage.js.html +1 -1
  21. package/coverage/src/custom-element/location-element.js.html +1 -1
  22. package/coverage/src/custom-element/module-url.js.html +1 -1
  23. package/coverage/src/index.html +1 -1
  24. package/coverage/src/material/theme/colors.js/coverage.svg +10 -0
  25. package/coverage/src/material/theme/colors.js.html +217 -0
  26. package/coverage/src/material/theme/coverage.svg +10 -0
  27. package/coverage/src/material/theme/index.html +116 -0
  28. package/coverage/src/mocks/handlers.ts.html +1 -1
  29. package/coverage/src/mocks/index.html +1 -1
  30. package/coverage/src/stories/frame.canvas.ts.html +1 -1
  31. package/coverage/src/stories/http-request.stories.ts.html +1 -1
  32. package/coverage/src/stories/index.html +1 -1
  33. package/coverage/src/stories/testStoryBook.ts.html +12 -12
  34. package/coverage/src/sum.ts.html +1 -1
  35. package/dist/{custom-element-WnOqmEOe.js → custom-element-BoYMoUtP.js} +193 -183
  36. package/dist/custom-element-BqtjrCRF.cjs +97 -0
  37. package/dist/custom-element-bundle.cjs +1 -1
  38. package/dist/custom-element-bundle.js +3 -3
  39. package/dist/demo/a.html +10 -3
  40. package/dist/demo/a.svg +26 -26
  41. package/dist/demo/html-template.html +4 -3
  42. package/dist/demo/s.xml +3856 -67
  43. package/dist/demo/s.xslt +13 -72
  44. package/dist/demo/s1.xml +3706 -0
  45. package/dist/http-request-DSaowcG1.cjs +1 -0
  46. package/dist/{http-request-BOvP4KTl.js → http-request-DTCzZ1gc.js} +15 -9
  47. package/package.json +2 -2
  48. package/public/demo/a.html +10 -3
  49. package/public/demo/a.svg +26 -26
  50. package/public/demo/html-template.html +4 -3
  51. package/public/demo/s.xml +3856 -67
  52. package/public/demo/s.xslt +13 -72
  53. package/public/demo/s1.xml +3706 -0
  54. package/src/custom-element/custom-element.js +28 -9
  55. package/src/custom-element/demo/a.html +10 -3
  56. package/src/custom-element/demo/a.svg +26 -26
  57. package/src/custom-element/demo/html-template.html +4 -3
  58. package/src/custom-element/demo/s.xml +3856 -67
  59. package/src/custom-element/demo/s.xslt +13 -72
  60. package/src/custom-element/demo/s1.xml +3706 -0
  61. package/src/custom-element/http-request.js +7 -0
  62. package/src/custom-element/ide/web-types-dce.json +1 -1
  63. package/src/custom-element/ide/web-types-xsl.json +1 -1
  64. package/src/material/angular.css +987 -987
  65. package/src/material/components/action.html +262 -0
  66. package/src/material/components/autocomplete.html +167 -239
  67. package/src/material/components/badge.html +238 -239
  68. package/src/material/components/dropdown.html +0 -1
  69. package/src/material/components/icon-link.html +160 -161
  70. package/src/material/components/icon.html +251 -252
  71. package/src/material/components/input.html +569 -570
  72. package/src/material/components/menu.html +235 -236
  73. package/src/material/components.html +157 -158
  74. package/src/material/demo.css +36 -36
  75. package/src/material/index.html +109 -110
  76. package/src/material/material.css +356 -356
  77. package/src/material/theme/Base-Principles.md +339 -0
  78. package/src/material/theme/README.md +298 -18
  79. package/src/material/theme/UI Domain Model in web applications.svg +1 -0
  80. package/src/material/theme/User Semantic Theme tokens.svg +1 -0
  81. package/src/material/theme/action-pending-poc.html +62 -0
  82. package/src/material/theme/actions-color.html +141 -0
  83. package/src/material/theme/colors-light.html +631 -0
  84. package/src/material/theme/colors-native.html +51 -0
  85. package/src/material/theme/colors-poc.html +66 -0
  86. package/src/material/theme/colors.html +297 -0
  87. package/src/material/theme/colors.js +44 -0
  88. package/src/material/theme/consumer-theme.css +745 -0
  89. package/src/material/theme/semantic.css +132 -132
  90. package/src/material/theme/style-bug.html +123 -0
  91. package/src/material/theme/theme-data.css +43 -0
  92. package/src/material/theme/theme-data.xhtml +2926 -0
  93. package/src/material/theme/todo.md +274 -0
  94. package/src/material/theme/tokens/action-colors.png +0 -0
  95. package/src/material/theme/tokens/cem-article-illustration-4x1-letterbox-2000x500.png +0 -0
  96. package/src/material/theme/tokens/cem-breakpoints.md +519 -0
  97. package/src/material/theme/tokens/cem-colors.md +715 -0
  98. package/src/material/theme/tokens/cem-consumerflow-typography-matrix.svg +198 -0
  99. package/src/material/theme/tokens/cem-coupling.md +372 -0
  100. package/src/material/theme/tokens/cem-data-vs-reading-numerals.svg +164 -0
  101. package/src/material/theme/tokens/cem-dimension.md +625 -0
  102. package/src/material/theme/tokens/cem-layering.md +562 -0
  103. package/src/material/theme/tokens/cem-m3-parity.md +343 -0
  104. package/src/material/theme/tokens/cem-responsive.md +238 -0
  105. package/src/material/theme/tokens/cem-shape.md +691 -0
  106. package/src/material/theme/tokens/cem-stroke-density-illustration-4to1-v3.svg +102 -0
  107. package/src/material/theme/tokens/cem-stroke.md +480 -0
  108. package/src/material/theme/tokens/cem-timing.md +198 -0
  109. package/src/material/theme/tokens/cem-typography-model-stack.svg +64 -0
  110. package/src/material/theme/tokens/cem-voice-fonts-typography.md +718 -0
  111. package/src/material/theme/tokens/cem-voice-ladder.svg +91 -0
  112. package/src/material/theme/tokens/chips.png +0 -0
  113. package/src/material/theme/tokens/columns-page.png +0 -0
  114. package/src/material/theme/tokens/initials.png +0 -0
  115. package/src/material/theme/tokens/nav-buttons.png +0 -0
  116. package/src/material/theme/tokens/script.png +0 -0
  117. package/src/material/theme/tokens/sufler.png +0 -0
  118. package/src/material/theme/tokens/typography-icons.png +0 -0
  119. package/src/mocks/versions.mock.ts +1 -1
  120. package/src/stories/__screenshots__/dom-merge.test.stories.ts/dom-merge-dom-merge-OrderPreservingOn2ndTransform-1.png +0 -0
  121. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-MultipleIfOrderingWorkaround-1.png +0 -0
  122. package/src/stories/dom-merge.test.stories.ts +25 -1
  123. package/src/stories/xslt-conditionals.test.stories.ts +492 -0
  124. package/src/stories/xslt-if.test.stories.ts +89 -0
  125. package/storybook-static/assets/{Color-F6OSRLHC-Cbp293x2.js → Color-F6OSRLHC-CzTOSlqB.js} +1 -1
  126. package/storybook-static/assets/{Configure-BrFr4SLE.js → Configure-7GqRsAoJ.js} +1 -1
  127. package/storybook-static/assets/{DocsRenderer-CFRXHY34-DhHzJiIO.js → DocsRenderer-CFRXHY34-Duc5rSIm.js} +2 -2
  128. package/storybook-static/assets/{attributes.test.stories-Gg9LQTEK.js → attributes.test.stories-DYuxF8h1.js} +1 -1
  129. package/storybook-static/assets/{css.test.stories-B_3ltOrx.js → css.test.stories-LOmvINyb.js} +1 -1
  130. package/storybook-static/assets/{custom-element-CPnvJnn8.js → custom-element-Bwx7otrT.js} +6 -6
  131. package/storybook-static/assets/{dom-merge.test.stories-nQxcgLoM.js → dom-merge.test.stories-CEKhWjaS.js} +47 -6
  132. package/storybook-static/assets/entry-preview-BNCt9WBs.js +26 -0
  133. package/storybook-static/assets/{entry-preview-docs-Dwczwtsc.js → entry-preview-docs-CbF8-81D.js} +2 -2
  134. package/storybook-static/assets/{external-template.test.stories-DZ-rjnfd.js → external-template.test.stories-jHu0wsJ-.js} +1 -1
  135. package/storybook-static/assets/{form.test.stories-DQhPYtMj.js → form.test.stories-CUyUnmwP.js} +1 -1
  136. package/storybook-static/assets/{frame.canvas-ClTqYyMN.js → frame.canvas-E5n9h6j1.js} +1 -1
  137. package/storybook-static/assets/{handlers-CLkps6Nz.js → handlers-F7GUfMqr.js} +1 -1
  138. package/storybook-static/assets/http-request-BWeEEBkP.js +1 -0
  139. package/storybook-static/assets/{http-request.stories-jo0f73nw.js → http-request.stories-wyX5-QOv.js} +1 -1
  140. package/storybook-static/assets/{iframe-CZwRpnn9.js → iframe-BS_DPWl0.js} +11 -11
  141. package/storybook-static/assets/{index-Dr4PwNfd.js → index-CGuyH0k-.js} +87 -87
  142. package/storybook-static/assets/{index-CJQtnF9V.js → index-DB7LLObI.js} +1 -1
  143. package/storybook-static/assets/index-DO1nmyvI.js +11 -0
  144. package/storybook-static/assets/{index-B68YUdzy.js → index-V1EGs-wm.js} +3 -3
  145. package/storybook-static/assets/{local-storage.test.stories-uA5EKRPf.js → local-storage.test.stories-BxOhsf1k.js} +1 -1
  146. package/storybook-static/assets/{location-element.test.stories-Cu-6Elcg.js → location-element.test.stories-DqhvvUoa.js} +1 -1
  147. package/storybook-static/assets/{module-url.test.stories-CD_wusXQ.js → module-url.test.stories-C1gG9G7Y.js} +1 -1
  148. package/storybook-static/assets/{preview-BFlNN3Wj.js → preview-Bn8igYMp.js} +1 -1
  149. package/storybook-static/assets/{preview-CuCH40jj.js → preview-Cwy1XFu2.js} +2 -2
  150. package/storybook-static/assets/{preview-Cm4PPhHS.js → preview-D6sehqkw.js} +1 -1
  151. package/storybook-static/assets/{set-url.test.stories-CY7B9BVZ.js → set-url.test.stories-BKQNdknJ.js} +1 -1
  152. package/storybook-static/assets/{slice-events.test.stories-BVnPXm6e.js → slice-events.test.stories-ChqULCeA.js} +1 -1
  153. package/storybook-static/assets/{slots.test.stories-Dxsa9KdA.js → slots.test.stories-BlyLoCRe.js} +1 -1
  154. package/storybook-static/assets/{version-select.test.stories-Buga1PAa.js → version-select.test.stories-CPGSh1tR.js} +1 -1
  155. package/storybook-static/assets/xslt-conditionals.test.stories-YC6QPqWZ.js +633 -0
  156. package/storybook-static/assets/xslt-if.test.stories-BRSWy2-x.js +71 -0
  157. package/storybook-static/demo/a.html +10 -3
  158. package/storybook-static/demo/a.svg +26 -26
  159. package/storybook-static/demo/html-template.html +4 -3
  160. package/storybook-static/demo/s.xml +3856 -67
  161. package/storybook-static/demo/s.xslt +13 -72
  162. package/storybook-static/demo/s1.xml +3706 -0
  163. package/storybook-static/iframe.html +2 -2
  164. package/storybook-static/index.json +1 -1
  165. package/storybook-static/project.json +1 -1
  166. package/storybook-static/sb-addons/essentials-controls-1/manager-bundle.js +69 -66
  167. package/storybook-static/sb-addons/essentials-docs-3/manager-bundle.js +62 -59
  168. package/dist/custom-element-6slVaFEs.cjs +0 -97
  169. package/dist/http-request-DPrY7mGh.cjs +0 -1
  170. package/storybook-static/assets/attributes.test.stories-CzWkKw0e.js +0 -1
  171. package/storybook-static/assets/entry-preview-DHVXbf3x.js +0 -26
  172. package/storybook-static/assets/external-template.test.stories-BivZqBTp.js +0 -1
  173. package/storybook-static/assets/http-request-DNq59pnj.js +0 -1
  174. package/storybook-static/assets/index-BwkS7JH_.js +0 -8
  175. package/storybook-static/assets/module-url.test.stories-CTjUAk3J.js +0 -1
@@ -0,0 +1,715 @@
1
+ # Semantic Palettes and Action States
2
+
3
+ **Status:** Canonical (v1.0)
4
+ **Last updated:** 2025-12-21
5
+ **Taxonomy placement:** D0. Color (Emotional Palette)
6
+ **Audience:** Design Systems, Product Design, Front-End Engineering
7
+
8
+ ---
9
+
10
+ CEM uses **color** as the primary channel for communicating, using a **branded palette** to express:
11
+
12
+ - using **branded palette** express
13
+ - **Emotional intent:** what the interface wants the user to feel (trust, danger, creativity, etc.)
14
+ - **Interaction meaning:** what an action will do (primary, destructive, alternate, etc.)
15
+ - **State progression:** how an element's condition changes (default → hover → active → pending)
16
+
17
+ **Companion specs:**
18
+ - **D1. Space & Rhythm** ([`cem-dimension.md`](./cem-dimension.md)) — spacing scale, density modes, and layout gaps
19
+ - **D2. Coupling & Compactness** ([`cem-coupling.md`](./cem-coupling.md)) — density affects perceived color intensity and separability
20
+ - **D3. Shape — Bend** ([`cem-shape.md`](./cem-shape.md)) — rounded shapes soften color impact
21
+ - **D4. Layering** ([`cem-layering.md`](./cem-layering.md)) — tonal shifts for depth perception (recess/lift)
22
+ - **D5. Stroke & Separation** ([`cem-stroke.md`](./cem-stroke.md)) — focus/selection colors; D0 defines hue, D5 defines geometry
23
+ - **D6. Typography** ([`cem-voice-fonts-typography.md`](./cem-voice-fonts-typography.md)) — text contrast requirements
24
+ - **D7. Time & Motion** ([`cem-timing.md`](./cem-timing.md)) — color transition timing
25
+
26
+ ## Table of contents
27
+
28
+ 1. [Scope](#1-scope)
29
+ 2. [Design principles](#2-design-principles)
30
+ 3. [Token taxonomy](#3-token-taxonomy)
31
+ 4. [Base branded color family](#4-base-branded-color-family)
32
+ 5. [Emotional palette](#5-emotional-palette)
33
+ 6. [Theme modes](#6-theme-modes)
34
+ 7. [Action intent and state tokens](#7-action-intent-and-state-tokens)
35
+ 8. [Zebra outline colors](#8-zebra-outline-colors)
36
+ 9. [System colors and forced-colors](#9-system-colors-and-forced-colors)
37
+ 10. [Component mapping checklist](#10-component-mapping-checklist)
38
+ 11. [Accessibility and QA](#11-accessibility-and-qa)
39
+ 12. [Implementation guidance](#12-implementation-guidance)
40
+ 13. [Governance and versioning](#13-governance-and-versioning)
41
+ 14. [Canonical token summary](#14-canonical-token-summary)
42
+ 15. [References](#15-references)
43
+
44
+ ---
45
+
46
+ ## 1. Scope
47
+
48
+ ### 1.1 What D0 controls (and what it does not define)
49
+
50
+ D0 (Color) defines:
51
+
52
+ - The **semantic meaning** of color: emotional palette, action intent colors, and state colors.
53
+ - **System/forced-colors mapping** for survivable theming in high-contrast environments.
54
+ - The **color endpoints** used by other dimensions (e.g., zebra stripe *colors*).
55
+
56
+ D0 (Color) does **not** define:
57
+
58
+ - Stroke geometry (ring widths, stripe layout, offsets): see **D5 Stroke**.
59
+ - Spacing/density and hit targets: see **D1 Space & Rhythm**.
60
+ - Layer depth/physical appearance (shadows, blur): see **D4 Layering**.
61
+ - Motion durations/easing: see **D7 Motion**.
62
+
63
+ This spec defines **consumer-semantic color tokens** for CEM:
64
+
65
+ - A compact **branded color family** (`--cem-color-*`) used as implementation substrate.
66
+ - An **emotional palette** (`--cem-palette-*`) that expresses *meaning* in user language (comfort, trust, danger, etc.).
67
+ - **Action intent and state tokens** (`--cem-action-*`) for buttons/steps and other “do something” controls.
68
+ - **Zebra outline colors** (`--cem-zebra-*`) used with D5 Stroke to express selection/focus/target without relying on
69
+ fill.
70
+ - **System/forced-colors integration** so CEM remains accessible and compatible with platform theming.
71
+
72
+ Non-goals:
73
+
74
+ - This document does not define shape/stroke/spacing metrics (see D5 Stroke, D1 Space, etc.).
75
+ - This document does not prescribe a single brand palette; it specifies semantic endpoints and default reference
76
+ mappings.
77
+
78
+ ---
79
+
80
+ ## 2. Design principles
81
+
82
+ ### 2.1 Consumer-semantic meaning first
83
+
84
+ Tokens are named for **what the user experiences** (comfort, danger, trust) and for **flow semantics** (primary,
85
+ destructive, selected, pending), rather than for RGB/hex values.
86
+
87
+ ### 2.2 State separation is multi-channel
88
+
89
+ CEM intentionally separates meaning across channels:
90
+
91
+ - **Background/fill** for “background-driven” states (default/hover/active/pending/disabled).
92
+ - **Zebra outline** (D5 + `--cem-zebra-*`) for high-salience but non-fill states (focus/target/selected).
93
+ - **Marker/text** for required/indeterminate and other information-bearing states.
94
+
95
+ This avoids overloading color fill and improves accessibility in compact/dense UIs.
96
+
97
+ ### 2.3 Forced-colors is first-class
98
+
99
+ ### 2.4 Bounded variation (governance by design)
100
+
101
+ To avoid “palette explosion”, D0 constrains variation intentionally:
102
+
103
+ - **Stable semantic set:** emotions and action intents are a fixed vocabulary.
104
+ - **Fixed brightness variants:** branded hues use a small set of variants (`xl`, `l`, `d`, `xd`), not per-component
105
+ shades.
106
+ - **Formulaic state progression:** hover/active/pending are derived via `color-mix()` rather than hand-picked colors.
107
+ - **Theme modes are adapters:** theme modes remap the same semantics; they do not introduce new semantics.
108
+
109
+ ### 2.5 Cross-dimension coupling (informative)
110
+
111
+ - **D0 → D4 (Layering):** surface/overlay colors must preserve legibility as layers change.
112
+ - **D0 → D5 (Stroke):** focus/selection meaning is primarily expressed via **outline channels** (zebra) where fill must
113
+ not be relied upon.
114
+ - **D0 → D6 (Typography):** text tokens and weight strategies exist to preserve contrast when fills collapse.
115
+ - **D0 → D7 (Motion):** color changes should align with feedback timing (e.g., hover is immediate; pending is
116
+ persistent).
117
+
118
+ When forced-colors is active, **system colors win**. CEM must preserve semantics using `Canvas`, `CanvasText`,
119
+ `Highlight`, `SelectedItem`, etc., and avoid losing meaning when shadows/glows are dropped by the UA.
120
+
121
+ ---
122
+
123
+ ## 3. Token taxonomy
124
+
125
+ ### 3.1 Consumer color vocabulary (informative)
126
+
127
+ **Emotional terms** (what the interface wants the user to feel):
128
+
129
+ | Term | Primary palette token | Typical usage |
130
+ |--------------|------------------------------|-------------------------------------------|
131
+ | comfort | `--cem-palette-comfort` | canvas/surfaces, low-salience backgrounds |
132
+ | calm | `--cem-palette-calm` | subtle affordances, secondary emphasis |
133
+ | trust | `--cem-palette-trust` | primary emphasis, highlights |
134
+ | enthusiasm | `--cem-palette-enthusiasm` | alternate emphasis, “positive energy” |
135
+ | creativity | `--cem-palette-creativity` | exploration, novelty |
136
+ | danger | `--cem-palette-danger` | errors, destructive affordances |
137
+ | conservative | `--cem-palette-conservative` | neutral/disabled, “quiet UI” |
138
+
139
+ **Action terms** (what an action will do):
140
+
141
+ | Term | Intent token prefix | Typical usage |
142
+ |-------------|------------------------------|-------------------------------|
143
+ | primary | `--cem-action-primary-*` | default “go forward” action |
144
+ | explicit | `--cem-action-explicit-*` | strong call-to-action |
145
+ | contextual | `--cem-action-contextual-*` | within-context action |
146
+ | alternate | `--cem-action-alternate-*` | secondary/alternate action |
147
+ | destructive | `--cem-action-destructive-*` | deletion, irreversible change |
148
+
149
+ **State terms** (how condition changes):
150
+
151
+ | State | Channel | Notes |
152
+ |----------------------------|-------------------|------------------------------------------------|
153
+ | disabled/readonly/editable | background + text | subdued progression (see §7.2) |
154
+ | hover/active/pending | background + text | formulaic `color-mix()` progression (see §7.2) |
155
+ | focus/selected/target | outline (zebra) | do not rely on fill alone (see §8) |
156
+
157
+ ### 3.2 Token model: branded → emotional → action
158
+
159
+ ```
160
+ Branded hues (implementation substrate)
161
+ --cem-color-{hue}-{variant}
162
+
163
+
164
+ Emotional palette (semantic contract)
165
+ --cem-palette-{emotion} (+ -x / -text / -text-x)
166
+
167
+
168
+ Action intents (consumer-facing API)
169
+ --cem-action-{intent}-{state}-{attribute}
170
+ ```
171
+
172
+ ### 3.3 Why three layers?
173
+
174
+ - **Brand control:** adjust the branded family without breaking product semantics.
175
+ - **Semantic stability:** emotions/intents remain stable across themes.
176
+ - **Implementation clarity:** components consume action/state endpoints; they do not depend on raw hues.
177
+
178
+ CEM color endpoints are layered:
179
+
180
+ 1. **Base branded family (implementation):** `--cem-color-{hue}-{variant}`
181
+ 2. **Emotional palette (semantic):** `--cem-palette-{emotion}` and `--cem-palette-{emotion}-text`
182
+ 3. **Action tokens (flow semantic):** `--cem-action-{intent}-{state}-{attribute}`
183
+ 4. **Zebra outline colors (state channel):** `--cem-zebra-color-0..3` + strip size
184
+
185
+ **Rule:** consumers should theme primarily by adjusting **palette** and (optionally) **base colors**; product code
186
+ should depend on palette/action/zebra endpoints.
187
+
188
+ ---
189
+
190
+ ## 4. Base branded color family
191
+
192
+ ### 4.1 Brightness variants (selection guidance)
193
+
194
+ Branded hues are provided in a small, repeatable set of brightness variants:
195
+
196
+ | Variant | Meaning (relative) | Typical role |
197
+ |---------|--------------------|------------------------------------------------------------------------|
198
+ | `xl` | lightest | large surface fills in light schemes; extreme contrast partner in dark |
199
+ | `l` | light | standard surface/intent fill in light schemes |
200
+ | `d` | dark | standard surface/intent fill in dark schemes |
201
+ | `xd` | darkest | extreme contrast partner in light schemes; deep surfaces in dark |
202
+
203
+ ### 4.2 Contrast pairing rule of thumb
204
+
205
+ When selecting a safe pairing (especially for text and outlines), prefer **opposite ends**:
206
+
207
+ - On **light** backgrounds (`xl`/`l`): pair with `d` or `xd` for text/outline.
208
+ - On **dark** backgrounds (`d`/`xd`): pair with `l` or `xl` for text/outline.
209
+
210
+ ### 4.3 Neutral (grey) exception
211
+
212
+ The neutral/grey family is intentionally smaller (typically `l` + `d`) and is used primarily via the **conservative**
213
+ palette.
214
+
215
+ The base family is a small set of named hues with a few variants. These are **reference values** (from
216
+ `theme-data.xhtml`) and may be overridden by a brand, as long as the semantic palette mappings remain coherent.
217
+
218
+ | Token | Hue | Variant | Hex | Label | Intended use |
219
+ |-------------------------|--------|---------|-----------|--------------------|--------------------------------------------|
220
+ | `--cem-color-blue-xl` | blue | xl | `#faf9fd` | Lightest blue | Comfort/trust emotion (light scene) |
221
+ | `--cem-color-blue-l` | blue | l | `#d7e3ff` | Light blue | Trust palette, attention semantic |
222
+ | `--cem-color-blue-d` | blue | d | `#002f65` | Dark blue | Trust palette (dark theme) |
223
+ | `--cem-color-blue-xd` | blue | xd | `#1a1b1f` | Darkest blue | Comfort/trust emotion (dark scene) |
224
+ | `--cem-color-brown-xl` | brown | xl | `#d7ccc8` | Extra light brown | Conservative palette (light theme) |
225
+ | `--cem-color-brown-l` | brown | l | `#a1887f` | Light brown | Conservative emotion, brand-3 |
226
+ | `--cem-color-brown-d` | brown | d | `#4e342e` | Dark brown | Conservative palette (dark theme) |
227
+ | `--cem-color-brown-xd` | brown | xd | `#3e2723` | Extra dark brown | Conservative palette (dark theme, extreme) |
228
+ | `--cem-color-cyan-xl` | cyan | xl | `#f1fefe` | Extra light cyan | Used for comfort palette (light scenes) |
229
+ | `--cem-color-cyan-l` | cyan | l | `#00fbfb` | Light cyan | Calm palette, creativity accent |
230
+ | `--cem-color-cyan-d` | cyan | d | `#006a6a` | Dark cyan | Calm palette (dark theme) |
231
+ | `--cem-color-cyan-xd` | cyan | xd | `#001010` | Extra dark cyan | Used for comfort palette (dark scenes) |
232
+ | `--cem-color-grey-l` | grey | l | `#f1f1eb` | Light grey | Conservative palette, neutral backgrounds |
233
+ | `--cem-color-grey-d` | grey | d | `#1a1c18` | Dark grey | Conservative palette (dark theme) |
234
+ | `--cem-color-orange-xl` | orange | xl | `#f0f070` | Extra light yellow | Enthusiasm palette (light theme) |
235
+ | `--cem-color-orange-l` | orange | l | `#ffe082` | Light orange | Enthusiasm emotion, brand-2 |
236
+ | `--cem-color-orange-d` | orange | d | `#723600` | Dark orange | Enthusiasm hype (dark theme) |
237
+ | `--cem-color-orange-xd` | orange | xd | `#502400` | Extra dark orange | Enthusiasm palette (dark theme, extreme) |
238
+ | `--cem-color-purple-xl` | purple | xl | `#f3e5f5` | Extra light purple | Creativity palette (light theme) |
239
+ | `--cem-color-purple-l` | purple | l | `#e1bee7` | Light purple | Creativity emotion, brand-1 |
240
+ | `--cem-color-purple-d` | purple | d | `#6a1b9a` | Dark purple | Creativity palette (dark theme) |
241
+ | `--cem-color-purple-xd` | purple | xd | `#4a148c` | Extra dark purple | Creativity palette (dark theme, extreme) |
242
+ | `--cem-color-red-xl` | red | xl | `#ffb4ab` | Extra light red | Danger palette (light theme) |
243
+ | `--cem-color-red-l` | red | l | `#ba1a1a` | Light red | Danger emotion, alert semantic |
244
+ | `--cem-color-red-d` | red | d | `#690005` | Dark red | Danger palette (dark theme) |
245
+ | `--cem-color-red-xd` | red | xd | `#410002` | Extra dark red | Danger palette (dark theme, extreme) |
246
+
247
+ Variant semantics:
248
+
249
+ - `xl` / `l`: light-scene support (surfaces, containers, accents)
250
+ - `d` / `xd`: dark-scene support (surfaces, ink-safe accents)
251
+
252
+ ---
253
+
254
+ ## 5. Emotional palette
255
+
256
+ The emotional palette is the **primary semantic contract** for color.
257
+
258
+ Reference mappings (from `theme-data.xhtml`) use `light-dark()` so a single token resolves appropriately for light vs dark schemes.
259
+
260
+ | Token | Role | Light / Dark mapping (reference) | Usage |
261
+ |-------------------------------------|------------------------------|-------------------------------------------|--------------------------------------------------|
262
+ | `--cem-palette-comfort` | Base comfort color | cyan-xl (#f1fefe) / cyan-xd (#001010) | Main canvas/background |
263
+ | `--cem-palette-comfort-x` | Comfort extreme variant | cyan-xd (#001010) / cyan-xl (#f1fefe) | Used in color-mix for state variations |
264
+ | `--cem-palette-comfort-text` | Comfort text color | cyan-xd (#001010) / cyan-xl (#f1fefe) | Primary text on comfort backgrounds |
265
+ | `--cem-palette-comfort-text-x` | Comfort extreme text | cyan-xl (#f1fefe) / cyan-xd (#001010) | Text on extreme variant backgrounds |
266
+ | `--cem-palette-calm` | Base calm color | cyan-l (#00fbfb) / cyan-d (#006a6a) | Foreground elements |
267
+ | `--cem-palette-calm-x` | Calm extreme variant | cyan-d (#006a6a) / cyan-l (#00fbfb) | Inverted calm color |
268
+ | `--cem-palette-calm-text` | Calm text color | Uses comfort-text | Text on calm backgrounds |
269
+ | `--cem-palette-calm-text-x` | Calm extreme text | Uses comfort-text-x | Text on extreme calm backgrounds |
270
+ | `--cem-palette-trust` | Base trust color | blue-l (#d7e3ff) / blue-d (#002f65) | Primary actions, highlights |
271
+ | `--cem-palette-trust-x` | Trust extreme variant | blue-d (#002f65) / blue-l (#d7e3ff) | Darker/lighter trust variation |
272
+ | `--cem-palette-trust-text` | Trust text color | comfort-text / white | Text on trust backgrounds |
273
+ | `--cem-palette-trust-text-x` | Trust extreme text | Uses comfort-text-x | Text on extreme trust backgrounds |
274
+ | `--cem-palette-enthusiasm` | Base enthusiasm color | orange-l (#ffe082) / orange-d (#723600) | Brand-2, alternate actions |
275
+ | `--cem-palette-enthusiasm-x` | Enthusiasm extreme variant | orange-xd (#502400) / orange-xl (#f0f070) | Darker/lighter enthusiasm variation |
276
+ | `--cem-palette-enthusiasm-text` | Enthusiasm text color | comfort-text / white | Text on enthusiasm backgrounds |
277
+ | `--cem-palette-enthusiasm-text-x` | Enthusiasm extreme text | Uses comfort-text-x | Text on extreme enthusiasm backgrounds |
278
+ | `--cem-palette-creativity` | Base creativity color | purple-l (#e1bee7) / purple-d (#6a1b9a) | Brand-1, explicit actions |
279
+ | `--cem-palette-creativity-x` | Creativity extreme variant | purple-d (#6a1b9a) / purple-l (#e1bee7) | Darker/lighter creativity variation |
280
+ | `--cem-palette-creativity-text` | Creativity text color | Uses comfort-text | Text on creativity backgrounds |
281
+ | `--cem-palette-creativity-text-x` | Creativity extreme text | Uses comfort-text-x | Text on extreme creativity backgrounds |
282
+ | `--cem-palette-danger` | Base danger color | red-l (#ba1a1a) / red-d (#690005) | Error messages, destructive actions |
283
+ | `--cem-palette-danger-x` | Danger extreme variant | red-d (#690005) / red-l (#ba1a1a) | Darker/lighter danger variation |
284
+ | `--cem-palette-danger-text` | Danger text color | comfort-text-x / comfort-text | Text on danger backgrounds |
285
+ | `--cem-palette-danger-text-x` | Danger extreme text | Uses orange-xl | High contrast text on extreme danger backgrounds |
286
+ | `--cem-palette-conservative` | Base conservative color | grey-l (#f1f1eb) / grey-d (#1a1c18) | Brand-3, disabled states |
287
+ | `--cem-palette-conservative-x` | Conservative extreme variant | grey-d (#1a1c18) / grey-l (#f1f1eb) | Darker/lighter conservative variation |
288
+ | `--cem-palette-conservative-text` | Conservative text color | Uses comfort-text | Text on conservative backgrounds |
289
+ | `--cem-palette-conservative-text-x` | Conservative extreme text | Uses comfort-text-x | Text on extreme conservative backgrounds |
290
+
291
+ ### 5.1 Semantics of the core emotions
292
+
293
+ - **comfort:** neutral surface/canvas
294
+ - **calm:** low-salience affordances, calm emphasis
295
+ - **trust:** primary emphasis, highlight, “go forward”
296
+ - **enthusiasm:** alternate/secondary positive emphasis
297
+ - **creativity:** explicit action affordance (the button you press)
298
+ - **danger:** errors and destructive actions
299
+ - **conservative:** low-emphasis/disabled/brand-3 support
300
+
301
+ ---
302
+
303
+ ## 6. Theme modes
304
+
305
+ CEM defines 5 operational modes for color behavior:
306
+
307
+ - `native`: rely on system colors (`Canvas`, `CanvasText`, etc.)
308
+ - `light`: branded palette in light scheme
309
+ - `dark`: branded palette in dark scheme
310
+ - `contrast-light`: minimize fill differences; emphasize outlines/markers
311
+ - `contrast-dark`: same, in dark scheme
312
+
313
+ **Normative expectations:**
314
+
315
+ - `native` MUST preserve meaning using system semantic colors (no hard-coded hex assumptions).
316
+ - `contrast-*` MUST NOT encode state primarily via background darkness; state must remain legible via zebra outline and
317
+ markers.
318
+
319
+ ---
320
+
321
+ ## 7. Action intent and state tokens
322
+
323
+ Action tokens encode **user-flow intent** (primary, explicit, destructive, etc.) and **interaction/state**.
324
+
325
+
326
+ ### 7.0 Visual reference: emotional palette gradations (light theme)
327
+
328
+ ![action-colors.png](./action-colors.png)
329
+
330
+ **Supplemental title:** Light theme — Emotional palette gradations across interaction states (action intents).
331
+
332
+ Notes (interpretation):
333
+ - The base color aligns with the `default` state row.
334
+ - As interaction escalates (hover → active → pending), tones shift toward the extreme variant (`*-x`) for higher salience.
335
+ - The upward direction ends in neutral/gray for `disabled`, preserving “less available” semantics.
336
+
337
+ ### 7.1 Action intent mapping (reference)
338
+
339
+ | Action intent | Emotional palette | Branded (light) | Branded (dark) | Primary token |
340
+ |---------------|-------------------|--------------------|--------------------|-----------------------------------------------|
341
+ | `explicit` | `creativity` | purple-l (#e1bee7) | purple-d (#6a1b9a) | `--cem-action-explicit-default-background` |
342
+ | `primary` | `trust` | blue-l (#d7e3ff) | blue-d (#002f65) | `--cem-action-primary-default-background` |
343
+ | `contextual` | `comfort` | cyan-xl (#f1fefe) | cyan-xd (#001010) | `--cem-action-contextual-default-background` |
344
+ | `alternate` | `enthusiasm` | orange-l (#ffe082) | orange-d (#723600) | `--cem-action-alternate-default-background` |
345
+ | `destructive` | `danger` | red-l (#ba1a1a) | red-d (#690005) | `--cem-action-destructive-default-background` |
346
+
347
+ ### 7.2 Canonical state model
348
+
349
+ CEM action states (union of form/action semantics and interaction semantics):
350
+
351
+ - `disabled`
352
+ - `readonly`
353
+ - `editable`
354
+ - `required`
355
+ - `default`
356
+ - `indeterminate`
357
+ - `target`
358
+ - `focus`
359
+ - `hover`
360
+ - `selected`
361
+ - `active`
362
+ - `pending`
363
+
364
+ State progression is defined as a **formulaic** movement from “least emphasized” to “most emphasized”, using
365
+ `color-mix()` against the emotion’s extreme variant (`--cem-palette-{emotion}-x`).
366
+
367
+ #### 7.2.1 Background-driven states
368
+
369
+ ```
370
+ disabled → readonly → editable → default → indeterminate → hover → active → pending
371
+ (30%) (80%) (90%) (base) (90%) (60%) (25%) (5%)
372
+ ```
373
+
374
+ - Percentages are **weights of the base emotion** mixed toward an “extreme” anchor.
375
+ - For **disabled**, the anchor is the conservative extreme (`--cem-palette-conservative-x`) to desaturate and quiet the
376
+ UI.
377
+
378
+ #### 7.2.2 State formulas (normative)
379
+
380
+ | State | Background formula (palette-level) | Text token |
381
+ |---------------|-------------------------------------------------------------------------------------------|-------------------------------------|
382
+ | disabled | `color-mix(in srgb, var(--cem-palette-{emotion}) 30%, var(--cem-palette-conservative-x))` | `--cem-palette-conservative-text-x` |
383
+ | readonly | `color-mix(in srgb, var(--cem-palette-{emotion}) 80%, var(--cem-palette-{emotion}-x))` | `--cem-palette-{emotion}-text` |
384
+ | editable | `color-mix(in srgb, var(--cem-palette-{emotion}) 90%, var(--cem-palette-{emotion}-x))` | `--cem-palette-{emotion}-text` |
385
+ | default | `var(--cem-palette-{emotion})` | `--cem-palette-{emotion}-text` |
386
+ | indeterminate | `color-mix(in srgb, var(--cem-palette-{emotion}) 90%, var(--cem-palette-{emotion}-x))` | `--cem-palette-{emotion}-text` |
387
+ | hover | `color-mix(in srgb, var(--cem-palette-{emotion}) 60%, var(--cem-palette-{emotion}-x))` | `--cem-palette-{emotion}-text` |
388
+ | active | `color-mix(in srgb, var(--cem-palette-{emotion}) 25%, var(--cem-palette-{emotion}-x))` | `--cem-palette-{emotion}-text-x` |
389
+ | pending | `color-mix(in srgb, var(--cem-palette-{emotion}) 5%, var(--cem-palette-{emotion}-x))` | `--cem-palette-{emotion}-text-x` |
390
+
391
+ **Applying this to action intents:** substitute `{emotion}` with the emotional palette mapped by the intent (see §7.1).
392
+ The resulting values populate `--cem-action-{intent}-{state}-background` and `--cem-action-{intent}-{state}-text`.
393
+
394
+ #### 7.2.3 Outline-driven states
395
+
396
+ `focus`, `selected`, and `target` are primarily expressed through the **zebra outline channel** (§8). Background tokens
397
+ MAY remain at `default` for these states; do not rely on fill alone.
398
+
399
+ ### 7.3 Attribute channels
400
+
401
+ Action state can affect these channels (the set varies by state):
402
+
403
+ - `background` (fill)
404
+ - `text` (ink on fill)
405
+ - `outline` (via zebra / stroke tokens)
406
+ - `marker` (required star, etc.)
407
+ - `font` (weight/face, see Typography spec)
408
+
409
+ ### 7.4 Minimal required action endpoints
410
+
411
+ To render functional UIs, the following endpoints are REQUIRED per action intent:
412
+
413
+ - `--cem-action-{intent}-default-background`
414
+ - `--cem-action-{intent}-default-text`
415
+ - `--cem-action-{intent}-hover-background`
416
+ - `--cem-action-{intent}-hover-text`
417
+ - `--cem-action-{intent}-active-background`
418
+ - `--cem-action-{intent}-active-text`
419
+ - `--cem-action-{intent}-disabled-background`
420
+ - `--cem-action-{intent}-disabled-text`
421
+ - `--cem-action-{intent}-selected-background`
422
+ - `--cem-action-{intent}-selected-text`
423
+
424
+ Other states (`focus`, `target`, `pending`, `required`, `indeterminate`, `readonly`, `editable`) are RECOMMENDED, and
425
+ may be implemented through zebra/markers rather than fill.
426
+
427
+ ### 7.5 Contrast themes: collapse fills, keep semantics
428
+
429
+ In `contrast-light` and `contrast-dark`, background tokens SHOULD converge on the base surface (
430
+ `--cem-palette-comfort`), with state primarily expressed via:
431
+
432
+ - zebra outline strip colors (`--cem-zebra-color-*`)
433
+ - markers (required/indeterminate)
434
+ - typography deltas (weight/decoration), if needed
435
+
436
+ ---
437
+
438
+ ### 7.6 Implementation guidance (non-normative)
439
+
440
+ **Deriving state backgrounds from palette (example):**
441
+
442
+ ```css
443
+ /* Example: primary intent is mapped to trust */
444
+ :root {
445
+ --cem-action-primary-default-background: var(--cem-palette-trust);
446
+ --cem-action-primary-default-text: var(--cem-palette-trust-text);
447
+
448
+ --cem-action-primary-hover-background: color-mix(in srgb, var(--cem-palette-trust) 60%, var(--cem-palette-trust-x));
449
+ --cem-action-primary-hover-text: var(--cem-palette-trust-text);
450
+
451
+ --cem-action-primary-active-background: color-mix(in srgb, var(--cem-palette-trust) 25%, var(--cem-palette-trust-x));
452
+ --cem-action-primary-active-text: var(--cem-palette-trust-text-x);
453
+ }
454
+
455
+ /* Focus should be expressed via zebra outlines (D5), not by fill alone */
456
+ .button:focus-visible { outline-color: var(--cem-zebra-color-1); }
457
+ ```
458
+
459
+ **Framework adapters (illustrative, not normative):**
460
+
461
+ | CEM semantic | MUI (conceptual) | Angular Material (conceptual) |
462
+ |------------------------------|-----------------------------------|-----------------------------------------|
463
+ | `--cem-action-primary-*` | `palette.primary.*` | `primary` |
464
+ | `--cem-action-destructive-*` | `palette.error.*` | `warn` |
465
+ | `--cem-action-alternate-*` | `palette.secondary.*` (or custom) | `accent` (or custom) |
466
+ | zebra focus/selected/target | focus ring / outline styles | focus indicator / ripple-outline styles |
467
+
468
+ ## 8. Zebra outline colors
469
+
470
+ ### 8.1 Outline-driven state mapping (zebra)
471
+
472
+ | State | Zebra stripe | Recommended meaning |
473
+ |----------|-----------------------|--------------------------------------|
474
+ | focus | `--cem-zebra-color-1` | keyboard focus visibility |
475
+ | selected | `--cem-zebra-color-2` | selection / checked / chosen |
476
+ | target | `--cem-zebra-color-3` | navigation target / guided attention |
477
+
478
+ See D5 Stroke for zebra geometry (stripe order, offsets, and ring widths).
479
+
480
+ Zebra is a **striped outline** (implemented in D5 Stroke) with four semantic strips.
481
+
482
+ Color endpoints:
483
+
484
+ - `--cem-zebra-color-0`: innermost stripe (base surface)
485
+ - `--cem-zebra-color-1`: focus stripe
486
+ - `--cem-zebra-color-2`: selection stripe
487
+ - `--cem-zebra-color-3`: target stripe
488
+ - `--cem-zebra-strip-size`: stripe thickness basis (pairs with D5 stroke widths)
489
+
490
+ Rules:
491
+
492
+ - Zebra colors MUST remain distinguishable from the adjacent surface in all modes.
493
+ - Zebra MUST remain meaningful in forced-colors; in `native` this is achieved by mapping to system colors.
494
+
495
+ ---
496
+
497
+ ## 9. System colors and forced-colors
498
+
499
+ ### 9.1 Native/system palette mapping
500
+
501
+ In `native` mode, palette endpoints SHOULD map to system colors:
502
+
503
+ - `--cem-palette-comfort`: `Canvas`
504
+ - `--cem-palette-comfort-text`: `CanvasText`
505
+ - `--cem-palette-trust`: `Highlight`
506
+ - `--cem-palette-trust-text`: `HighlightText`
507
+ - `--cem-zebra-color-2`: `SelectedItem` (or fallback to trust)
508
+
509
+ ### 9.2 Forced colors
510
+
511
+ When `@media (forced-colors: active)` is true:
512
+
513
+ - Prefer system colors (`Canvas`, `CanvasText`, `Highlight`, `SelectedItem`) over authored colors.
514
+ - Avoid relying on `box-shadow`/glow as a sole state indicator (UAs commonly drop or adjust it).
515
+ - Use outline/zebra and semantic system colors to preserve state visibility.
516
+
517
+ ---
518
+
519
+ ## 10. Component mapping checklist
520
+
521
+ Use this as a quick “did we wire tokens correctly?” checklist.
522
+
523
+ ### 10.1 Actions
524
+
525
+ - [ ] Buttons (primary): `--cem-action-primary-*`
526
+ - [ ] Buttons (explicit): `--cem-action-explicit-*`
527
+ - [ ] Toolbar/menu actions (contextual): `--cem-action-contextual-*`
528
+ - [ ] Secondary actions (alternate): `--cem-action-alternate-*`
529
+ - [ ] Destructive: `--cem-action-destructive-*`
530
+
531
+ ### 10.2 Inputs and selection controls
532
+
533
+ - [ ] Text fields use comfort surface; state uses zebra/underline + `readonly/editable/required`
534
+ - [ ] Checkboxes/radios reflect `selected` and `indeterminate` distinctly
535
+ - [ ] Targeted elements (`:target`) use target zebra strip
536
+
537
+ ### 10.3 Informational semantics
538
+
539
+ - [ ] Errors use `--cem-palette-danger` + `--cem-palette-danger-text`
540
+ - [ ] Highlights use `--cem-palette-trust`
541
+ - [ ] Low-emphasis/disabled uses `--cem-palette-conservative`
542
+
543
+ ---
544
+
545
+ ## 11. Accessibility and QA
546
+
547
+ ### 11.1 Contrast requirements (normative)
548
+
549
+ | Element | Minimum ratio |
550
+ |-------------------------------------|------------------------------|
551
+ | Body text on background | ≥4.5:1 |
552
+ | Large text (≥18pt or ≥14pt bold) | ≥3:1 |
553
+ | UI components and graphical objects | ≥3:1 |
554
+ | Focus indicators | ≥3:1 against adjacent colors |
555
+
556
+ ### 11.2 QA checklist (done-ness)
557
+
558
+ - Verify **theme switching** (light/dark/contrast/native) does not change semantics (only mappings).
559
+ - Verify all **action intents** have complete state endpoints (default/hover/active/disabled/selected).
560
+ - Verify **zebra focus/selection/target** remains visible across surfaces and in forced-colors.
561
+ - Verify **pending** is perceivable without relying on hue alone (may require motion per D7).
562
+ - Verify **color-blind resilience**: state remains distinguishable via outline/pattern/label/shape.
563
+
564
+ Minimum QA expectations:
565
+
566
+ - Contrast: text-on-background combinations MUST meet your target WCAG level for the corresponding text size.
567
+ - Focus visibility: keyboard focus MUST be detectable without color-fill changes (zebra/outline required).
568
+ - Forced-colors: verify key flows with forced-colors enabled (Windows High Contrast / similar).
569
+ - Color-blindness: verify that state is still perceivable via non-hue channels (outline thickness, pattern, marker).
570
+
571
+ ---
572
+
573
+
574
+ ### 11.3 Color-blind resilience and redundancy (normative)
575
+
576
+ - Meaning MUST NOT rely on hue alone. Any state with user impact (error, destructive, focus, selection, pending) MUST also be conveyed via at least one of:
577
+ - text (label or status copy)
578
+ - iconography
579
+ - outline/pattern (e.g., zebra ring), or
580
+ - shape/position change (where appropriate).
581
+ - Implementations SHOULD test common color-vision deficiencies (e.g., deuteranopia and protanopia) and verify that state progression remains distinguishable.
582
+
583
+ ### 11.4 Motion sensitivity (normative)
584
+
585
+ - Theme transitions and state transitions SHOULD respect `prefers-reduced-motion` (see D7).
586
+ - Instant color changes are acceptable; animated gradients and long “breathing” color loops SHOULD NOT be required to understand state.
587
+ ## 12. Implementation guidance
588
+
589
+ ### 12.1 Recommended layering: branded → emotional → action
590
+
591
+ Implementations SHOULD preserve the three-layer model:
592
+
593
+ 1) **Branded hues** (`--cem-color-*`) — implementation substrate (brand-controlled)
594
+ 2) **Emotional palette** (`--cem-palette-*`) — semantic contract (theme-adaptive via `light-dark()`)
595
+ 3) **Action intents** (`--cem-action-*`) — product-facing API (derived state progression via `color-mix()`)
596
+
597
+ ### 12.2 Derivation pattern (illustrative CSS)
598
+
599
+ ```css
600
+ :root {
601
+ /* Emotional palette (example) */
602
+ --cem-palette-trust: light-dark(var(--cem-color-blue-l), var(--cem-color-blue-d));
603
+ --cem-palette-trust-x: light-dark(var(--cem-color-blue-d), var(--cem-color-blue-l));
604
+ --cem-palette-trust-text: light-dark(var(--cem-color-blue-d), white);
605
+ --cem-palette-trust-text-x: light-dark(var(--cem-color-blue-xl), var(--cem-color-blue-xl));
606
+
607
+ /* Primary intent mapped to trust */
608
+ --cem-action-primary-default-background: var(--cem-palette-trust);
609
+ --cem-action-primary-default-text: var(--cem-palette-trust-text);
610
+
611
+ --cem-action-primary-hover-background: color-mix(in srgb, var(--cem-palette-trust) 60%, var(--cem-palette-trust-x));
612
+ --cem-action-primary-hover-text: var(--cem-palette-trust-text);
613
+
614
+ --cem-action-primary-active-background: color-mix(in srgb, var(--cem-palette-trust) 25%, var(--cem-palette-trust-x));
615
+ --cem-action-primary-active-text: var(--cem-palette-trust-text-x);
616
+ }
617
+
618
+ @media (forced-colors: active) {
619
+ :root {
620
+ --cem-palette-comfort: Canvas;
621
+ --cem-palette-comfort-text: CanvasText;
622
+ --cem-palette-trust: Highlight;
623
+ --cem-palette-trust-text: HighlightText;
624
+ }
625
+ }
626
+ ```
627
+
628
+ ### 12.3 Framework mapping (conceptual)
629
+
630
+ | CEM semantic | Material Design 3 (concept) | Angular Material (concept) | MUI (concept) |
631
+ |------------------------------|-------------------------------|-----------------------------|------------------------------------|
632
+ | `--cem-palette-comfort` | `md-sys-color-surface` | `--mat-sys-surface` | `theme.palette.background.default` |
633
+ | `--cem-palette-comfort-text` | `md-sys-color-on-surface` | `--mat-sys-on-surface` | `theme.palette.text.primary` |
634
+ | `--cem-palette-trust` | `md-sys-color-primary` | `--mat-sys-primary` | `theme.palette.primary.main` |
635
+ | `--cem-palette-danger` | `md-sys-color-error` | `--mat-sys-error` | `theme.palette.error.main` |
636
+ | zebra focus/selected/target | focus indicator guidance | focus indicator styles | focus ring / outline styles |
637
+
638
+ ### 12.4 Test focus: “semantic survives adapters”
639
+
640
+ In addition to contrast, validate that **semantic meaning remains stable** across:
641
+
642
+ - light/dark
643
+ - contrast-light/contrast-dark
644
+ - `forced-colors: active`
645
+ - density modes (D2), where reduced whitespace increases the importance of outlines/markers.
646
+
647
+ ## 13. Governance and versioning
648
+
649
+ Treat as **breaking** (major):
650
+
651
+ - Renaming/removing any `--cem-palette-*`, `--cem-action-*`, or `--cem-zebra-*` canonical endpoint.
652
+ - Changing the semantic meaning of any endpoint (e.g., swapping “trust” and “danger”).
653
+ - Changing the intent↔emotion mapping used for action defaults (e.g., `primary` no longer mapping to `trust`).
654
+ - Changing the meaning or ordering of canonical states (e.g., redefining `active` to be less emphasized than `hover`).
655
+ - Reducing contrast below the normative thresholds stated in §11.1.
656
+
657
+ Treat as **non-breaking** (minor/patch):
658
+
659
+ - Adjusting reference hex values of `--cem-color-*` while preserving semantics.
660
+ - Adding new optional endpoints with clear scope.
661
+ - Clarifying mapping guidance.
662
+
663
+ ---
664
+
665
+ ## 14. Canonical token summary
666
+
667
+ ### 14.1 Required (product contract)
668
+
669
+ **Emotional palette (minimum set):**
670
+
671
+ - `--cem-palette-comfort`, `--cem-palette-comfort-text`
672
+ - `--cem-palette-trust`, `--cem-palette-trust-text`
673
+ - `--cem-palette-danger`, `--cem-palette-danger-text`
674
+ - `--cem-palette-conservative`, `--cem-palette-conservative-text`
675
+
676
+ **Zebra (outline/pattern channel):**
677
+
678
+ - `--cem-zebra-color-0`, `--cem-zebra-color-1`, `--cem-zebra-color-2`, `--cem-zebra-color-3`
679
+ - `--cem-zebra-strip-size`
680
+
681
+ **Actions (per shipped intent):**
682
+
683
+ For each shipped intent (`primary`, `explicit`, `contextual`, `alternate`, `destructive`), the implementation MUST provide at least:
684
+
685
+ - `--cem-action-{intent}-default-background`, `--cem-action-{intent}-default-text`
686
+ - `--cem-action-{intent}-hover-background`, `--cem-action-{intent}-hover-text`
687
+ - `--cem-action-{intent}-active-background`, `--cem-action-{intent}-active-text`
688
+ - `--cem-action-{intent}-disabled-background`, `--cem-action-{intent}-disabled-text`
689
+ - `--cem-action-{intent}-selected-background`, `--cem-action-{intent}-selected-text`
690
+
691
+ ### 14.2 Recommended (implementation substrate)
692
+
693
+ - Branded hues: `--cem-color-*` (brand-controlled; used to derive palette tokens)
694
+ - Palette extremes: `--cem-palette-*-x`, `--cem-palette-*-text-x` (required if using formulaic `color-mix()` state progression)
695
+ - Additional emotions: `--cem-palette-calm`, `--cem-palette-enthusiasm`, `--cem-palette-creativity` (recommended where the product uses the corresponding semantics)
696
+ - Additional action states (recommended where applicable): `readonly`, `editable`, `required`, `indeterminate`, `focus`, `target`, `pending`
697
+
698
+ ## 15. References
699
+
700
+ ### Internal
701
+
702
+ - Action states and visual priority order (EPA-WG `custom-element-dist` discussion #14): https://github.com/EPA-WG/custom-element-dist/discussions/14
703
+
704
+ ### External
705
+
706
+ - WCAG 2.2 — Focus Appearance (Minimum): https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance.html
707
+ - WCAG 2.1 — Contrast (Minimum): https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html
708
+ - MDN: `color-mix()`: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix
709
+ - MDN: `light-dark()`: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark
710
+ - MDN: `forced-colors`: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/forced-colors
711
+ - Material Design 3 — Color system overview: https://m3.material.io/styles/color/overview
712
+
713
+ ---
714
+
715
+ *This spec is the canonical D0 contract for CEM color semantics.*