@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,691 @@
1
+ # CEM D3 Shape — Bend (Edge Softness & Corner Roundedness)
2
+
3
+ **Status:** Proposed (canonical CEM spec)
4
+ **Last updated:** December 19, 2025
5
+
6
+ **Taxonomy placement:** D3. Shape & Bend (part of the 7-dimensional CEM token framework)
7
+
8
+ **Companion specs:**
9
+ - **D0. Color (Emotional Palette)** ([`cem-colors.md`](./cem-colors.md)) — color and shape work together for emotional impact
10
+ - **D1. Space & Rhythm** ([`cem-dimension.md`](./cem-dimension.md)) — provides dimension scale used by bend
11
+ - **D2. Coupling & Compactness** ([`cem-coupling.md`](./cem-coupling.md)) — provides control height for geometry-driven bend
12
+ - **D5. Stroke & Separation** ([`cem-stroke.md`](./cem-stroke.md)) — boundaries, dividers, and focus/selection/target indicators
13
+ - **D6. Typography** ([`cem-voice-fonts-typography.md`](./cem-voice-fonts-typography.md)) — related visual hierarchy
14
+ - **D7. Time & Motion** ([`cem-timing.md`](./cem-timing.md)) — animation timing for shape transitions
15
+
16
+ ---
17
+
18
+ ## Table of Contents
19
+
20
+ 1. [Purpose and scope](#1-purpose-and-scope)
21
+ 2. [Why "bend" (token naming rationale)](#2-why-bend-token-naming-rationale)
22
+ 3. [CEM alignment principles applied to shape](#3-cem-alignment-principles-applied-to-shape)
23
+ - [3.1 Semantic intent first](#31-semantic-intent-first)
24
+ - [3.2 Bounded variation](#32-bounded-variation)
25
+ - [3.3 Layering (basis → semantic endpoints → adapters)](#33-layering-basis--semantic-endpoints--adapters)
26
+ 4. [Minimal bend basis (complexity-compliant)](#4-minimal-bend-basis-complexity-compliant)
27
+ 5. [Semantic endpoints (product-facing contract)](#5-semantic-endpoints-product-facing-contract)
28
+ 6. [Shape mode knob (brand expression)](#6-shape-mode-knob-brand-expression)
29
+ - [6.1 Mode meanings](#61-mode-meanings)
30
+ - [6.2 Mode implementation (recommended)](#62-mode-implementation-recommended)
31
+ - [6.3 Helper classes (optional; scoped overrides)](#63-helper-classes-optional-scoped-overrides)
32
+ 7. [Directional and asymmetric patterns](#7-directional-and-asymmetric-patterns)
33
+ - [7.1 Attachment pattern](#71-attachment-pattern-one-pattern-not-many-tokens)
34
+ - [7.2 When to use asymmetric corners](#72-when-to-use-asymmetric-corners)
35
+ - [7.3 Implementation guidance](#73-implementation-guidance)
36
+ - [7.4 Common recipes](#74-common-recipes)
37
+ 8. [Accessibility and inclusive design requirements](#8-accessibility-and-inclusive-design-requirements)
38
+ - [8.1 Shape must not be the only signal](#81-shape-must-not-be-the-only-signal)
39
+ - [8.2 High-contrast and forced-colors resilience](#82-high-contrast-and-forced-colors-resilience)
40
+ - [8.3 Focus indicators must respect the target](#83-focus-indicators-must-respect-the-target)
41
+ - [8.4 Pointer target size and spacing](#84-pointer-target-size-and-spacing-bend--d2-size--d1-separation)
42
+ - [8.5 Bend vs inset readability](#85-bend-vs-inset-readability-bend--d1-padding)
43
+ - [8.6 Minimum test checklist](#86-minimum-test-checklist)
44
+ 9. [Consumer vocabulary for "round ends" (capsules)](#9-consumer-vocabulary-for-round-ends-capsules)
45
+ 10. [Component mapping](#10-component-mapping)
46
+ - [10.1 Action binding (existing)](#101-action-binding-existing)
47
+ - [10.2 Extended component mapping](#102-extended-component-mapping)
48
+ - [10.3 Local alias pattern](#103-local-alias-pattern-preferred-for-variants)
49
+ 11. [Notes on external systems (adapter-only)](#11-notes-on-external-systems-adapter-only)
50
+ 12. [Quick adoption checklist](#12-quick-adoption-checklist)
51
+ 13. [Governance and versioning](#13-governance-and-versioning)
52
+ - [13.1 What counts as breaking (MAJOR)](#131-what-counts-as-breaking-major)
53
+ - [13.2 What is non-breaking (MINOR / PATCH)](#132-what-is-non-breaking-minor--patch)
54
+ - [13.3 Deprecation policy (recommended)](#133-deprecation-policy-recommended)
55
+ - [13.4 Canonical token summary](#134-canonical-token-summary-contract-surface)
56
+
57
+ **Appendices**
58
+ - [Appendix A — Material 3 shape scale reference](#appendix-a--material-3-shape-scale-reference-adapter-mapping)
59
+ - [References](#references)
60
+
61
+ ---
62
+
63
+ ## 1. Purpose and scope
64
+
65
+ This spec defines **shape tokens beyond actions** — a consumer-semantic subsystem for **edge softness** and **corner roundedness**.
66
+
67
+ It:
68
+
69
+ - Describes **edge softness** and **corner roundedness** in terms of *perceived friendliness* rather than pixel values.
70
+ - Provides a **bounded reference basis** that can be adapter-mapped to Material 3 (and other) shape scales.
71
+ - Exposes **semantic endpoints** for surfaces and components based on their **role** in the UI.
72
+ - Supports an optional **shape mode knob** for brand expression: `sharp | smooth | round`.
73
+
74
+ Shape tokens communicate personality and help users understand **UI boundaries, groupings, and interactive affordances**.
75
+
76
+ **Out of scope:** layering/elevation (D4 — see [`cem-layering.md`](./cem-layering.md)), stroke thickness (D5), spacing/insets (D1), and operable/touch geometry (D2) — though shape must integrate with them (see §8 Accessibility section).
77
+
78
+ ---
79
+
80
+ ## 2. Why "bend" (token naming rationale)
81
+
82
+ In CEM terms, **bend** names the degree to which an edge curves away from a sharp corner. This framing:
83
+
84
+ - Avoids ambiguity with CSS `border-radius` (which can be a length, percentage, or elliptical).
85
+ - Emphasizes the *perceived* quality rather than the *implementation* detail.
86
+ - Supports consumer-semantic intent: "How friendly/formal does this surface feel?"
87
+
88
+ **Rule:** product code should use `--cem-bend-*` endpoints; implementation primitives (`border-radius`, elliptical radii,
89
+ corner pairs, etc.) remain an adapter/implementation detail.
90
+
91
+ ---
92
+
93
+ ## 3. CEM alignment principles applied to shape
94
+
95
+ ### 3.1 Semantic intent first
96
+
97
+ Developers should apply tokens like:
98
+
99
+ - `--cem-bend-surface`, `--cem-bend-control`, `--cem-bend-overlay` (role semantics)
100
+ - `--cem-bend` (active bend value, mode-switchable)
101
+
102
+ …and not value-centric names like `radius-8` in component code.
103
+
104
+ This mirrors common design-token practice: values are "primitive/global," while **semantic/alias tokens** name where/how a
105
+ value is used. Keep product code semantic; keep value plumbing in the token layer.
106
+
107
+ ### 3.2 Bounded variation
108
+
109
+ A small set of *distinct, recognizable* bend steps should cover most UI. The range goes from:
110
+
111
+ - `sharp` (none) → `smooth` (small bend) → `round-ends` (capsule) → `circle`
112
+
113
+ CEM applies a "bounded token budget" heuristic: avoid a long ladder of barely-distinguishable bend steps. If you need a new
114
+ step, justify it by a perceptual difference that survives dense mode, high zoom, and high-contrast overrides.
115
+
116
+ ### 3.3 Layering (basis → semantic endpoints → adapters)
117
+
118
+ - **Basis tokens** define "what bend exists" (sharp / smooth / round-ends / circle).
119
+ - **Semantic endpoints** define "where bend is used" (surface / control / overlay / media).
120
+ - **Adapters** map external systems (Material / Fluent / etc.) into the basis and endpoints.
121
+
122
+ This keeps complexity low while still supporting multiple libraries.
123
+
124
+ ---
125
+
126
+ ## 4. Minimal bend basis (complexity-compliant)
127
+
128
+ This is the smallest stable basis that supports most UIs without overfitting.
129
+
130
+ ```css
131
+ :root {
132
+ /* Sharp = no bend */
133
+ --cem-bend-sharp: 0;
134
+
135
+ /* Smooth = small, friendly rounding; bind to D1 dimension scale */
136
+ --cem-bend-smooth: var(--cem-dim-x-small); /* 0.5rem / 8px */
137
+
138
+ /*
139
+ Round ends (capsule / pill):
140
+ Semicircle ends require bend = 0.5 * element height.
141
+ Uses --cem-control-height from D2 (cem-coupling.md) as default.
142
+ Provide --cem-shape-height where --cem-control-height is not appropriate.
143
+ */
144
+ --cem-bend-round: calc(var(--cem-shape-height, var(--cem-control-height)) / 2);
145
+
146
+ /* True circle (avatars): percentage is defined relative to the element box. */
147
+ --cem-bend-circle: 50%;
148
+
149
+ /* Active bend used by endpoints that want the "default feel" (mode-switchable). */
150
+ --cem-bend: var(--cem-bend-smooth);
151
+ }
152
+ ```
153
+
154
+ **Cross-references:**
155
+ - `--cem-dim-x-small` is defined in [`cem-dimension.md`](./cem-dimension.md) §5
156
+ - `--cem-control-height` is defined in [`cem-coupling.md`](./cem-coupling.md) §4.2
157
+
158
+ ---
159
+
160
+ ## 5. Semantic endpoints (product-facing contract)
161
+
162
+ These are the tokens components should consume.
163
+
164
+ ```css
165
+ :root {
166
+ /* Core roles */
167
+ --cem-bend-control: var(--cem-bend);
168
+ --cem-bend-surface: var(--cem-dim-small); /* 0.75rem / 12px — perceptual container geometry */
169
+ --cem-bend-overlay: var(--cem-bend); /* menus, tooltips, small popovers */
170
+
171
+ /* Common specializations (keep minimal) */
172
+ --cem-bend-field: var(--cem-bend-control);
173
+ --cem-bend-control-round-ends: var(--cem-bend-round); /* optional capsule control variant */
174
+ --cem-bend-modal: calc(var(--cem-dim-large) + var(--cem-dim-xx-small)); /* ~28px — larger overlays */
175
+
176
+ /* Media */
177
+ --cem-bend-media: var(--cem-bend);
178
+ --cem-bend-avatar: var(--cem-bend-circle);
179
+ }
180
+ ```
181
+
182
+ **Cross-references:**
183
+ - `--cem-dim-small`, `--cem-dim-large`, `--cem-dim-xx-small` are defined in [`cem-dimension.md`](./cem-dimension.md) §5
184
+
185
+ ---
186
+
187
+ ## 6. Shape mode knob (brand expression)
188
+
189
+ A shape mode knob is an **optional** product-level control that shifts bend across the UI to express a consistent brand
190
+ personality. It is intentionally coarse-grained: three modes are usually enough.
191
+
192
+ ### 6.1 Mode meanings
193
+
194
+ | Mode | Product intent | Typical bend policy (what changes) | Perceived feel |
195
+ |-----------|-----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|------------------------|
196
+ | `sharp` | Technical, precise, enterprise | Default bend moves toward `--cem-bend-sharp`; surfaces/overlays may remain slightly bent to preserve grouping and layer separation | Formal, authoritative |
197
+ | `smooth` | Balanced, modern (default) | Canonical defaults (base `--cem-bend-smooth`, surfaces at D1 "small") | Friendly, professional |
198
+ | `round` | Consumer, welcoming, approachable | Surfaces step up (e.g., D1 "medium"); optional capsule controls via `--cem-bend-control-round-ends` where the product uses them consistently | Warm, inviting |
199
+
200
+ **Critical constraint:** shape modes must not change meaning. A user should not need to infer state or priority from
201
+ roundness alone (see §8 Accessibility section).
202
+
203
+ ### 6.2 Mode implementation (recommended)
204
+
205
+ Implement modes via a theme selector (attribute or class) and override **only** the base and/or semantic endpoints.
206
+ Avoid an in-CSS "mode selector variable" (e.g., `--cem-shape-mode: round`) because CSS cannot branch on it without a
207
+ preprocessor; it also obscures where the mode is applied.
208
+
209
+ ```css
210
+ /* Default / smooth */
211
+ :root,
212
+ :root[data-cem-shape="smooth"] {
213
+ --cem-bend: var(--cem-bend-smooth);
214
+ --cem-bend-control: var(--cem-bend);
215
+ --cem-bend-overlay: var(--cem-bend);
216
+ --cem-bend-surface: var(--cem-dim-small);
217
+ }
218
+
219
+ /* Sharp */
220
+ :root[data-cem-shape="sharp"] {
221
+ --cem-bend: var(--cem-bend-sharp);
222
+
223
+ /* Minimum resilience policy (recommended): keep containers slightly bent unless the brand explicitly wants boxy UI */
224
+ --cem-bend-surface: var(--cem-bend-smooth);
225
+ --cem-bend-overlay: var(--cem-bend-smooth);
226
+ --cem-bend-control: var(--cem-bend); /* sharp controls */
227
+ }
228
+
229
+ /* Round */
230
+ :root[data-cem-shape="round"] {
231
+ /* Keep the default control bend unless capsules are a deliberate product-wide choice */
232
+ --cem-bend: var(--cem-bend-smooth);
233
+
234
+ --cem-bend-surface: var(--cem-dim-medium);
235
+ --cem-bend-overlay: var(--cem-bend-smooth);
236
+
237
+ /* Optional: enable capsules consistently (brand decision) */
238
+ /* --cem-bend-control: var(--cem-bend-round); */
239
+ /* --cem-bend-field: var(--cem-bend-round); */
240
+ }
241
+ ```
242
+
243
+ **If you introduce more granular local aliases** (e.g., card vs page surface), they may also be overridden by the mode
244
+ selector, but only as pointers to existing endpoints. Do not mint a parallel "mode-specific" token family.
245
+
246
+ ### 6.3 Helper classes (optional; scoped overrides)
247
+
248
+ If you need one-off local overrides (e.g., a demo page or controlled experiment), helper classes are acceptable, but should
249
+ not replace theme-level mode selectors.
250
+
251
+ ```css
252
+ .cem-bend-smooth { --cem-bend: var(--cem-bend-smooth); }
253
+ .cem-bend-round { --cem-bend: var(--cem-bend-round); }
254
+ .cem-bend-sharp { --cem-bend: var(--cem-bend-sharp); }
255
+ ```
256
+
257
+ Prefer overriding **semantic endpoints** (`--cem-bend-control`, `--cem-bend-surface`) rather than the global `--cem-bend`
258
+ when working inside components.
259
+
260
+ ---
261
+
262
+ ## 7. Directional and asymmetric patterns
263
+
264
+ ### 7.1 Attachment pattern (one pattern, not many tokens)
265
+
266
+ When a surface is **attached** (sheet, drawer), do not round the attached edge.
267
+
268
+ ```css
269
+ :root {
270
+ --cem-bend-attached-edge: var(--cem-bend-sharp);
271
+ --cem-bend-free-edge: var(--cem-bend-modal);
272
+ }
273
+
274
+ /* Example: bottom sheet */
275
+ .cem-bottom-sheet {
276
+ border-radius:
277
+ var(--cem-bend-free-edge)
278
+ var(--cem-bend-free-edge)
279
+ var(--cem-bend-attached-edge)
280
+ var(--cem-bend-attached-edge);
281
+ }
282
+ ```
283
+
284
+ ### 7.2 When to use asymmetric corners
285
+
286
+ Use asymmetric bend only when it communicates **composition**:
287
+
288
+ - **Attached elements:** popovers, sheets, or dropdowns visually "connected" to a trigger or viewport edge
289
+ - **Grouped controls:** segmented buttons / grouped toggles where only the outer corners are rounded
290
+ - **Sectioned containers:** card headers/footers that inherit top/bottom corners from the parent surface
291
+
292
+ Do **not** use asymmetric corners as the sole carrier of meaning or state (see §8 Accessibility section).
293
+
294
+ ### 7.3 Implementation guidance
295
+
296
+ - Prefer **logical corner properties** so behavior is correct in RTL and other writing modes:
297
+ `border-start-start-radius`, `border-start-end-radius`, `border-end-start-radius`, `border-end-end-radius`.
298
+ - Reuse existing semantic/basis tokens (`--cem-bend-control`, `--cem-bend-overlay`, `--cem-bend-attached-edge`,
299
+ `--cem-bend-free-edge`) rather than minting new global "top/start/end" tokens.
300
+
301
+ ### 7.4 Common recipes
302
+
303
+ **1) Popover attached to a trigger (attached on top, free on bottom)**
304
+
305
+ ```css
306
+ .cem-popover--attached-top {
307
+ border-start-start-radius: var(--cem-bend-attached-edge);
308
+ border-start-end-radius: var(--cem-bend-attached-edge);
309
+ border-end-start-radius: var(--cem-bend-overlay);
310
+ border-end-end-radius: var(--cem-bend-overlay);
311
+ }
312
+ ```
313
+
314
+ **2) Segmented / grouped controls (outer corners only)**
315
+
316
+ ```css
317
+ .cem-segment {
318
+ border-radius: 0; /* inner corners remain sharp */
319
+ }
320
+
321
+ .cem-segment:first-child {
322
+ border-start-start-radius: var(--cem-bend-control);
323
+ border-end-start-radius: var(--cem-bend-control);
324
+ }
325
+
326
+ .cem-segment:last-child {
327
+ border-start-end-radius: var(--cem-bend-control);
328
+ border-end-end-radius: var(--cem-bend-control);
329
+ }
330
+ ```
331
+
332
+ **3) Card header inherits top corners, body stays rectangular**
333
+
334
+ ```css
335
+ .cem-card {
336
+ border-radius: var(--cem-bend-surface);
337
+ overflow: clip; /* ensure header background respects corners */
338
+ }
339
+
340
+ .cem-card__header {
341
+ border-start-start-radius: var(--cem-bend-surface);
342
+ border-start-end-radius: var(--cem-bend-surface);
343
+ border-end-start-radius: 0;
344
+ border-end-end-radius: 0;
345
+ }
346
+ ```
347
+
348
+ **Optional local shorthand (avoid globals):** If you need `border-radius` shorthand, keep it component-scoped and do not
349
+ encode LTR assumptions into global `--cem-bend-start/end` variables.
350
+
351
+ ---
352
+
353
+ ## 8. Accessibility and inclusive design requirements
354
+
355
+ Bend is a *secondary* visual cue. It must never be the only carrier of state, meaning, or instructions.
356
+
357
+ ### 8.1 Shape must not be the only signal
358
+
359
+ Do not encode meaning using bend alone (e.g., "rounded = primary" / "square = secondary") unless there is a redundant cue
360
+ (color, text, icon, pattern, or stroke).
361
+
362
+ ### 8.2 High-contrast and forced-colors resilience
363
+
364
+ High-contrast modes can override fills/shadows and reduce the perceptibility of subtle shape differences. Treat bend deltas
365
+ smaller than "sharp vs smooth" as **non-essential**. For critical distinctions:
366
+
367
+ - rely on **D5 stroke/outline** ([`cem-stroke.md`](./cem-stroke.md)) and **D0 color semantics**
368
+ - provide non-color redundancy (icon/text) for state/meaning
369
+
370
+ ### 8.3 Focus indicators must respect the target
371
+
372
+ Focus rings and outlines must align with the target's bend, and must remain visible at high zoom and in forced-colors.
373
+
374
+ Practical guidance (cross-dimension):
375
+
376
+ - **D1:** reserve ring space via offset/inset so the ring does not collide with corners or get clipped (see [`cem-dimension.md`](./cem-dimension.md)).
377
+ - **D5:** define focus stroke width and style via `--cem-stroke-focus`; do not rely on bend to indicate focus (see [`cem-stroke.md`](./cem-stroke.md) §5).
378
+ - **D2:** ensure focus ring does not reduce effective hit size; hit targets remain compliant (see [`cem-coupling.md`](./cem-coupling.md)).
379
+
380
+ Recommended robust pattern (shape-aligned ring in normal mode, resilient in forced-colors):
381
+
382
+ ```css
383
+ .cem-focusable:focus-visible {
384
+ /* Baseline indicator that survives forced-colors */
385
+ outline: var(--cem-stroke-focus, 2px) solid transparent;
386
+ outline-offset: var(--cem-stroke-indicator-offset, 2px); /* D5 indicator placement */
387
+
388
+ /* Primary ring for normal mode (shape-aligned) */
389
+ box-shadow: 0 0 0 var(--cem-stroke-focus, 2px) currentColor;
390
+
391
+ border-radius: var(--cem-bend-control);
392
+ }
393
+ ```
394
+
395
+
396
+ ### 8.4 Pointer target size and spacing (bend × D2 size × D1 separation)
397
+
398
+ Round controls can *look* smaller even when they meet minimum targets. Ensure:
399
+
400
+ - D2 control height/width targets are met (especially icon buttons and small chips) — see [`cem-coupling.md`](./cem-coupling.md)
401
+ - D1 spacing provides separation between adjacent targets — see [`cem-dimension.md`](./cem-dimension.md)
402
+
403
+ ### 8.5 Bend vs inset readability (bend × D1 padding)
404
+
405
+ High bend on compact surfaces increases corner curvature and can visually crowd content. When bend increases, step D1 inset
406
+ up rather than pushing content into the curve.
407
+
408
+ ### 8.6 Minimum test checklist
409
+
410
+ Validate under:
411
+
412
+ - keyboard navigation with `:focus-visible`
413
+ - forced-colors / high-contrast modes
414
+ - zoom 200–400% and text scaling (no clipping; adequate spacing)
415
+ - dense vs normal modes (D2 height changes keep round-ends correct)
416
+ - small-target components (icon buttons, chips) for hit area and separation
417
+
418
+ ---
419
+
420
+ ## 9. Consumer vocabulary for "round ends" (capsules)
421
+
422
+ Recommended consumer-perspective terms (descending literalness):
423
+
424
+ - **round-ends**
425
+ - **capsule**
426
+ - **pill**
427
+ - **bubble button** (marketing-leaning)
428
+ - **stadium** (designer-leaning)
429
+
430
+ **Canonical endpoint name in this spec:** `--cem-bend-control-round-ends`
431
+
432
+ If you want an alias, make it a pointer:
433
+
434
+ ```css
435
+ --cem-bend-control-capsule: var(--cem-bend-control-round-ends);
436
+ ```
437
+
438
+ ---
439
+
440
+ ## 10. Component mapping
441
+
442
+ This section provides a practical "where to bind bend" reference. It is intentionally **role-first** and maps components to
443
+ existing CEM endpoints. If a component needs an internal override, implement it as a **local alias** (component scope),
444
+ not as new global tokens.
445
+
446
+ ### 10.1 Action binding (existing)
447
+
448
+ The existing implementation binds actions to the bend system:
449
+
450
+ ```css
451
+ .action, button {
452
+ --cem-action-border-radius: var(--cem-bend);
453
+ border-radius: var(--cem-action-border-radius);
454
+ }
455
+ ```
456
+
457
+ ### 10.2 Extended component mapping
458
+
459
+ The mapping below is consistent with common practices across modern systems:
460
+
461
+ - Material 3 applies the corner radius scale broadly to rectangular components (e.g., cards, dialogs, menus) and uses larger
462
+ radii for prominent overlays (dialogs are specified with 28dp container corners).
463
+ - Fluent groups shape usage into rectangular elements, flyout elements (popovers), and pill/round elements (personas), and
464
+ recommends "none" for structural bars.
465
+ - Radix Themes treats radius as a theme-level property inherited by panels like Card/Dialog/Popover.
466
+ - Polaris documents concrete radii for cards (e.g., default 8px).
467
+ - Carbon specifies radii for certain control families (e.g., content switcher corners).
468
+
469
+ **Table: map components to CEM endpoints**
470
+
471
+ | Component family | Recommended token / basis | Rationale (consumer + system) |
472
+ |--------------------------------------|--------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
473
+ | **Buttons** | `--cem-bend-control` | Standard interactive affordance (default feel) |
474
+ | **Icon buttons (circular variants)** | Local alias → `border-radius: var(--cem-bend-circle)` | Icon buttons often present as circles; use basis circle via local alias (do not mint a global "icon radius") |
475
+ | **FAB** | Circle variant → `--cem-bend-circle`; Extended FAB → `--cem-bend-control-round-ends` | Prominent control; circular (classic FAB) or capsule (extended FAB) |
476
+ | **Chips / Tags** | `--cem-bend-control-round-ends` | "Capsule" shape signals lightweight, removable, filter-like affordance |
477
+ | **Badges / Counters** | `--cem-bend-smooth` (or `--cem-bend-control`) | Small rounding prevents harsh micro-shapes; keep subtle |
478
+ | **Text fields / Select** | `--cem-bend-field` | Field geometry should match the product's primary control feel |
479
+ | **Switches / Toggles** | Track: `--cem-bend-round`; Thumb: `--cem-bend-circle` | Track is a pill; thumb is a circle (distinct affordance) |
480
+ | **Cards / Panels** | `--cem-bend-surface` | Container grouping and boundaries |
481
+ | **Tables / Dense list rows** | `--cem-bend-sharp` (or none) | Grid-aligned surfaces should remain formal/structural; avoid decorative rounding |
482
+ | **Dialogs / Sheets** | `--cem-bend-modal` (+ attachment pattern for sheets) | High salience overlays; larger bend supports "layered" reading and separation |
483
+ | **Menus / Dropdowns / Popovers** | `--cem-bend-overlay` | Transient overlays; match default bend feel |
484
+ | **Tooltips** | `--cem-bend-overlay` | Small transient overlay; keep consistent with menus |
485
+ | **Snackbars / Toasts** | `--cem-bend-overlay` (policy may choose sharper) | Notification surfaces should not demand attention via shape alone |
486
+ | **Navigation rail / App bar** | `--cem-bend-sharp` | Structural navigation regions read more stable with sharp edges |
487
+ | **Tabs** | Underline tabs: `--cem-bend-sharp`; Pill tabs: `--cem-bend-control-round-ends` | Keep minimal unless the design intentionally uses pill tabs |
488
+ | **Avatars / Personas** | `--cem-bend-avatar` (`50%`) | Circular identity affordance |
489
+ | **Media thumbnails** | `--cem-bend-media` | Gentle rounding to match overall feel without obscuring content edges |
490
+
491
+ ### 10.3 Local alias pattern (preferred for variants)
492
+
493
+ ```css
494
+ .cem-icon-button {
495
+ /* local alias: do not mint a global "icon radius" */
496
+ border-radius: var(--cem-bend-circle);
497
+ }
498
+
499
+ .cem-chip {
500
+ border-radius: var(--cem-bend-control-round-ends);
501
+ }
502
+ ```
503
+
504
+ ---
505
+
506
+ ## 11. Notes on external systems (adapter-only)
507
+
508
+ Many systems use a **bounded corner scale** and recommend applying it by role:
509
+
510
+ - Material 3: "corner radius scale" across rectangular components; larger corners on prominent overlays.
511
+ - Fluent 2: "None…Circle" tokens and guidance by component area (structural bars vs flyouts vs personas).
512
+ - Radix Themes: theme-level radius inherited by panel-like components.
513
+ - Polaris and Carbon: documented radii for common container/control families.
514
+
515
+ CEM consumes these patterns at the adapter layer but keeps product code consumer-semantic.
516
+
517
+ ---
518
+
519
+ ## 12. Quick adoption checklist
520
+
521
+ Use this checklist to adopt the bend system with minimal churn and predictable outcomes.
522
+
523
+ 1. **Confirm prerequisites (D1 + D2 are present)**
524
+ - D1 provides the physical scale used by bend (`--cem-dim-xx-small`, `--cem-dim-x-small`, `--cem-dim-small`, etc.) — see [`cem-dimension.md`](./cem-dimension.md).
525
+ - D2 provides height for geometry-driven bend (`--cem-control-height`), so round-ends remain correct across density/size modes — see [`cem-coupling.md`](./cem-coupling.md).
526
+
527
+ 2. **Adopt the bend basis (`--cem-bend-*`)**
528
+ - Keep the basis small: `sharp`, `smooth`, `round` (endcaps), `circle`, and the active `--cem-bend`.
529
+ - Decide product policy for "capsule controls" (where `--cem-bend-round` is used): occasional variant vs product-wide style.
530
+
531
+ 3. **Map semantic endpoints to the basis (role-first)**
532
+ - Set `--cem-bend-control`, `--cem-bend-surface`, `--cem-bend-overlay`, and the minimal specializations already defined in this spec.
533
+ - Avoid mapping components directly to "scale aliases" (`xs/sm/md/...`) in product code. Those are adapter-only.
534
+
535
+ 4. **Bind components to semantic endpoints (no raw values)**
536
+ - Bind `border-radius` to endpoints (e.g., `--cem-bend-control`, `--cem-bend-surface`) or to basis geometry tokens (`--cem-bend-round`, `--cem-bend-circle`) via **local aliases** for variants.
537
+ - For asymmetric corners (groups/attachments), use the patterns in this spec and prefer **logical corner properties** to remain RTL-safe.
538
+
539
+ 5. **If needed, introduce a shape mode knob (`sharp | smooth | round`)**
540
+ - Add `data-cem-shape="..."` only if brand expression requires it.
541
+ - Modes should override **only** `--cem-bend` and/or semantic endpoints (never introduce mode-specific component tokens).
542
+
543
+ 6. **Validate in accessibility and "hard mode" rendering**
544
+ - **Focus ring follows target shape** and is not clipped (avoid `overflow: hidden` trapping focus; validate `outline-offset` / ring space).
545
+ - **Forced-colors / high-contrast**: affordances remain clear when shadows/fills are overridden; outline-based focus remains visible.
546
+ - **Grouped controls**: only outer corners rounded; inner corners sharp; RTL behavior correct.
547
+ - **Overlays** (tooltips/menus/popovers) are consistent with `--cem-bend-overlay`; **modals** use `--cem-bend-modal` (M3 dialogs are typically 28dp).
548
+ - **Chips and badges** maintain pill/circular intent across density modes (round ends use ½-height rule).
549
+ - **Target size & spacing** remain compliant when shapes look visually smaller (particularly icon buttons and chips). Coordinate with D2 sizing and D1 separation.
550
+ - **Focus not obscured** by sticky headers/overlays during keyboard navigation.
551
+
552
+ 7. **Lock in governance**
553
+ - Add a code convention (or lint rule) that forbids raw `border-radius` values in components except inside adapter layers.
554
+ - Document which endpoints are allowed for each component family (use the Component mapping table as the baseline).
555
+
556
+ ---
557
+
558
+ ## 13. Governance and versioning
559
+
560
+ This spec is intended to be adopted as a **stable contract** between design, engineering, and component libraries. Treat
561
+ changes using **semantic versioning** (MAJOR.MINOR.PATCH) with explicit deprecation when feasible.
562
+
563
+ ### 13.1 What counts as breaking (MAJOR)
564
+
565
+ Treat as major (breaking) if you:
566
+
567
+ - Rename or remove any **canonical** bend basis token (`--cem-bend-*`) or any **canonical semantic endpoint**.
568
+ - Change the **semantic meaning** of an endpoint (e.g., what "overlay" covers; whether "round" means endcaps vs fixed value).
569
+ - Change the **geometry definition** of round-ends (`½ height`) or circle (`50%`) in a way that alters component behavior.
570
+ - Change mode names, add/remove supported modes, or change the meaning of an existing mode selector
571
+ (e.g., `data-cem-shape="sharp|smooth|round"`).
572
+
573
+ **Business rationale:** these changes can silently alter UI boundaries, focus geometry, and density-mode behavior across many
574
+ components at once.
575
+
576
+ ### 13.2 What is non-breaking (MINOR / PATCH)
577
+
578
+ Treat as minor/patch if you:
579
+
580
+ - Adjust underlying numeric values (via D1 tokens) while preserving semantics and perceptual intent.
581
+ - Add new semantic endpoints that are **optional**, clearly scoped, and do not change existing endpoint meaning.
582
+ - Add mapping guidance, adapter notes, examples, or clarify documentation.
583
+ - Expand component mapping tables without changing existing bindings.
584
+
585
+ ### 13.3 Deprecation policy (recommended)
586
+
587
+ - When replacing an endpoint, keep the old name as an **alias** for at least one minor release cycle.
588
+ - Provide a migration note: "old → new," and a rationale tied to consumer semantics and accessibility.
589
+
590
+ ### 13.4 Canonical token summary (contract surface)
591
+
592
+ The table below distinguishes **required CEM contract tokens** from **optional adapter aliases**.
593
+
594
+ | Token | Category | Required | Notes |
595
+ |---------------------------------|-----------------------------|:--------------:|-------------------------------------------------------|
596
+ | `--cem-bend-sharp` | Bend basis | Yes | No bend (sharp corners) |
597
+ | `--cem-bend-smooth` | Bend basis | Yes | Small bend; binds to D1 `--cem-dim-x-small` |
598
+ | `--cem-bend-round` | Bend basis (geometry) | Yes | Round-ends (capsule): `½ height` |
599
+ | `--cem-bend-circle` | Bend basis (geometry) | Yes | Circle: `50%` |
600
+ | `--cem-bend` | Active alias | Yes | Mode-switchable default bend |
601
+ | `--cem-bend-control` | Semantic endpoint | Yes | Primary control bend |
602
+ | `--cem-bend-surface` | Semantic endpoint | Yes | Primary container/surface bend |
603
+ | `--cem-bend-overlay` | Semantic endpoint | Yes | Small overlays (menus/tooltips/popovers) |
604
+ | `--cem-bend-field` | Semantic endpoint | Recommended | Usually equals control bend |
605
+ | `--cem-bend-modal` | Semantic endpoint | Recommended | Prominent overlays (dialogs/sheets) |
606
+ | `--cem-bend-control-round-ends` | Semantic endpoint (variant) | Optional | Use only if capsules are a consistent product pattern |
607
+ | `--cem-bend-media` | Semantic endpoint | Recommended | Media thumbnails/previews |
608
+ | `--cem-bend-avatar` | Semantic endpoint | Recommended | Avatar/persona geometry (circle) |
609
+ | `--cem-bend-attached-edge` | Pattern token | Recommended | For asymmetric attachment patterns |
610
+ | `--cem-bend-free-edge` | Pattern token | Recommended | For asymmetric attachment patterns |
611
+ | `--cem-action-border-radius` | Component binding | Yes (existing) | Existing action binding contract |
612
+
613
+ **Adapter-only (optional) aliases**
614
+
615
+ The following "M3-parity" aliases may be exposed for compatibility, but must not be required by product component code:
616
+
617
+ - `--cem-bend-none`, `--cem-bend-xs`, `--cem-bend-sm`, `--cem-bend-md`, `--cem-bend-lg`, `--cem-bend-xl`, `--cem-bend-full`
618
+
619
+ If these aliases exist, treat them as adapter surface: renames/removals are breaking for adapter consumers, but should not
620
+ affect product components if semantic endpoints are followed.
621
+
622
+ ---
623
+
624
+ ## Appendix A — Material 3 shape scale reference (adapter mapping)
625
+
626
+ This appendix is **non-normative**: it exists to help adapters map Material 3 shape scales into the CEM bend basis and
627
+ semantic endpoints.
628
+
629
+ Material Design 3 defines a corner-radius scale with canonical steps (0/4/8/12/16/28 + "full"), and also introduces
630
+ additional "increased" steps for larger containers in newer guidance.
631
+
632
+ ### A.1 Canonical M3 `--md-sys-shape-corner-*` steps → CEM
633
+
634
+ | M3 token | Typical value | CEM mapping (adapter-only) | Prefer applying via CEM endpoints | Perceived quality |
635
+ |-------------------------------------|----------------|------------------------------------------------------------------|------------------------------------------------------|--------------------------|
636
+ | `--md-sys-shape-corner-none` | 0 | `--cem-bend-sharp` | attached edges, structural bars (`--cem-bend-sharp`) | Sharp, formal, technical |
637
+ | `--md-sys-shape-corner-extra-small` | 4dp | `var(--cem-dim-xx-small)` | rare micro-bend (badges, subtle containers) | Barely rounded, subtle |
638
+ | `--md-sys-shape-corner-small` | 8dp | `--cem-bend-smooth` | `--cem-bend-control`, `--cem-bend-overlay` | Slightly soft |
639
+ | `--md-sys-shape-corner-medium` | 12dp | `var(--cem-dim-small)` | `--cem-bend-surface` | Balanced friendliness |
640
+ | `--md-sys-shape-corner-large` | 16dp | `var(--cem-dim-medium)` | `--cem-bend-surface-strong` (if you expose it) | Noticeably rounded |
641
+ | `--md-sys-shape-corner-extra-large` | 28dp | `--cem-bend-modal` | `--cem-bend-modal` | Very soft, approachable |
642
+ | `--md-sys-shape-corner-full` | pill / 50% | `--cem-bend-round` (capsule) and/or `--cem-bend-circle` (circle) | chips, capsule controls, avatars | Playful, highly rounded |
643
+
644
+ ### A.2 Optional M3-parity aliases (adapter-only)
645
+
646
+ If you want to expose M3-like short aliases for compatibility, define them as **aliases** to CEM basis and D1 tokens.
647
+ These are **not** intended for product component code.
648
+
649
+ ```css
650
+ :root {
651
+ --cem-bend-none: var(--cem-bend-sharp);
652
+ --cem-bend-xs: var(--cem-dim-xx-small); /* ~4dp */
653
+ --cem-bend-sm: var(--cem-dim-x-small); /* ~8dp */
654
+ --cem-bend-md: var(--cem-dim-small); /* ~12dp */
655
+ --cem-bend-lg: var(--cem-dim-medium); /* ~16dp */
656
+ --cem-bend-xl: var(--cem-bend-modal); /* ~28dp */
657
+
658
+ /* "full" depends on geometry: capsule vs circle */
659
+ --cem-bend-full: var(--cem-bend-round);
660
+ }
661
+ ```
662
+
663
+ ### A.3 Notes on validation vs "current" libraries
664
+
665
+ - Material Web uses `--md-sys-shape-corner-*` tokens in theming and leaves exact numeric assignments to the system theme.
666
+ - Angular Material may publish/ship a scale whose *numeric* values differ from the M3 "typical" table; treat Angular's
667
+ scale as its **own source scale** and map to CEM by intent, not by exact dp numbers.
668
+ - CEM's contract is semantic endpoints. Adapters own external token mapping.
669
+
670
+ ---
671
+
672
+ ## References
673
+
674
+ **Primary sources**
675
+ - [Material Design 3: Shape (shape scale tokens)](https://m3.material.io/styles/shape/shape-scale-tokens)
676
+ - [Material Design 3: Corner radius scale](https://m3.material.io/styles/shape/corner-radius-scale)
677
+ - [Material Web: Theming](https://material-web.dev/theming/material-theming/)
678
+ - [Angular Material: Design Tokens](https://deepwiki.com/angular/components/5.2-material-design-tokens)
679
+ - [Google Developers: Building the Shape System](https://developers.googleblog.com/building-the-shape-system-for-material-design/)
680
+
681
+ **Additional ecosystem references (non-normative)**
682
+ - [Fluent 2: Shapes](https://fluent2.microsoft.design/shapes)
683
+ - [Radix Themes: Radius](https://www.radix-ui.com/themes/docs/theme/radius)
684
+ - [Shopify Polaris: Card](https://polaris-react.shopify.com/components/layout-and-structure/card)
685
+ - [Carbon: Content switcher style](https://carbondesignsystem.com/components/content-switcher/style/)
686
+
687
+ **Local CEM documentation**
688
+ - [D1. Space & Rhythm](./cem-dimension.md) — dimension scale tokens
689
+ - [D2. Coupling & Compactness](./cem-coupling.md) — control height and operability
690
+ - [D6. Typography](./cem-voice-fonts-typography.md) — voice and typography tokens
691
+ - [D7. Time & Motion](./cem-timing.md) — timing and easing tokens