@epa-wg/custom-element-dist 0.0.32 → 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 (300) 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 -21
  8. package/.storybook/preview.ts +23 -25
  9. package/README.md +6 -4
  10. package/coverage/block-navigation.js +1 -1
  11. package/coverage/coverage-final.json +8 -18
  12. package/coverage/index.html +45 -30
  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 +687 -480
  17. package/coverage/src/custom-element/http-request.js/coverage.svg +1 -1
  18. package/coverage/src/custom-element/http-request.js.html +39 -18
  19. package/coverage/src/custom-element/index.html +35 -35
  20. package/coverage/src/custom-element/local-storage.js.html +1 -1
  21. package/coverage/src/custom-element/location-element.js.html +31 -31
  22. package/coverage/src/custom-element/module-url.js/coverage.svg +1 -1
  23. package/coverage/src/custom-element/module-url.js.html +20 -20
  24. package/coverage/src/index.html +1 -1
  25. package/coverage/src/{stories/local-storage.test.stories.ts → material/theme/colors.js}/coverage.svg +1 -1
  26. package/coverage/src/material/theme/colors.js.html +217 -0
  27. package/coverage/src/{stories/location-element.test.stories.ts → material/theme}/coverage.svg +1 -1
  28. package/coverage/src/material/theme/index.html +116 -0
  29. package/coverage/src/mocks/handlers.ts.html +1 -1
  30. package/coverage/src/mocks/index.html +1 -1
  31. package/coverage/src/stories/coverage.svg +1 -1
  32. package/coverage/src/stories/{external-template.test.stories.ts → frame.canvas.ts}/coverage.svg +1 -1
  33. package/coverage/src/stories/frame.canvas.ts.html +175 -0
  34. package/coverage/src/stories/http-request.stories.ts.html +1 -1
  35. package/coverage/src/stories/index.html +14 -179
  36. package/coverage/src/stories/testStoryBook.ts.html +12 -12
  37. package/coverage/src/sum.ts.html +1 -1
  38. package/dist/custom-element-BoYMoUtP.js +619 -0
  39. package/dist/custom-element-BqtjrCRF.cjs +97 -0
  40. package/dist/custom-element-bundle.cjs +1 -1
  41. package/dist/custom-element-bundle.js +3 -3
  42. package/dist/demo/a.html +10 -3
  43. package/dist/demo/a.svg +26 -26
  44. package/dist/demo/attributes.html +153 -0
  45. package/dist/demo/external-templates-sb-6.html +42 -0
  46. package/dist/demo/external-templates-sb-7.html +42 -0
  47. package/dist/demo/html-template.html +5 -4
  48. package/dist/demo/module-url-sb-2.html +46 -0
  49. package/dist/demo/module-url-sb-4.html +48 -0
  50. package/dist/demo/module-url-sb-5.html +53 -0
  51. package/dist/demo/s.xml +3859 -7
  52. package/dist/demo/s.xslt +13 -48
  53. package/dist/demo/s1.xml +3706 -0
  54. package/dist/demo/ss.html +13 -4
  55. package/dist/http-request-DSaowcG1.cjs +1 -0
  56. package/dist/{http-request-BOvP4KTl.js → http-request-DTCzZ1gc.js} +15 -9
  57. package/dist/mockServiceWorker.js +31 -8
  58. package/package.json +25 -26
  59. package/public/demo/a.html +10 -3
  60. package/public/demo/a.svg +26 -26
  61. package/public/demo/attributes.html +153 -0
  62. package/public/demo/external-templates-sb-6.html +42 -0
  63. package/public/demo/external-templates-sb-7.html +42 -0
  64. package/public/demo/html-template.html +5 -4
  65. package/public/demo/module-url-sb-2.html +46 -0
  66. package/public/demo/module-url-sb-4.html +48 -0
  67. package/public/demo/module-url-sb-5.html +53 -0
  68. package/public/demo/s.xml +3859 -7
  69. package/public/demo/s.xslt +13 -48
  70. package/public/demo/s1.xml +3706 -0
  71. package/public/demo/ss.html +13 -4
  72. package/public/mockServiceWorker.js +31 -8
  73. package/src/custom-element/custom-element.d.ts +4 -0
  74. package/src/custom-element/custom-element.js +119 -50
  75. package/src/custom-element/demo/a.html +10 -3
  76. package/src/custom-element/demo/a.svg +26 -26
  77. package/src/custom-element/demo/attributes.html +153 -0
  78. package/src/custom-element/demo/html-template.html +5 -4
  79. package/src/custom-element/demo/s.xml +3859 -7
  80. package/src/custom-element/demo/s.xslt +13 -48
  81. package/src/custom-element/demo/s1.xml +3706 -0
  82. package/src/custom-element/demo/ss.html +13 -4
  83. package/src/custom-element/http-request.js +7 -0
  84. package/src/custom-element/ide/web-types-dce.json +1 -1
  85. package/src/custom-element/ide/web-types-xsl.json +1 -1
  86. package/src/custom-element/index.html +1 -1
  87. package/src/material/angular.css +987 -987
  88. package/src/material/components/action.html +262 -0
  89. package/src/material/components/autocomplete.html +167 -239
  90. package/src/material/components/badge.html +239 -0
  91. package/src/material/components/dropdown.html +7 -13
  92. package/src/material/components/icon-link.html +160 -160
  93. package/src/material/components/icon.html +252 -0
  94. package/src/material/components/input.html +569 -362
  95. package/src/material/components/menu.html +235 -234
  96. package/src/material/components.html +157 -121
  97. package/src/material/demo.css +36 -36
  98. package/src/material/index.html +109 -110
  99. package/src/material/material.css +356 -356
  100. package/src/material/theme/Base-Principles.md +339 -0
  101. package/src/material/theme/README.md +298 -18
  102. package/src/material/theme/UI Domain Model in web applications.svg +1 -0
  103. package/src/material/theme/User Semantic Theme tokens.svg +1 -0
  104. package/src/material/theme/action-pending-poc.html +62 -0
  105. package/src/material/theme/actions-color.html +141 -0
  106. package/src/material/theme/colors-light.html +631 -0
  107. package/src/material/theme/colors-native.html +51 -0
  108. package/src/material/theme/colors-poc.html +66 -0
  109. package/src/material/theme/colors.html +297 -0
  110. package/src/material/theme/colors.js +44 -0
  111. package/src/material/theme/consumer-theme.css +745 -0
  112. package/src/material/theme/semantic.css +132 -113
  113. package/src/material/theme/style-bug.html +123 -0
  114. package/src/material/theme/theme-data.css +43 -0
  115. package/src/material/theme/theme-data.xhtml +2926 -0
  116. package/src/material/theme/todo.md +274 -0
  117. package/src/material/theme/tokens/action-colors.png +0 -0
  118. package/src/material/theme/tokens/cem-article-illustration-4x1-letterbox-2000x500.png +0 -0
  119. package/src/material/theme/tokens/cem-breakpoints.md +519 -0
  120. package/src/material/theme/tokens/cem-colors.md +715 -0
  121. package/src/material/theme/tokens/cem-consumerflow-typography-matrix.svg +198 -0
  122. package/src/material/theme/tokens/cem-coupling.md +372 -0
  123. package/src/material/theme/tokens/cem-data-vs-reading-numerals.svg +164 -0
  124. package/src/material/theme/tokens/cem-dimension.md +625 -0
  125. package/src/material/theme/tokens/cem-layering.md +562 -0
  126. package/src/material/theme/tokens/cem-m3-parity.md +343 -0
  127. package/src/material/theme/tokens/cem-responsive.md +238 -0
  128. package/src/material/theme/tokens/cem-shape.md +691 -0
  129. package/src/material/theme/tokens/cem-stroke-density-illustration-4to1-v3.svg +102 -0
  130. package/src/material/theme/tokens/cem-stroke.md +480 -0
  131. package/src/material/theme/tokens/cem-timing.md +198 -0
  132. package/src/material/theme/tokens/cem-typography-model-stack.svg +64 -0
  133. package/src/material/theme/tokens/cem-voice-fonts-typography.md +718 -0
  134. package/src/material/theme/tokens/cem-voice-ladder.svg +91 -0
  135. package/src/material/theme/tokens/chips.png +0 -0
  136. package/src/material/theme/tokens/columns-page.png +0 -0
  137. package/src/material/theme/tokens/initials.png +0 -0
  138. package/src/material/theme/tokens/nav-buttons.png +0 -0
  139. package/src/material/theme/tokens/script.png +0 -0
  140. package/src/material/theme/tokens/sufler.png +0 -0
  141. package/src/material/theme/tokens/typography-icons.png +0 -0
  142. package/src/mocks/versions.mock.ts +1 -1
  143. package/src/stories/__screenshots__/attributes.test.stories.ts +1 -0
  144. package/src/stories/__screenshots__/dom-merge.test.stories.ts/dom-merge-dom-merge-OrderPreservingOn2ndTransform-1.png +0 -0
  145. package/src/stories/__screenshots__/external-template.test.stories.ts +1 -0
  146. package/src/stories/__screenshots__/module-url.test.stories.ts +1 -0
  147. package/src/stories/__screenshots__/stories.test.ts/attributes-Attributes-definition-1.png +0 -0
  148. package/src/stories/__screenshots__/stories.test.ts/attributes-Attributes-runtime-change-1.png +0 -0
  149. package/src/stories/__screenshots__/stories.test.ts/attributes-Instance-Attributes-1.png +0 -0
  150. package/src/stories/__screenshots__/stories.test.ts/attributes-Instance-Attributes-2.png +0 -0
  151. package/src/stories/__screenshots__/stories.test.ts/attributes-cloneAs-el-newTag--1.png +0 -0
  152. package/src/stories/__screenshots__/stories.test.ts/attributes-mergeAttr--from--to---1.png +0 -0
  153. package/src/stories/__screenshots__/stories.test.ts/attributes-mergeAttr--from--to---2.png +0 -0
  154. package/src/stories/__screenshots__/stories.test.ts/attributes-mergeAttr--from--to---3.png +0 -0
  155. package/src/stories/__screenshots__/stories.test.ts/attributes-mix-to-from--1.png +0 -0
  156. package/src/stories/__screenshots__/stories.test.ts/http-request-Attributes-definition-1.png +0 -0
  157. package/src/stories/__screenshots__/stories.test.ts/http-request-Attributes-runtime-change-1.png +0 -0
  158. package/src/stories/__screenshots__/stories.test.ts/http-request-Instance-Attributes-1.png +0 -0
  159. package/src/stories/__screenshots__/stories.test.ts/http-request-Instance-Attributes-2.png +0 -0
  160. package/src/stories/__screenshots__/stories.test.ts/http-request-cloneAs-el-newTag--1.png +0 -0
  161. package/src/stories/__screenshots__/stories.test.ts/http-request-http-request-headers-and-response-status-and-headers-1.png +0 -0
  162. package/src/stories/__screenshots__/stories.test.ts/http-request-http-request-with-delayed--5-seconds-response-1.png +0 -0
  163. package/src/stories/__screenshots__/stories.test.ts/http-request-http-request-with-error-1.png +0 -0
  164. package/src/stories/__screenshots__/stories.test.ts/http-request-mergeAttr--from--to---1.png +0 -0
  165. package/src/stories/__screenshots__/stories.test.ts/http-request-mergeAttr--from--to---2.png +0 -0
  166. package/src/stories/__screenshots__/stories.test.ts/http-request-mergeAttr--from--to---3.png +0 -0
  167. package/src/stories/__screenshots__/stories.test.ts/http-request-mix-to-from--1.png +0 -0
  168. package/src/stories/__screenshots__/stories.test.ts/http-request-url-and-slice-1.png +0 -0
  169. package/src/stories/__screenshots__/stories.test.ts/http-request-url-change-1.png +0 -0
  170. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-MultipleIfOrderingWorkaround-1.png +0 -0
  171. package/src/stories/attributes.test.stories.ts +83 -17
  172. package/src/stories/dom-merge.test.stories.ts +25 -1
  173. package/src/stories/external-template.test.stories.ts +16 -14
  174. package/src/stories/frame.canvas.ts +31 -0
  175. package/src/stories/module-url.test.stories.ts +29 -61
  176. package/src/stories/xslt-conditionals.test.stories.ts +492 -0
  177. package/src/stories/xslt-if.test.stories.ts +89 -0
  178. package/storybook-static/assets/Color-F6OSRLHC-CzTOSlqB.js +1 -0
  179. package/storybook-static/assets/Configure-7GqRsAoJ.js +165 -0
  180. package/storybook-static/assets/DocsRenderer-CFRXHY34-Duc5rSIm.js +2 -0
  181. package/storybook-static/assets/{attributes.test.stories-D1X6EBrd.js → attributes.test.stories-DYuxF8h1.js} +109 -38
  182. package/storybook-static/assets/{css.test.stories-Cp_g2hE1.js → css.test.stories-LOmvINyb.js} +1 -1
  183. package/storybook-static/assets/custom-element-Bwx7otrT.js +97 -0
  184. package/storybook-static/assets/{dom-merge.test.stories-hbpdCka0.js → dom-merge.test.stories-CEKhWjaS.js} +47 -6
  185. package/storybook-static/assets/entry-preview-BNCt9WBs.js +26 -0
  186. package/storybook-static/assets/entry-preview-docs-CbF8-81D.js +2 -0
  187. package/storybook-static/assets/{external-template.test.stories-BK89h6sk.js → external-template.test.stories-jHu0wsJ-.js} +38 -40
  188. package/storybook-static/assets/{form.test.stories-BfoLe_rw.js → form.test.stories-CUyUnmwP.js} +1 -1
  189. package/storybook-static/assets/frame.canvas-E5n9h6j1.js +1 -0
  190. package/storybook-static/assets/{handlers-yVPwH_Nz.js → handlers-F7GUfMqr.js} +17 -14
  191. package/storybook-static/assets/http-request-BWeEEBkP.js +1 -0
  192. package/storybook-static/assets/{http-request.stories-CBFJS2Ws.js → http-request.stories-wyX5-QOv.js} +1 -1
  193. package/storybook-static/assets/iframe-BS_DPWl0.js +199 -0
  194. package/storybook-static/assets/index-CGuyH0k-.js +240 -0
  195. package/storybook-static/assets/index-DB7LLObI.js +1 -0
  196. package/storybook-static/assets/index-DO1nmyvI.js +11 -0
  197. package/storybook-static/assets/index-V1EGs-wm.js +621 -0
  198. package/storybook-static/assets/{local-storage.test.stories-C0Yzy6Am.js → local-storage.test.stories-BxOhsf1k.js} +1 -1
  199. package/storybook-static/assets/{location-element.test.stories-DNFrEu5A.js → location-element.test.stories-DqhvvUoa.js} +1 -1
  200. package/storybook-static/assets/module-url.test.stories-C1gG9G7Y.js +142 -0
  201. package/storybook-static/assets/preview-1xJJ3sKE.js +1 -0
  202. package/storybook-static/assets/preview-Bn8igYMp.js +1 -0
  203. package/storybook-static/assets/preview-CTOeX_lO.js +1 -0
  204. package/storybook-static/assets/preview-Cwy1XFu2.js +2 -0
  205. package/storybook-static/assets/preview-D6sehqkw.js +50 -0
  206. package/storybook-static/assets/preview-DfTudP20.js +1 -0
  207. package/storybook-static/assets/{set-url.test.stories-BBfLxv2u.js → set-url.test.stories-BKQNdknJ.js} +1 -1
  208. package/storybook-static/assets/{slice-events.test.stories-HcXF8XQI.js → slice-events.test.stories-ChqULCeA.js} +1 -1
  209. package/storybook-static/assets/{slots.test.stories-i6mnIFM2.js → slots.test.stories-BlyLoCRe.js} +1 -1
  210. package/storybook-static/assets/{version-select.test.stories-BsUFH6Va.js → version-select.test.stories-CPGSh1tR.js} +1 -1
  211. package/storybook-static/assets/xslt-conditionals.test.stories-YC6QPqWZ.js +633 -0
  212. package/storybook-static/assets/xslt-if.test.stories-BRSWy2-x.js +71 -0
  213. package/storybook-static/demo/a.html +10 -3
  214. package/storybook-static/demo/a.svg +26 -26
  215. package/storybook-static/demo/attributes.html +153 -0
  216. package/storybook-static/demo/external-templates-sb-6.html +42 -0
  217. package/storybook-static/demo/external-templates-sb-7.html +42 -0
  218. package/storybook-static/demo/html-template.html +5 -4
  219. package/storybook-static/demo/module-url-sb-2.html +46 -0
  220. package/storybook-static/demo/module-url-sb-4.html +48 -0
  221. package/storybook-static/demo/module-url-sb-5.html +53 -0
  222. package/storybook-static/demo/s.xml +3859 -7
  223. package/storybook-static/demo/s.xslt +13 -48
  224. package/storybook-static/demo/s1.xml +3706 -0
  225. package/storybook-static/demo/ss.html +13 -4
  226. package/storybook-static/iframe.html +2 -2
  227. package/storybook-static/index.html +6 -10
  228. package/storybook-static/index.json +1 -1
  229. package/storybook-static/mockServiceWorker.js +31 -8
  230. package/storybook-static/project.json +1 -1
  231. package/storybook-static/sb-addons/essentials-actions-2/manager-bundle.js +3 -0
  232. package/storybook-static/sb-addons/essentials-backgrounds-4/manager-bundle.js +8 -8
  233. package/storybook-static/sb-addons/essentials-controls-1/manager-bundle.js +394 -0
  234. package/storybook-static/sb-addons/essentials-docs-3/manager-bundle.js +233 -0
  235. package/storybook-static/sb-addons/essentials-measure-7/manager-bundle.js +1 -1
  236. package/storybook-static/sb-addons/essentials-outline-8/manager-bundle.js +1 -1
  237. package/storybook-static/sb-addons/essentials-toolbars-6/manager-bundle.js +1 -1
  238. package/storybook-static/sb-addons/essentials-viewport-5/manager-bundle.js +1 -1
  239. package/storybook-static/sb-addons/interactions-9/manager-bundle.js +58 -58
  240. package/storybook-static/sb-manager/globals-module-info.js +9 -0
  241. package/storybook-static/sb-manager/globals-runtime.js +10719 -10473
  242. package/storybook-static/sb-manager/runtime.js +4944 -6321
  243. package/coverage/src/stories/attributes.test.stories.ts/coverage.svg +0 -10
  244. package/coverage/src/stories/attributes.test.stories.ts.html +0 -814
  245. package/coverage/src/stories/css.test.stories.ts/coverage.svg +0 -10
  246. package/coverage/src/stories/css.test.stories.ts.html +0 -460
  247. package/coverage/src/stories/dom-merge.test.stories.ts/coverage.svg +0 -10
  248. package/coverage/src/stories/dom-merge.test.stories.ts.html +0 -706
  249. package/coverage/src/stories/external-template.test.stories.ts.html +0 -865
  250. package/coverage/src/stories/form.test.stories.ts/coverage.svg +0 -10
  251. package/coverage/src/stories/form.test.stories.ts.html +0 -661
  252. package/coverage/src/stories/local-storage.test.stories.ts.html +0 -1315
  253. package/coverage/src/stories/location-element.test.stories.ts.html +0 -523
  254. package/coverage/src/stories/module-url.test.stories.ts/coverage.svg +0 -10
  255. package/coverage/src/stories/module-url.test.stories.ts.html +0 -640
  256. package/coverage/src/stories/set-url.test.stories.ts/coverage.svg +0 -10
  257. package/coverage/src/stories/set-url.test.stories.ts.html +0 -433
  258. package/coverage/src/stories/slice-events.test.stories.ts/coverage.svg +0 -10
  259. package/coverage/src/stories/slice-events.test.stories.ts.html +0 -952
  260. package/coverage/src/stories/slots.test.stories.ts/coverage.svg +0 -10
  261. package/coverage/src/stories/slots.test.stories.ts.html +0 -742
  262. package/coverage/src/stories/version-select.test.stories.ts/coverage.svg +0 -10
  263. package/coverage/src/stories/version-select.test.stories.ts.html +0 -397
  264. package/dist/custom-element-D2wf_rqP.js +0 -576
  265. package/dist/custom-element-Dtzhbjkc.cjs +0 -97
  266. package/dist/http-request-DPrY7mGh.cjs +0 -1
  267. package/storybook-static/assets/Color-F6OSRLHC-BU3iy8jH.js +0 -1
  268. package/storybook-static/assets/Configure-DN6ifayP.js +0 -165
  269. package/storybook-static/assets/DocsRenderer-CFRXHY34-BaVEufDj.js +0 -2
  270. package/storybook-static/assets/custom-element-uuAtIYWS.js +0 -97
  271. package/storybook-static/assets/entry-preview-DHVXbf3x.js +0 -26
  272. package/storybook-static/assets/entry-preview-docs-BbcIMweR.js +0 -2
  273. package/storybook-static/assets/http-request-DNq59pnj.js +0 -1
  274. package/storybook-static/assets/iframe-CJEL_4Nu.js +0 -2
  275. package/storybook-static/assets/index-BcZLpTeD.js +0 -8
  276. package/storybook-static/assets/index-CxRwF5Or.js +0 -234
  277. package/storybook-static/assets/index-D-8MO0q_.js +0 -1
  278. package/storybook-static/assets/index-D5fBh-7N.js +0 -1
  279. package/storybook-static/assets/index-DM-KBPdl.js +0 -1
  280. package/storybook-static/assets/index-RSFf30w1.js +0 -1
  281. package/storybook-static/assets/index-SnjB5uV8.js +0 -769
  282. package/storybook-static/assets/module-url.test.stories-CXibF5Ta.js +0 -208
  283. package/storybook-static/assets/preview-BhhEZcNS.js +0 -1
  284. package/storybook-static/assets/preview-Bnd0XhaF.js +0 -52
  285. package/storybook-static/assets/preview-CNKoaWES.js +0 -1
  286. package/storybook-static/assets/preview-DAeyCMnM.js +0 -1
  287. package/storybook-static/assets/preview-DHPc-V4N.js +0 -1
  288. package/storybook-static/assets/preview-DJMlNTk8.js +0 -2
  289. package/storybook-static/assets/preview-DYzi3Z2p.js +0 -1
  290. package/storybook-static/sb-addons/chromatic-com-storybook-10/manager-bundle.js +0 -333
  291. package/storybook-static/sb-addons/chromatic-com-storybook-10/manager-bundle.js.LEGAL.txt +0 -40
  292. package/storybook-static/sb-addons/essentials-actions-3/manager-bundle.js +0 -3
  293. package/storybook-static/sb-addons/essentials-controls-2/manager-bundle.js +0 -391
  294. package/storybook-static/sb-addons/links-1/manager-bundle.js +0 -3
  295. package/storybook-static/sb-preview/globals.js +0 -33
  296. package/storybook-static/sb-preview/runtime.js +0 -7174
  297. package/test-runner-jest.config.js +0 -15
  298. /package/storybook-static/sb-addons/{essentials-actions-3 → essentials-actions-2}/manager-bundle.js.LEGAL.txt +0 -0
  299. /package/storybook-static/sb-addons/{essentials-controls-2 → essentials-controls-1}/manager-bundle.js.LEGAL.txt +0 -0
  300. /package/storybook-static/sb-addons/{links-1 → essentials-docs-3}/manager-bundle.js.LEGAL.txt +0 -0
@@ -0,0 +1,102 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" width="3200" height="800" viewBox="0 0 3200 800">
3
+
4
+ <defs>
5
+ <filter id="shadow" x="-20%" y="-20%" width="140%" height="160%">
6
+ <feOffset dx="0" dy="10" result="off"/>
7
+ <feGaussianBlur in="off" stdDeviation="10" result="blur"/>
8
+ <feColorMatrix in="blur" type="matrix"
9
+ values="0 0 0 0 0
10
+ 0 0 0 0 0
11
+ 0 0 0 0 0
12
+ 0 0 0 0.22 0" result="shadow"/>
13
+ <feBlend in="shadow" in2="SourceGraphic" mode="normal"/>
14
+ </filter>
15
+ <style>
16
+ .title { font: 700 54px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: black; }
17
+ .banner { font: 400 30px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #13539b; }
18
+ .label { font: 700 30px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #141416; }
19
+ .sub { font: 400 24px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #4b4b52; }
20
+ .ui { font: 400 30px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #141416; }
21
+ .ui-bold { font: 700 30px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #141416; }
22
+ .small { font: 400 24px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #4b4b52; }
23
+ </style>
24
+ </defs>
25
+
26
+ <rect x="0" y="0" width="3200" height="800" fill="#ffffff"/>
27
+ <rect x="60" y="28" width="3080" height="78" rx="24" fill="#e8f1fc"/>
28
+ <text x="95" y="80" class="banner">Dense UI may need stronger strokes; Comfort UI can rely on whitespace for separation.</text>
29
+ <text x="1600.0" y="164" text-anchor="middle" class="title">Stroke thickness varies by density mode (semantics unchanged)</text>
30
+ <g filter="url(#shadow)"><rect x="90" y="216" width="1475" height="494" rx="32" fill="#ffffff"/></g>
31
+ <g filter="url(#shadow)"><rect x="1635" y="216" width="1475" height="494" rx="32" fill="#ffffff"/></g>
32
+ <text x="130" y="278" class="label">DENSE</text>
33
+ <text x="160" y="316" class="sub">Ink carries more of the separation load</text>
34
+ <text x="1675" y="278" class="label">COMFORT</text>
35
+ <text x="1698" y="316" class="sub">Space carries more of the separation load</text>
36
+ <rect x="130" y="336" width="1395" height="360" rx="28" fill="#f5f6f8" stroke="#37373c" stroke-width="5"/>
37
+ <rect x="135" y="341" width="1385" height="86" rx="22" fill="#ffffff"/>
38
+ <circle cx="173" cy="384.0" r="16" fill="#d2d4da" stroke="#5f5f66" stroke-width="1"/>
39
+ <text x="203" y="385" class="ui-bold">Settings</text>
40
+ <rect x="1388" y="366.0" width="110" height="36" rx="18" fill="#ebecf0" stroke="#8c8e94" stroke-width="1"/>
41
+ <circle cx="1480.0" cy="384.0" r="18.0" fill="#ffffff" stroke="#8c8e94" stroke-width="1"/>
42
+ <rect x="135" y="443" width="1385" height="78" fill="#ffffff"/>
43
+ <rect x="157" y="464.0" width="36" height="36" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="2"/>
44
+ <text x="211" y="481" class="ui-bold">Option 1</text>
45
+ <text x="211" y="515" class="small">Supporting detail</text>
46
+ <line x1="1470" y1="474.0" x2="1478" y2="482.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
47
+ <line x1="1470" y1="490.0" x2="1478" y2="482.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
48
+ <line x1="135" y1="521" x2="1520" y2="521" stroke="#46484e" stroke-width="4" stroke-linecap="round"/>
49
+ <rect x="135" y="521" width="1385" height="78" fill="#fafbfd"/>
50
+ <rect x="157" y="542.0" width="36" height="36" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="2"/>
51
+ <line x1="165" y1="560.0" x2="173" y2="570.0" stroke="#46484e" stroke-width="3" stroke-linecap="round"/>
52
+ <line x1="173" y1="570.0" x2="187" y2="550.0" stroke="#46484e" stroke-width="3" stroke-linecap="round"/>
53
+ <text x="211" y="559" class="ui">Option 2</text>
54
+ <text x="211" y="593" class="small">Supporting detail</text>
55
+ <line x1="1470" y1="552.0" x2="1478" y2="560.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
56
+ <line x1="1470" y1="568.0" x2="1478" y2="560.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
57
+ <line x1="135" y1="599" x2="1520" y2="599" stroke="#46484e" stroke-width="4" stroke-linecap="round"/>
58
+ <rect x="135" y="599" width="1385" height="78" fill="#ffffff"/>
59
+ <rect x="157" y="620.0" width="36" height="36" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="2"/>
60
+ <text x="211" y="637" class="ui">Option 3</text>
61
+ <text x="211" y="671" class="small">Supporting detail</text>
62
+ <line x1="1470" y1="630.0" x2="1478" y2="638.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
63
+ <line x1="1470" y1="646.0" x2="1478" y2="638.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
64
+ <line x1="135" y1="677" x2="1520" y2="677" stroke="#46484e" stroke-width="2" stroke-linecap="round"/>
65
+
66
+ <line x1="152" y1="596" x2="392" y2="596" stroke="#28282d" stroke-width="4" stroke-linecap="round"/>
67
+ <text x="412" y="596" class="small" style="fill:#141416;">4px separator</text>
68
+ <rect x="1675" y="336" width="1395" height="360" rx="28" fill="#f5f6f8" stroke="#37373c" stroke-width="2"/>
69
+ <rect x="1677" y="338" width="1391" height="104" rx="22" fill="#ffffff"/>
70
+ <circle cx="1725" cy="390.0" r="18" fill="#d2d4da" stroke="#5f5f66" stroke-width="1"/>
71
+ <text x="1757" y="392" class="ui-bold">Settings</text>
72
+ <rect x="2928" y="372.0" width="110" height="36" rx="18" fill="#ebecf0" stroke="#8c8e94" stroke-width="1"/>
73
+ <circle cx="3020.0" cy="390.0" r="18.0" fill="#ffffff" stroke="#8c8e94" stroke-width="1"/>
74
+ <rect x="1677" y="464" width="1391" height="105" fill="#ffffff"/>
75
+ <rect x="1707" y="496.5" width="40" height="40" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="1"/>
76
+ <text x="1765" y="512" class="ui-bold">Option 1</text>
77
+ <text x="1765" y="546" class="small">Supporting detail</text>
78
+ <line x1="3010" y1="508.5" x2="3018" y2="516.5" stroke="#787a80" stroke-width="2" stroke-linecap="round"/>
79
+ <line x1="3010" y1="524.5" x2="3018" y2="516.5" stroke="#787a80" stroke-width="2" stroke-linecap="round"/>
80
+ <line x1="1677" y1="569" x2="3068" y2="569" stroke="#96989e" stroke-width="1" stroke-linecap="round"/>
81
+ <rect x="1677" y="569" width="1391" height="105" fill="#fafbfd"/>
82
+ <rect x="1707" y="601.5" width="40" height="40" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="1"/>
83
+ <line x1="1715" y1="621.5" x2="1725" y2="633.5" stroke="#46484e" stroke-width="2" stroke-linecap="round"/>
84
+ <line x1="1725" y1="633.5" x2="1741" y2="609.5" stroke="#46484e" stroke-width="2" stroke-linecap="round"/>
85
+ <text x="1765" y="617" class="ui">Option 2</text>
86
+ <text x="1765" y="651" class="small">Supporting detail</text>
87
+ <line x1="3010" y1="613.5" x2="3018" y2="621.5" stroke="#787a80" stroke-width="2" stroke-linecap="round"/>
88
+ <line x1="3010" y1="629.5" x2="3018" y2="621.5" stroke="#787a80" stroke-width="2" stroke-linecap="round"/>
89
+ <line x1="1677" y1="674" x2="3068" y2="674" stroke="#96989e" stroke-width="1" stroke-linecap="round"/>
90
+ <rect x="1707" y="811.5" width="40" height="40" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="1"/>
91
+ <line x1="1705" y1="570" x2="1945" y2="570" stroke="#28282d" stroke-width="1" stroke-linecap="round"/>
92
+ <text x="1965" y="572" class="small" style="fill:#141416;">1px separator</text>
93
+ <text x="760.0" y="240" class="small" >Density mode</text>
94
+ <line x1="680.0" y1="278" x2="920.0" y2="278" stroke="#a0a2a8" stroke-width="6" stroke-linecap="round"/>
95
+ <line x1="680.0" y1="266" x2="680.0" y2="290" stroke="#a0a2a8" stroke-width="4" stroke-linecap="round"/>
96
+ <line x1="800.0" y1="266" x2="800.0" y2="290" stroke="#a0a2a8" stroke-width="4" stroke-linecap="round"/>
97
+ <line x1="920.0" y1="266" x2="920.0" y2="290" stroke="#a0a2a8" stroke-width="4" stroke-linecap="round"/>
98
+ <circle cx="730.0" cy="278" r="20" fill="#ffffff" stroke="#46484e" stroke-width="4"/>
99
+ <text x="674.0" y="328" class="small">Dense</text>
100
+ <text x="834.0" y="328" class="small">Comfort</text>
101
+ <text x="1600.0" y="770" text-anchor="middle" class="small">Non-breaking adjustment: tune stroke thickness per density mode; preserve semantic meaning of boundaries.</text>
102
+ </svg>
@@ -0,0 +1,480 @@
1
+ # CEM D5 Stroke & Separation — Boundaries, Dividers, and Focus Indicators
2
+
3
+ **Status:** Proposed (canonical CEM spec)
4
+ **Last updated:** December 19, 2025
5
+
6
+ **Taxonomy placement:** D5. Stroke & Separation (part of the 7-dimensional CEM token framework)
7
+
8
+ **Companion specs:**
9
+ - **D0. Color (Emotional Palette & System Color Mapping)** ([`cem-colors.md`](./cem-colors.md)) — defines separator/focus colors; D5 defines *thickness and geometry*
10
+ - **D1. Space & Rhythm** ([`cem-dimension.md`](./cem-dimension.md)) — inset/spacing rules that keep strokes readable without crowding
11
+ - **D2. Coupling & Compactness** ([`cem-coupling.md`](./cem-coupling.md)) — density modes that affect when thin strokes must become stronger
12
+ - **D3. Shape — Bend** ([`cem-shape.md`](./cem-shape.md)) — corner radii and rounding rules that strokes must follow
13
+ - **D4. Layering** ([`cem-layering.md`](./cem-layering.md)) — when to prefer shadow separation vs stroke separation
14
+ - **D7. Time & Motion** ([`cem-timing.md`](./cem-timing.md)) — animation timing for focus/selection transitions
15
+
16
+ ---
17
+
18
+ ## Contents
19
+
20
+ 1. [What D5 controls](#1-what-d5-controls)
21
+ 2. [Design goals](#2-design-goals)
22
+ 3. [Minimal stroke basis](#3-minimal-stroke-basis)
23
+ 4. [Semantic endpoints (product-facing contract)](#4-semantic-endpoints-product-facing-contract)
24
+ 5. [Focus, selected, and target indicators](#5-focus-selected-and-target-indicators)
25
+ 6. [Dividers and separators](#6-dividers-and-separators)
26
+ 7. [Inter-dimension coupling](#7-inter-dimension-coupling)
27
+ 8. [Accessibility and forced-colors requirements](#8-accessibility-and-forced-colors-requirements)
28
+ 9. [Implementation guidance (CSS recipes)](#9-implementation-guidance-css-recipes)
29
+ 10. [Framework mapping guidance (Angular Material, MUI)](#10-framework-mapping-guidance-angular-material-mui)
30
+ 11. [Canonical token summary](#11-canonical-token-summary)
31
+ 12. [Governance and versioning](#12-governance-and-versioning)
32
+ 13. [References](#13-references)
33
+
34
+ ---
35
+
36
+ ## 1. What D5 controls
37
+
38
+ D5 defines the **geometry of separation**:
39
+
40
+ - **Stroke thickness**: borders, hairlines, dividers, gridlines, outlines.
41
+ - **Indicator geometry**: focus rings, selection rings, target indicators (including patterned outlines such as zebra).
42
+ - **Stroke placement**: whether an indicator is *inside* the component, *on the edge*, or *outside* the component.
43
+
44
+ D5 **does not** define:
45
+ - **Colors** (D0 defines `Canvas`, `CanvasText`, `SelectedItem`, emotional palettes, etc.).
46
+ - **Spacing and inset** (D1).
47
+ - **Component height or density rules** (D2).
48
+ - **Corner rounding** (D3).
49
+ - **Motion curves and timing** (D7).
50
+
51
+ ---
52
+
53
+ ## 2. Design goals
54
+
55
+ ### 2.1 Consumer semantics first
56
+
57
+ Tokens must express *what the stroke means to the consumer*, not how it is implemented:
58
+
59
+ - “boundary” vs “divider” vs “focus indicator” vs “selection indicator”
60
+ - not “mdc notched-outline width” or “outlined input border width”
61
+
62
+ ### 2.2 Bounded complexity
63
+
64
+ Stroke systems can explode into per-component and per-state width tokens. CEM avoids that by defining:
65
+
66
+ - a **small width basis** (few values)
67
+ - a **small set of semantic endpoints**
68
+ - and **mapping guidance** for frameworks that expose many internal variables.
69
+
70
+ ### 2.3 No layout shift on interaction
71
+
72
+ Changing border width on focus is a common source of **layout shift** (e.g., label jumps in outlined text fields). Focus and selection indicators should be drawn using **outline** or **box-shadow**, or on a pseudo-element, rather than changing border-box geometry.
73
+
74
+ ### 2.4 Accessibility as a hard constraint
75
+
76
+ D5 must support modern focus-indicator requirements (including minimum visible area/thickness and sufficient contrast in high-contrast themes). See §8.
77
+
78
+ ---
79
+
80
+ ## 3. Minimal stroke basis
81
+
82
+ CEM D5 uses a **4-step stroke basis** that covers almost all UI needs without a large token surface.
83
+
84
+ ### 3.1 Stroke basis tokens
85
+
86
+ > These tokens are *foundational*. Semantic endpoints map to them.
87
+
88
+ ```css
89
+ :root {
90
+ /* Basis: keep small and stable */
91
+ --cem-stroke-none: 0px; /* no stroke */
92
+ --cem-stroke-hair: 1px; /* hairline separators, subtle boundaries */
93
+ --cem-stroke-standard: 2px; /* focus/selection indicators; high legibility */
94
+ --cem-stroke-strong: 3px; /* high-emphasis boundaries; contrast themes */
95
+ }
96
+ ```
97
+
98
+ **Notes**
99
+ - `1px` remains device-independent (CSS px), and is appropriate for dividers and subtle component boundaries.
100
+ - `2px` is the default for **focus visibility** and state distinction.
101
+ - `3px` exists primarily for **high contrast** and “hard separation” contexts.
102
+
103
+ - Material Design component specs frequently use 1–2dp stroke thickness for outlines and focus indicators; in web CEM this maps cleanly onto `1px` hairlines and `2px` indicators (see References for representative component spec links and issue discussions).
104
+
105
+
106
+ ### 3.2 Density coupling (D2 interaction)
107
+
108
+ Stroke thickness is allowed to vary *by density mode* as a **non-breaking** adjustment, as long as semantics stay intact:
109
+
110
+ - Dense UI may need **stronger strokes** because small targets and reduced whitespace reduce separability.
111
+ - Comfort UI can remain at hairline boundaries in more places because whitespace carries part of the separation work.
112
+ ![cem-stroke-density-illustration-4to1-v3.svg](./cem-stroke-density-illustration-4to1-v3.svg)
113
+ ---
114
+
115
+ ## 4. Semantic endpoints (product-facing contract)
116
+
117
+ These are the **canonical semantic endpoints** that components consume.
118
+
119
+ ### 4.1 Endpoints
120
+
121
+ ```css
122
+ :root {
123
+ /* Canonical boundaries */
124
+ --cem-stroke-boundary: var(--cem-stroke-hair);
125
+
126
+ /* Canonical separators */
127
+ --cem-stroke-divider: var(--cem-stroke-hair);
128
+
129
+ /* Canonical indicators */
130
+ --cem-stroke-focus: var(--cem-stroke-standard);
131
+ --cem-stroke-selected: var(--cem-stroke-standard);
132
+ --cem-stroke-target: var(--cem-stroke-standard);
133
+
134
+ /* Placement */
135
+ --cem-stroke-indicator-offset: 2px; /* distance outside the edge, not thickness */
136
+
137
+ /* Optional convenience endpoints (aliases, not required by contract) */
138
+ --cem-stroke-grid: var(--cem-stroke-divider); /* tables / data grids */
139
+ --cem-stroke-boundary-strong: var(--cem-stroke-standard); /* dialogs / sheets when needed */
140
+ }
141
+ ```
142
+
143
+ ### 4.2 Semantics (normative)
144
+
145
+ - `--cem-stroke-boundary` is the default edge for **control containers** (text fields, chips, cards, tiles).
146
+ - `--cem-stroke-divider` separates **siblings** (list rows, table rows, sections).
147
+ - `--cem-stroke-focus` is for **keyboard focus** (and must meet §8).
148
+ - `--cem-stroke-selected` marks **selection** where background does not carry the whole burden of state (CEM preference).
149
+ - `--cem-stroke-target` marks a **deep-linked / navigated-to** target (e.g., URL fragment target, “jump to result”).
150
+ - `--cem-stroke-indicator-offset` prevents rings/indicators from visually merging with the component edge.
151
+
152
+ Optional convenience endpoints (aliases):
153
+
154
+ - `--cem-stroke-grid` is a readability alias for “divider inside structured content” (tables / data grids).
155
+ - `--cem-stroke-boundary-strong` is a stronger boundary used only when elevation/shadow is unavailable or insufficient.
156
+
157
+ ---
158
+
159
+ ### 4.3 Component mapping matrix (informative)
160
+
161
+ The D5 contract intentionally avoids per-component thickness tokens (e.g., `--cem-input-outline`). Instead:
162
+
163
+ - Components bind to one of the **semantic endpoints** (boundary/divider/focus/selected/target).
164
+ - Component libraries may expose **adapter variables** with component-friendly names, but those adapter names are *not* part of the canonical CEM contract.
165
+
166
+ > Rule of thumb: **color is D0**, **thickness is D5**, **corner curvature is D3**, **spacing/insets is D1**, **density-mode overrides are D2**.
167
+
168
+ | Component family | Primary D5 endpoint(s) | Typical stroke usage | Notes |
169
+ |------------------------------------------|--------------------------------------------------------|--------------------------------|----------------------------------------------------------------------------------------------------------------------------|
170
+ | Dividers (horizontal/vertical) | `--cem-stroke-divider` | 1px hairline between siblings | Prefer inset patterns for lists; increase strength in dense or low-contrast contexts. |
171
+ | List item separators | `--cem-stroke-divider` (or `--cem-stroke-grid`) | Row separators | Treat dense “data-list” layouts as a grid for readability. |
172
+ | Table borders / grid lines | `--cem-stroke-grid` | Cell/row separators | Use `grid` to distinguish “structured separators” from generic dividers; same thickness by default. |
173
+ | Text field outline (outlined pattern) | `--cem-stroke-boundary` | Control container edge | Focus indication should be a ring (`--cem-stroke-focus`) rather than mutating border width. |
174
+ | Text field underline (filled pattern) | `--cem-stroke-boundary` or `--cem-stroke-divider` | Baseline boundary | Underline is a boundary of the control, not a sibling divider; map to divider only when visually used as “row separation”. |
175
+ | Outlined button border | `--cem-stroke-boundary` | Variant boundary | Use `boundary-strong` only for “hard separation” themes (e.g., low-elevation UIs). |
176
+ | Card / tile border | `--cem-stroke-boundary` (often `--cem-stroke-none`) | Optional edge | Prefer D4 elevation or D0 surface contrast; use boundary only when needed for scannability. |
177
+ | Checkbox / radio container border | `--cem-stroke-boundary` | Control boundary | The checkmark/dot is not a stroke token concern; it is icon geometry (D3) + color (D0). |
178
+ | Switch track outline (if any) | `--cem-stroke-boundary` | Track boundary | Track *height* is D2/D1, not D5; D5 only provides line weight if outlined. |
179
+ | Chip / badge border (bordered variant) | `--cem-stroke-boundary` | Subtle outline | In dense chips, consider mapping `boundary` → `standard` via D2 coupling if needed for separation. |
180
+ | Tabs / segmented control indicator | `--cem-stroke-selected` | Active underline/bar thickness | Avoid using `divider` for active indicators; indicators communicate state, not separation. |
181
+ | Focus ring (all controls) | `--cem-stroke-focus` + `--cem-stroke-indicator-offset` | External ring/outline | Must satisfy WCAG 2.2 focus appearance (§8.1). |
182
+ | Target highlight (deep link / “jump to”) | `--cem-stroke-target` | Temporary outline/ring | Distinct from focus: target is navigational, focus is interactive. |
183
+ | Menus / dropdowns / popovers (edge) | `--cem-stroke-boundary` (often none) | Optional border | Prefer D4 shadow separation; use boundary/boundary-strong in forced-colors or shadow-suppressed contexts. |
184
+ | Progress/slider tracks | (usually none) / `--cem-stroke-boundary` | Outline only if required | Track *thickness* (e.g., 8px) is a **dimension**; treat that as D2/D1, not D5. |
185
+
186
+
187
+ ## 5. Focus, selected, and target indicators
188
+
189
+ CEM uses an **outline-driven indicator** model for states that must remain visible across backgrounds:
190
+ - focus (keyboard / focus-visible)
191
+ - selected
192
+ - target (e.g., anchor `:target`)
193
+
194
+ ### 5.1 Zebra outline system (existing in `theme-data.xhtml`)
195
+
196
+ The current theme implementation uses a **zebra ring** composed of stacked outside strokes using `box-shadow` and zebra color variables:
197
+
198
+ - `--cem-zebra-strip-size`
199
+ - `--cem-zebra-color-0` … `--cem-zebra-color-3`
200
+ - `--cem-action-box-shadow` (used by `.action` components)
201
+
202
+ In normal themes, a 3-stripe ring is used; in contrast themes, a 4-stripe ring is used (intent + focus + selected + target).
203
+
204
+ ### 5.2 Canonical zebra tokens (D5 contract)
205
+
206
+ D5 treats these as canonical *indicator-pattern tokens*:
207
+
208
+ ```css
209
+ :root {
210
+ --cem-zebra-strip-size: 2px; /* thickness per stripe */
211
+ --cem-zebra-angle: 45deg; /* if stripes are rendered as gradients */
212
+ --cem-zebra-color-0: Canvas; /* intent / base stripe (contrast themes) */
213
+ --cem-zebra-color-1: CanvasText; /* focus stripe */
214
+ --cem-zebra-color-2: SelectedItem; /* selected stripe */
215
+ --cem-zebra-color-3: SelectedItem; /* target stripe (or themed alternative) */
216
+ }
217
+ ```
218
+
219
+ ### 5.3 Recommended indicator composition (box-shadow ring)
220
+
221
+ ```css
222
+ /* 3-stripe ring: focus/selected/target (normal themes) */
223
+ --cem-ring-zebra-3:
224
+ 0 0 0 calc(1 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-1),
225
+ 0 0 0 calc(2 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-2),
226
+ 0 0 0 calc(3 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-3);
227
+
228
+ /* 4-stripe ring: intent + focus + selected + target (contrast themes) */
229
+ --cem-ring-zebra-4:
230
+ 0 0 0 calc(1 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-0),
231
+ 0 0 0 calc(2 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-1),
232
+ 0 0 0 calc(3 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-2),
233
+ 0 0 0 calc(4 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-3);
234
+ ```
235
+
236
+ **Why `box-shadow`?**
237
+ - Avoids layout shift (unlike border-width changes).
238
+ - Works with rounded corners (D3) and can visually sit outside the component.
239
+ - Can be swapped to `outline` in forced-colors contexts (§8.2).
240
+
241
+ ### 5.4 Focus heuristics
242
+
243
+ Prefer `:focus-visible` semantics. If the platform needs a polyfilled focus-ring behavior, align with heuristics similar to Material Web’s focus ring utilities (see references).
244
+
245
+ ---
246
+
247
+ ## 6. Dividers and separators
248
+
249
+ ### 6.1 Divider role types
250
+
251
+ CEM recognizes three common divider roles (same thickness basis, different usage):
252
+
253
+ 1. **Section divider**: separates groups (higher salience)
254
+ 2. **Row divider**: list/table row hairlines
255
+ 3. **Gridline**: dense tabular separation
256
+
257
+ All three should normally map to `--cem-stroke-divider` (hairline). Promote to `--cem-stroke-boundary-strong` when:
258
+ - the UI is dense (D2)
259
+ - the background is textured/animated
260
+ - or the consumer must not miss the separation (e.g., critical comparison tables).
261
+
262
+ ### 6.2 Inset patterns (non-token guidance)
263
+
264
+ Avoid creating many inset tokens. Use a single **inset rule**:
265
+ - “Full-bleed dividers for full-bleed lists”
266
+ - “Inset dividers under leading avatar/icon to preserve grouping”
267
+
268
+ Spacing and inset should use D1 tokens.
269
+
270
+ ---
271
+
272
+ ## 7. Inter-dimension coupling
273
+
274
+ ### 7.1 D3 shape coupling
275
+
276
+ Indicator rings should follow component rounding:
277
+
278
+ ```css
279
+ border-radius: var(--cem-bend-control);
280
+ box-shadow: var(--cem-ring-zebra-3);
281
+ ```
282
+
283
+ If the ring is outside, it may require a slightly larger radius:
284
+
285
+ ```css
286
+ border-radius: calc(var(--cem-bend-control) + var(--cem-stroke-indicator-offset));
287
+ ```
288
+
289
+ ### 7.2 D1 spacing coupling
290
+
291
+ Where indicators sit outside the edge, ensure surrounding layout provides enough breathing room. Prefer:
292
+ - container padding (D1)
293
+ - or internal “guard rails” around interactive controls (D2), including `--cem-coupling-guard-min`
294
+ and `--cem-coupling-halo`
295
+
296
+ Treat `--cem-coupling-guard-min` as the default clearance budget between adjacent operable zones.
297
+ If you increase any of the following, you must also increase surrounding D1 spacing and/or D2 guard/halo
298
+ (or accept overlap):
299
+
300
+ - zebra ring outset: `3 * --cem-zebra-strip-size` (normal) / `4 * --cem-zebra-strip-size` (contrast)
301
+ - outline outset: `--cem-stroke-indicator-offset + --cem-stroke-focus`
302
+
303
+ See the D2 compatibility rule in [`cem-coupling.md`](./cem-coupling.md) §4.1.1.
304
+
305
+ ### 7.3 D4 elevation coupling
306
+
307
+ Elevation and stroke are substitutes:
308
+ - Use elevation for depth separation in normal themes where shadows are viable.
309
+ - Use stroke (including zebra) in contrast themes, where shadows can be insufficient.
310
+
311
+ ---
312
+
313
+ ## 8. Accessibility and forced-colors requirements
314
+
315
+ ### 8.1 Focus appearance (WCAG 2.2)
316
+
317
+ The focus indicator must be large/visible enough to be reliably perceived. A robust default is a **2px** perimeter (or equivalent area) around the focused component, which D5’s `--cem-stroke-focus` supports.
318
+
319
+ ### 8.2 Forced colors / high contrast
320
+
321
+ In `forced-colors: active` contexts:
322
+ - prefer `outline` (system colors) and avoid relying on subtle shadows
323
+ - avoid gradients that may be flattened
324
+ - ensure indicator uses `CanvasText` / `Highlight` as appropriate in D0 mapping
325
+
326
+ Suggested baseline:
327
+
328
+ ```css
329
+ @media (forced-colors: active) {
330
+ .cem-focusable:focus-visible {
331
+ outline: var(--cem-stroke-focus) solid CanvasText;
332
+ outline-offset: var(--cem-stroke-indicator-offset);
333
+ box-shadow: none;
334
+ }
335
+ }
336
+ ```
337
+
338
+ ---
339
+
340
+ ## 9. Implementation guidance (CSS recipes)
341
+
342
+ ### 9.1 Prefer rings over border-width mutation
343
+
344
+ **Avoid**
345
+ ```css
346
+ /* Causes layout shift */
347
+ .control:focus { border-width: 2px; }
348
+ ```
349
+
350
+ **Prefer**
351
+ ```css
352
+ .control:focus-visible {
353
+ outline: var(--cem-stroke-focus) solid currentColor;
354
+ outline-offset: var(--cem-stroke-indicator-offset);
355
+ }
356
+ ```
357
+
358
+ or (for rounded geometry / zebra):
359
+ ```css
360
+ .control:focus-visible {
361
+ box-shadow: var(--cem-ring-zebra-3);
362
+ }
363
+ ```
364
+
365
+ ### 9.2 Layering order for multiple indicators
366
+
367
+ If multiple indicators can apply, compose in a stable order:
368
+ 1. focus
369
+ 2. selected
370
+ 3. target
371
+
372
+ In zebra, this is naturally expressed as concentric stripes.
373
+
374
+ ### 9.3 Action components (existing pattern)
375
+
376
+ Current implementation uses:
377
+
378
+ ```css
379
+ .action { box-shadow: var(--cem-action-box-shadow); }
380
+ .action:hover { --cem-action-box-shadow: var(--cem-action-box-shadow-hover); }
381
+ .action:active { --cem-action-box-shadow: var(--cem-action-box-shadow-active); }
382
+ ```
383
+
384
+ In contrast themes, `--cem-action-box-shadow` becomes the zebra ring.
385
+
386
+ ---
387
+
388
+ ## 10. Framework mapping guidance (Angular Material, MUI)
389
+
390
+ This section is **non-normative**. It documents how to map framework tokens/variables into the CEM D5 semantic endpoints.
391
+
392
+ ### 10.1 Angular Material (MDC-based) mapping
393
+
394
+ Common MDC variables (examples seen in Angular Material customization workflows):
395
+
396
+ - `--mdc-outlined-text-field-outline-width` → `--cem-stroke-boundary`
397
+ - `--mdc-outlined-text-field-focus-outline-width` → `--cem-stroke-focus` (or `--cem-stroke-boundary-strong`)
398
+ - `--mdc-filled-text-field-active-indicator-height` → `--cem-stroke-divider`
399
+ - `--mdc-filled-text-field-focus-active-indicator-height` → `--cem-stroke-focus`
400
+ - `--mdc-outlined-card-outline-width` → `--cem-stroke-boundary`
401
+
402
+ Angular Material also exposes higher-level variables in some setups, e.g.:
403
+ - `--mat-form-field-outlined-focus-outline-width` → `--cem-stroke-focus`
404
+
405
+ **Guidance:** map these variables *from* CEM tokens; do not treat them as canonical tokens in CEM.
406
+
407
+ ### 10.2 MUI mapping
408
+
409
+ **MUI System**
410
+ - `sx={{ border: 1 }}` expresses a border thickness via the theme’s `borders` scale.
411
+ - Map `border: 1` (typical) to `--cem-stroke-boundary` (hairline).
412
+
413
+ **MUI Joy UI**
414
+ Joy exposes per-component CSS variables for focus ring geometry (examples):
415
+ - `--Input-focusedThickness` → `--cem-stroke-focus`
416
+ - `--Input-focusedInset` → whether focus is inset or outset (maps to indicator placement policy)
417
+ - `--Input-focusedOffset` → `--cem-stroke-indicator-offset`
418
+
419
+ ---
420
+
421
+ ## 11. Canonical token summary
422
+
423
+ | Token | Category | Required | Meaning |
424
+ |------|----------|----------|---------|
425
+ | `--cem-stroke-none` | Basis | ✓ | No stroke |
426
+ | `--cem-stroke-hair` | Basis | ✓ | 1px hairline |
427
+ | `--cem-stroke-standard` | Basis | ✓ | 2px standard indicator |
428
+ | `--cem-stroke-strong` | Basis | ✓ | 3px strong separation |
429
+ | `--cem-stroke-boundary` | Semantic | ✓ | Default component boundary |
430
+ | `--cem-stroke-boundary-strong` | Semantic | Optional | Strong boundary for cases where elevation/shadow cannot carry separation |
431
+ | `--cem-stroke-divider` | Semantic | ✓ | Default separator/divider |
432
+ | `--cem-stroke-grid` | Semantic | Optional | Divider alias for structured content (tables/grids) |
433
+ | `--cem-stroke-focus` | Semantic | ✓ | Focus-visible indicator width |
434
+ | `--cem-stroke-selected` | Semantic | ✓ | Selection indicator width |
435
+ | `--cem-stroke-target` | Semantic | ✓ | Target indicator width |
436
+ | `--cem-stroke-indicator-offset` | Placement | ✓ | Ring/outline offset distance |
437
+ | `--cem-zebra-strip-size` | Pattern | Optional | Stripe thickness for zebra indicators |
438
+ | `--cem-zebra-angle` | Pattern | Optional | Stripe angle for gradient zebra |
439
+ | `--cem-zebra-color-0..3` | Pattern | Optional | Concentric zebra stripe colors (intent/focus/selected/target) |
440
+ | `--cem-action-box-shadow` | Adapter hook | Optional | Existing action indicator/shadow hook (implementation detail) |
441
+
442
+ ---
443
+
444
+ ## 12. Governance and versioning
445
+
446
+ ### 12.1 What counts as breaking
447
+
448
+ Treat as **major** (breaking) if you:
449
+
450
+ - Rename or remove any **Required (✓)** D5 endpoint listed in §11.
451
+ - Change the semantic meaning of an endpoint (e.g., `--cem-stroke-focus` no longer representing focus thickness).
452
+ - Remove zebra token meanings that consumers rely on (e.g., swapping which stripe denotes focus).
453
+
454
+ ### 12.2 What is non-breaking
455
+
456
+ Treat as **minor/patch** if you:
457
+
458
+ - Adjust numeric values within a theme while preserving semantics (e.g., `2px` → `3px` in contrast theme only).
459
+ - Add new optional endpoints that are clearly scoped.
460
+ - Clarify documentation, examples, or mapping guidance.
461
+
462
+ ---
463
+
464
+ ## 13. References
465
+
466
+ - W3C WCAG 2.2 Understanding: Focus Appearance (Minimum) — https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance.html
467
+ - MDN: `:focus-visible` — https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible
468
+ - Material Web focus ring documentation — https://github.com/material-components/material-web/blob/main/docs/components/focus-ring.md
469
+ - Material Design 3 component specs (stroke/focus indicator values are listed per component):
470
+ - Menus (specs) — https://m3.material.io/components/menus/specs
471
+ - Checkbox (specs) — https://m3.material.io/components/checkbox/specs
472
+ - Google issue tracker example referencing OutlinedTextField outline thickness in specs — https://issuetracker.google.com/issues/191543915
473
+
474
+ - Angular Material customization guidance — https://v12.material.angular.io/guide/customizing-component-styles
475
+ - Angular Material outlined form-field focus border width discussion (example) — https://github.com/angular/components/issues/28023
476
+ - Angular Material customization examples showing outline width variables (examples):
477
+ - https://www.fusonic.net/en/blog/angular-material-customization
478
+ - https://dev.to/dhutaryan/how-to-make-angular-material-inputs-look-like-simple-fields-3oe5
479
+ - MUI System borders utilities — https://mui.com/system/borders/
480
+ - MUI Joy UI Input variables (focus thickness/offset) — https://mui.com/joy-ui/react-input/