@repobit/dex-system-design 0.25.12 → 0.26.0

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 (336) hide show
  1. package/CHANGELOG.md +187 -0
  2. package/README.md +131 -8
  3. package/package.json +95 -13
  4. package/schemas/component-manifest.json +3294 -405
  5. package/schemas/manifest-omissions.json +173 -0
  6. package/src/blog/src/breakpoints.js +6 -6
  7. package/src/blog/src/content/blog-atoms-showcase.js +1 -1
  8. package/src/blog/src/content/blog-page-layout.js +2 -2
  9. package/src/blog/src/lib/article-toc.js +7 -7
  10. package/src/blog/src/shell/blog-shell.js +1 -1
  11. package/src/blog/src/tokens/blog.js +2 -2
  12. package/src/blog/src/tokens/core.js +34 -35
  13. package/src/blog/src/tokens/legacy.js +0 -9
  14. package/src/blog/tokens/blog.js +2 -2
  15. package/src/blog/tokens/core.js +34 -35
  16. package/src/blog/tokens/legacy.js +0 -9
  17. package/src/blog/tokens.css +36 -46
  18. package/src/components/accordion/accordion-bg.css.js +83 -59
  19. package/src/components/accordion/accordion-bg.js +29 -10
  20. package/src/components/accordion/accordion-bg.stories.js +67 -67
  21. package/src/components/accordion/accordion-keyboard.js +80 -0
  22. package/src/components/accordion/accordion.css.js +142 -80
  23. package/src/components/accordion/accordion.js +37 -10
  24. package/src/components/accordion/accordion.stories.js +7 -7
  25. package/src/components/agent-endpoints/agent-endpoints.css.js +36 -39
  26. package/src/components/agent-endpoints/agent-endpoints.js +30 -20
  27. package/src/components/agent-endpoints/agent-endpoints.stories.js +1 -1
  28. package/src/components/ai-guardian-demo.stories.js +91 -91
  29. package/src/components/alert/alert.css.js +198 -0
  30. package/src/components/alert/alert.js +103 -0
  31. package/src/components/alert/alert.stories.js +206 -0
  32. package/src/components/anchor/anchor-nav.css.js +213 -101
  33. package/src/components/anchor/anchor-nav.js +26 -40
  34. package/src/components/anchor/anchor.stories.js +22 -12
  35. package/src/components/annotation/annotation.css.js +58 -0
  36. package/src/components/annotation/annotation.js +67 -0
  37. package/src/components/annotation/annotation.stories.js +63 -0
  38. package/src/components/architecture.stories.js +285 -0
  39. package/src/components/atoms.stories.js +342 -0
  40. package/src/components/avatar/avatar.css.js +67 -0
  41. package/src/components/avatar/avatar.js +42 -0
  42. package/src/components/avatar/avatar.stories.js +95 -0
  43. package/src/components/awards/awards-flex.css.js +209 -23
  44. package/src/components/awards/awards-flex.js +66 -7
  45. package/src/components/awards/awards-flex.stories.js +1 -1
  46. package/src/components/awards/{awards-light.stories.js → awards-summary.stories.js} +54 -64
  47. package/src/components/awards/awards.css.js +116 -58
  48. package/src/components/awards/awards.js +102 -28
  49. package/src/components/awards/awards.stories.js +1 -1
  50. package/src/components/back/back.css.js +51 -22
  51. package/src/components/back/back.js +28 -7
  52. package/src/components/back/back.stories.js +9 -3
  53. package/src/components/badge/badge.css.js +158 -46
  54. package/src/components/badge/badge.js +62 -74
  55. package/src/components/badge/badge.stories.js +176 -248
  56. package/src/components/bento-grid/bento-grid.css.js +21 -16
  57. package/src/components/bento-grid/bento-grid.js +16 -4
  58. package/src/components/bento-grid/bento-grid.stories.js +19 -18
  59. package/src/components/bento-grid/bento-item.css.js +52 -28
  60. package/src/components/bento-grid/bento-item.js +2 -2
  61. package/src/components/blockquote/blockquote.css.js +47 -0
  62. package/src/components/blockquote/blockquote.js +29 -0
  63. package/src/components/blockquote/blockquote.stories.js +62 -0
  64. package/src/components/breadcrumb/breadcrumb.css.js +92 -22
  65. package/src/components/breadcrumb/breadcrumb.js +56 -11
  66. package/src/components/button/button.css.js +531 -161
  67. package/src/components/button/button.js +206 -214
  68. package/src/components/button/button.stories.js +322 -174
  69. package/src/components/caption/caption.css.js +21 -0
  70. package/src/components/caption/caption.js +31 -0
  71. package/src/components/caption/caption.stories.js +62 -0
  72. package/src/components/card-features/card-features.css.js +14 -22
  73. package/src/components/card-features/card-features.js +68 -9
  74. package/src/components/card-features/card-features.stories.js +11 -11
  75. package/src/components/cards/card.css.js +60 -81
  76. package/src/components/cards/card.js +56 -25
  77. package/src/components/cards/card.stories.js +39 -39
  78. package/src/components/carousel/carousel.css.js +93 -99
  79. package/src/components/carousel/carousel.js +32 -4
  80. package/src/components/checkbox/checkbox.css.js +111 -93
  81. package/src/components/checkbox/checkbox.js +64 -90
  82. package/src/components/checkbox/checkbox.stories.js +96 -29
  83. package/src/components/code/code.css.js +70 -0
  84. package/src/components/code/code.js +40 -0
  85. package/src/components/code/code.stories.js +73 -0
  86. package/src/components/compare/compare.css.js +179 -43
  87. package/src/components/compare/compare.js +52 -25
  88. package/src/components/compare/compare.stories.js +61 -4
  89. package/src/components/comparison-panel/comparison-panel.css.js +38 -51
  90. package/src/components/comparison-panel/comparison-panel.js +5 -4
  91. package/src/components/comparison-panel/comparison-panel.stories.js +1 -1
  92. package/src/components/compatibility-table/compatibility-table.css.js +180 -80
  93. package/src/components/compatibility-table/compatibility-table.js +37 -9
  94. package/src/components/control-alignment.stories.js +393 -0
  95. package/src/components/cta-banner/cta-banner.css.js +41 -13
  96. package/src/components/cta-banner/cta-banner.js +6 -5
  97. package/src/components/cta-banner/cta-banner.stories.js +43 -98
  98. package/src/components/display/display.css.js +25 -1
  99. package/src/components/display/display.js +46 -13
  100. package/src/components/display/display.stories.js +270 -40
  101. package/src/components/divider/divider-horizontal.js +21 -5
  102. package/src/components/divider/divider-vertical.js +15 -7
  103. package/src/components/divider/divider.css.js +2 -2
  104. package/src/components/divider/divider.stories.js +38 -34
  105. package/src/components/dropdown/dropdown.css.js +93 -126
  106. package/src/components/dropdown/dropdown.js +114 -34
  107. package/src/components/dropdown/dropdown.stories.js +56 -24
  108. package/src/components/features/features.css.js +24 -11
  109. package/src/components/features/features.js +7 -3
  110. package/src/components/features/features.stories.js +37 -37
  111. package/src/components/features-tab/features-tab.css.js +19 -8
  112. package/src/components/features-tab/features-tab.js +6 -5
  113. package/src/components/features-tab/features-tab.stories.js +23 -23
  114. package/src/components/fieldset/fieldset.css.js +30 -0
  115. package/src/components/fieldset/fieldset.js +28 -0
  116. package/src/components/fieldset/fieldset.stories.js +84 -0
  117. package/src/components/footer/footer-links-group.css.js +10 -14
  118. package/src/components/footer/footer-links-group.js +4 -3
  119. package/src/components/footer/footer-lp.css.js +59 -30
  120. package/src/components/footer/footer-lp.js +17 -12
  121. package/src/components/footer/footer-lp.stories.js +63 -75
  122. package/src/components/footer/footer-nav-menu.css.js +26 -4
  123. package/src/components/footer/footer-nav-menu.js +3 -2
  124. package/src/components/footer/footer.css.js +146 -264
  125. package/src/components/footer/footer.js +176 -106
  126. package/src/components/footer/footer.stories.js +9 -9
  127. package/src/components/footer/localeMap.js +1 -1
  128. package/src/components/grid/grid.css.js +1 -1
  129. package/src/components/grid/grid.js +49 -7
  130. package/src/components/grid/grid.stories.js +111 -0
  131. package/src/components/header/header-code.css.js +61 -51
  132. package/src/components/header/header-code.js +28 -14
  133. package/src/components/header/header-code.stories.js +5 -5
  134. package/src/components/header/header.css.js +655 -176
  135. package/src/components/header/header.js +269 -36
  136. package/src/components/header/header.stories.js +841 -18
  137. package/src/components/heading/heading.css.js +14 -17
  138. package/src/components/heading/heading.js +48 -33
  139. package/src/components/heading/heading.stories.js +27 -25
  140. package/src/components/help-text/help-text.css.js +21 -0
  141. package/src/components/help-text/help-text.js +25 -0
  142. package/src/components/help-text/help-text.stories.js +66 -0
  143. package/src/components/highlight/highlight.css.js +86 -64
  144. package/src/components/highlight/highlight.js +18 -27
  145. package/src/components/highlight/highlight.stories.js +14 -3
  146. package/src/components/icons/analysis-icon.js +6 -16
  147. package/src/components/icons/arrow-down-icon.js +6 -19
  148. package/src/components/icons/arrow-icon.js +44 -0
  149. package/src/components/icons/arrow-right-icon.js +30 -23
  150. package/src/components/icons/arrow-up-icon.js +19 -18
  151. package/src/components/icons/bd-ai-icon.js +1 -1
  152. package/src/components/icons/brand-marks.stories.js +279 -0
  153. package/src/components/icons/brand-signature-icon.js +42 -0
  154. package/src/components/icons/check-icon.js +27 -0
  155. package/src/components/icons/circle-info-icon.js +33 -0
  156. package/src/components/icons/close-icon.js +6 -18
  157. package/src/components/icons/family-icon.js +8 -20
  158. package/src/components/icons/globe-icon.js +6 -18
  159. package/src/components/icons/guide-icon.js +6 -18
  160. package/src/components/icons/icon-element.js +99 -0
  161. package/src/components/icons/icons.js +36 -0
  162. package/src/components/icons/icons.stories.js +184 -52
  163. package/src/components/icons/individual-icon.js +6 -18
  164. package/src/components/icons/laurel-icon.js +9 -19
  165. package/src/components/icons/machine-learning-icon.js +6 -17
  166. package/src/components/icons/marks.js +41 -0
  167. package/src/components/icons/minus-icon.js +7 -21
  168. package/src/components/icons/missing-icon.js +52 -0
  169. package/src/components/icons/plus-icon.js +7 -21
  170. package/src/components/icons/quote-icon.js +19 -19
  171. package/src/components/image/image.css.js +72 -25
  172. package/src/components/image/image.js +11 -6
  173. package/src/components/image/image.stories.js +2 -2
  174. package/src/components/input/custom-form.stories.js +214 -62
  175. package/src/components/input/input-clipboard.css.js +51 -144
  176. package/src/components/input/input-clipboard.js +31 -15
  177. package/src/components/input/input.css.js +8 -146
  178. package/src/components/input/input.js +93 -38
  179. package/src/components/install-options/install-options.css.js +84 -77
  180. package/src/components/install-options/install-options.js +33 -30
  181. package/src/components/install-options/install-options.stories.js +3 -3
  182. package/src/components/label/label.css.js +35 -0
  183. package/src/components/label/label.js +38 -0
  184. package/src/components/label/label.stories.js +82 -0
  185. package/src/components/light-carousel/light-carousel.css.js +111 -63
  186. package/src/components/light-carousel/light-carousel.js +85 -11
  187. package/src/components/light-carousel/light-carousel.stories.js +126 -82
  188. package/src/components/link/link.css.js +150 -99
  189. package/src/components/link/link.js +86 -11
  190. package/src/components/link/link.stories.js +124 -30
  191. package/src/components/list/list-item/list-item.css.js +74 -22
  192. package/src/components/list/list-item/list-item.js +32 -10
  193. package/src/components/list/list-item/list-item.stories.js +23 -23
  194. package/src/components/list/list.css.js +8 -2
  195. package/src/components/list/list.js +3 -2
  196. package/src/components/list/list.stories.js +222 -0
  197. package/src/components/modal/modal.css.js +114 -24
  198. package/src/components/modal/modal.js +83 -7
  199. package/src/components/modal/modal.stories.js +9 -9
  200. package/src/components/overview/overview.css.js +19 -14
  201. package/src/components/overview/overview.js +6 -5
  202. package/src/components/overview/overview.stories.js +10 -10
  203. package/src/components/page-switcher/page-switcher.css.js +97 -40
  204. package/src/components/page-switcher/page-switcher.js +28 -5
  205. package/src/components/page-switcher/page-switcher.stories.js +95 -0
  206. package/src/components/paragraph/paragraph.css.js +15 -10
  207. package/src/components/paragraph/paragraph.js +41 -44
  208. package/src/components/paragraph/paragraph.stories.js +56 -21
  209. package/src/components/picture/picture.css.js +103 -44
  210. package/src/components/picture/picture.js +100 -30
  211. package/src/components/picture/picture.stories.js +1 -1
  212. package/src/components/pricing-cards/new-pricing-card.js +3 -3
  213. package/src/components/pricing-cards/new-pricing.css.js +24 -15
  214. package/src/components/pricing-cards/pricing-card-actions.css.js +1 -1
  215. package/src/components/pricing-cards/pricing-card-actions.js +3 -4
  216. package/src/components/pricing-cards/pricing-card-container.css.js +3 -3
  217. package/src/components/pricing-cards/pricing-card-container.js +3 -2
  218. package/src/components/pricing-cards/pricing-card-header.css.js +10 -8
  219. package/src/components/pricing-cards/pricing-card-header.js +6 -7
  220. package/src/components/pricing-cards/pricing-card-pricing.css.js +16 -9
  221. package/src/components/pricing-cards/pricing-card-pricing.js +8 -6
  222. package/src/components/pricing-cards/pricing-card-show-more.css.js +11 -3
  223. package/src/components/pricing-cards/pricing-card-show-more.js +8 -3
  224. package/src/components/pricing-cards/pricing-card.css.js +244 -190
  225. package/src/components/pricing-cards/pricing-card.js +54 -70
  226. package/src/components/pricing-cards/pricing-feature-item.css.js +25 -8
  227. package/src/components/pricing-cards/pricing-feature-item.js +8 -3
  228. package/src/components/process-steps/process-steps.css.js +26 -14
  229. package/src/components/process-steps/process-steps.js +23 -6
  230. package/src/components/process-steps/process-steps.stories.js +1 -1
  231. package/src/components/progress/progress.css.js +80 -0
  232. package/src/components/progress/progress.js +42 -0
  233. package/src/components/progress/progress.stories.js +79 -0
  234. package/src/components/quick-answer/quick-answer.css.js +75 -13
  235. package/src/components/quick-answer/quick-answer.js +8 -3
  236. package/src/components/radio/radio.css.js +92 -128
  237. package/src/components/radio/radio.js +106 -127
  238. package/src/components/radio/radio.stories.js +54 -19
  239. package/src/components/review/review-grid.css.js +5 -6
  240. package/src/components/review/review-grid.js +14 -11
  241. package/src/components/review/review.css.js +11 -6
  242. package/src/components/review/review.js +3 -8
  243. package/src/components/shared/ensemble.css.js +93 -0
  244. package/src/components/shared/form-field.css.js +206 -0
  245. package/src/components/shared/prop-vocabulary.js +48 -0
  246. package/src/components/shared/token-scales.js +306 -0
  247. package/src/components/skeleton/skeleton.css.js +34 -0
  248. package/src/components/skeleton/skeleton.js +32 -0
  249. package/src/components/skeleton/skeleton.stories.js +70 -0
  250. package/src/components/spinner/spinner.css.js +62 -0
  251. package/src/components/spinner/spinner.js +38 -0
  252. package/src/components/spinner/spinner.stories.js +92 -0
  253. package/src/components/spotlight-section/spotlight-section.css.js +14 -13
  254. package/src/components/spotlight-section/spotlight-section.js +42 -39
  255. package/src/components/switch/switch.css.js +103 -0
  256. package/src/components/switch/switch.js +44 -0
  257. package/src/components/switch/switch.stories.js +86 -0
  258. package/src/components/tab-list/content-switcher.stories.js +189 -0
  259. package/src/components/tab-list/tab-list.css.js +250 -0
  260. package/src/components/tab-list/tab-list.js +184 -0
  261. package/src/components/tab-list/tab-list.stories.js +221 -0
  262. package/src/components/tabs/tabs.css.js +14 -123
  263. package/src/components/tabs/tabs.js +16 -19
  264. package/src/components/tabs/tabs.stories.js +95 -95
  265. package/src/components/tag/tag.css.js +54 -0
  266. package/src/components/tag/tag.js +32 -0
  267. package/src/components/tag/tag.stories.js +126 -0
  268. package/src/components/terminal/terminal-message.css.js +164 -60
  269. package/src/components/terminal/terminal-message.js +5 -5
  270. package/src/components/terminal/terminal-message.stories.js +70 -1
  271. package/src/components/termsOfUse/terms.css.js +25 -20
  272. package/src/components/termsOfUse/terms.js +13 -9
  273. package/src/components/termsOfUse/terms.stories.js +1 -1
  274. package/src/components/textarea/textarea.css.js +51 -0
  275. package/src/components/textarea/textarea.js +136 -0
  276. package/src/components/textarea/textarea.stories.js +191 -0
  277. package/src/components/tooltip/tooltip.css.js +75 -0
  278. package/src/components/tooltip/tooltip.js +156 -0
  279. package/src/components/tooltip/tooltip.stories.js +161 -0
  280. package/src/components/trust-panel/trust-panel.css.js +85 -33
  281. package/src/components/trust-panel/trust-panel.js +18 -10
  282. package/src/components/trust-panel/trust-panel.stories.js +1 -1
  283. package/src/components/ultimate-security-demo.stories.js +431 -0
  284. package/src/components/video/video.css.js +17 -0
  285. package/src/components/video/video.js +40 -0
  286. package/src/components/video/video.stories.js +106 -0
  287. package/src/components/video-player/video-player.css.js +67 -11
  288. package/src/components/video-player/video-player.js +35 -4
  289. package/src/components/video-player/video-player.stories.js +1 -1
  290. package/src/components/visual-alignment.stories.js +411 -0
  291. package/src/components/visually-hidden/visually-hidden.css.js +24 -0
  292. package/src/components/visually-hidden/visually-hidden.js +16 -0
  293. package/src/components/visually-hidden/visually-hidden.stories.js +56 -0
  294. package/src/stories/Button.stories.js +17 -17
  295. package/src/stories/Header.stories.js +10 -10
  296. package/src/stories/Page.js +1 -1
  297. package/src/stories/Page.stories.js +6 -6
  298. package/src/tokens/borders.stories.js +339 -0
  299. package/src/tokens/color-responsibilities.stories.js +227 -0
  300. package/src/tokens/dark-derivation.js +309 -0
  301. package/src/tokens/dark-findings.js +197 -0
  302. package/src/tokens/dark-mode.stories.js +207 -0
  303. package/src/tokens/dimension.stories.js +251 -0
  304. package/src/tokens/elevation.stories.js +143 -0
  305. package/src/tokens/focus.stories.js +276 -0
  306. package/src/tokens/fonts.css +20 -20
  307. package/src/tokens/fonts.stories.js +354 -374
  308. package/src/tokens/layout.css +25 -11
  309. package/src/tokens/motion.stories.js +231 -0
  310. package/src/tokens/shape.stories.js +272 -0
  311. package/src/tokens/spacing-rhythm.stories.js +359 -0
  312. package/src/tokens/spacing.stories.js +208 -703
  313. package/src/tokens/story-chrome.js +503 -0
  314. package/src/tokens/surfaces.stories.js +224 -0
  315. package/src/tokens/text-on-surface.stories.js +164 -0
  316. package/src/tokens/token-map.js +220 -0
  317. package/src/tokens/token-map.stories.js +257 -0
  318. package/src/tokens/token-purposes.js +266 -0
  319. package/src/tokens/tokens-grid.stories.js +388 -900
  320. package/src/tokens/tokens.css +1633 -1045
  321. package/src/tokens/tokens.js +1130 -492
  322. package/src/tokens/tokens.stories.js +137 -47
  323. package/src/tokens/type-ceiling-words.js +299 -0
  324. package/src/tokens/typography.stories.js +1003 -965
  325. package/src/tokens/vertical-rhythm.stories.js +224 -0
  326. package/src/components/awards/awards-icon.js +0 -56
  327. package/src/components/awards/awards-light.js +0 -240
  328. package/src/components/banner/banner.js +0 -60
  329. package/src/components/banner/banner.stories.js +0 -51
  330. package/src/components/button/icons.js +0 -24
  331. package/src/components/input/index.js +0 -0
  332. package/src/components/light-carousel/light-carousel-simple.css.js +0 -183
  333. package/src/components/light-carousel/light-carousel-simple.js +0 -74
  334. package/src/tokens/colors.js +0 -121
  335. package/src/tokens/typography.css.js +0 -207
  336. package/src/tokens/typography.js +0 -0
@@ -1,1048 +1,1636 @@
1
- :root {
2
- /* ================================
3
- CORE TYPOGRAPHY TOKENS
4
- ================================ */
5
-
6
- --typography-fontFamily-sans: "IBM Plex Sans", system-ui, -apple-system,
7
- BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
8
- --typography-fontFamily-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular,
9
- Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
10
-
11
- --typography-fontSize-xxs: 0.6875rem; /* 11px */
12
- --typography-fontSize-xs: 0.75rem; /* 12px */
13
- --typography-fontSize-sm: 0.875rem; /* 14px */
14
- --typography-fontSize-base: 1rem; /* 16px */
15
- --typography-fontSize-lg: 1.125rem; /* 18px */
16
- --typography-fontSize-xl: 1.25rem; /* 20px */
17
- --typography-fontSize-2xl: 1.5rem; /* 24px */
18
- --typography-fontSize-3xl: 2rem; /* 32px */
19
- --typography-fontSize-4xl: 2.25rem; /* 36px */
20
- --typography-fontSize-5xl: 3rem; /* 48px */
21
- --typography-fontSize-6xl: 3.75rem; /* 60px */
22
- --typography-fontSize-7xl: 4.5rem; /* 72px */
23
- --typography-fontSize-8xl: 6rem; /* 96px */
24
- --typography-fontSize-9xl: 8rem; /* 128px */
25
-
26
- --typography-fontWeight-light: 300;
27
- --typography-fontWeight-normal: 400;
28
- --typography-fontWeight-medium: 500;
29
- --typography-fontWeight-semibold: 600;
30
- --typography-fontWeight-bold: 700;
31
- /* Awards section — Orbit Frame 14 (node 1882:9342) */
32
- --layout-awards-section-background: var(--color-blue-50);
33
- --layout-awards-banner-max-width: 37.5rem; /* legacy narrow cap; prefer cluster */
34
- --layout-awards-cluster-max-width: 49.5625rem; /* 793px — trust banner column */
35
- --layout-awards-intro-max-width: 39.4375rem; /* 631px — headline stack */
36
- /* Legacy: narrow lower block from Orbit; prefer --layout-ensemble-content-max for compare-aligned grids */
37
- --layout-awards-content-max-width: 53.0625rem; /* 849px */
38
- --layout-ensemble-inline-padding: var(--spacing-24);
39
-
40
- --typography-lineHeight-none: 1;
41
- --typography-lineHeight-tight: 1.25;
42
- --typography-lineHeight-snug: 1.375;
43
- --typography-lineHeight-normal: 1.5;
44
- --typography-lineHeight-relaxed: 1.625;
45
- --typography-lineHeight-loose: 2;
46
-
47
- --typography-letterSpacing-tighter: -0.05em;
48
- --typography-letterSpacing-tight: -0.025em;
49
- --typography-letterSpacing-normal: 0em;
50
- --typography-letterSpacing-wide: 0.025em;
51
- --typography-letterSpacing-wider: 0.05em;
52
- --typography-letterSpacing-widest: 0.1em;
53
-
54
- /* =====================
55
- COLORS
56
- ====================== */
57
- --color-blue-50: #f0f7ff;
58
- --color-blue-100: #d6e8ff;
59
- --color-blue-200: #9ec8ff;
60
- --color-blue-300: #6babff;
61
- --color-blue-400: #338bff;
62
- --color-blue-500: #006dff;
63
- --color-blue-600: #0059d6;
64
- --color-blue-700: #0045ad;
65
- --color-blue-800: #003385;
66
- --color-blue-900: #00225c;
67
- --color-blue-950: #001947;
68
-
69
- --color-red-50: #fff0f0;
70
- --color-red-100: #ffd6d6;
71
- --color-red-200: #ff9e9e;
72
- --color-red-300: #ff6b6b;
73
- --color-red-400: #ff3333;
74
- --color-red-500: #ff0000;
75
- --color-red-600: #d60000;
76
- --color-red-700: #ad0000;
77
- --color-red-800: #850000;
78
- --color-red-900: #5c0000;
79
- --color-red-950: #470000;
80
-
81
- --color-green-50: #edfdf1;
82
- --color-green-100: #d1fadc;
83
- --color-green-200: #9af4b4;
84
- --color-green-300: #63ee8d;
85
- --color-green-400: #2ce767;
86
- --color-green-500: #15c14f;
87
- --color-green-600: #12a641;
88
- --color-green-700: #0e8532;
89
- --color-green-800: #0b6a26;
90
- --color-green-900: #084a1a;
91
- --color-green-950: #063c14;
92
-
93
- --color-yellow-50: #fffbf0;
94
- --color-yellow-100: #fff5d6;
95
- --color-yellow-200: #ffe89e;
96
- --color-yellow-300: #ffdc6b;
97
- --color-yellow-400: #ffcf33;
98
- --color-yellow-500: #ffc400;
99
- --color-yellow-600: #d6a000;
100
- --color-yellow-700: #ad7f00;
101
- --color-yellow-800: #855f00;
102
- --color-yellow-900: #5c4000;
103
- --color-yellow-950: #473100;
104
-
105
- --color-neutral-0: #ffffff;
106
- --color-neutral-25: #fafafa;
107
- --color-neutral-50: #f1f2f3;
108
- --color-neutral-100: #e1e3e5;
109
- --color-neutral-200: #c5c9ce;
110
- --color-neutral-300: #a6adb4;
111
- --color-neutral-400: #88909b;
112
- --color-neutral-500: #6c7580;
113
- --color-neutral-600: #565e66;
114
- --color-neutral-700: #41474d;
115
- --color-neutral-800: #2c3035;
116
- --color-neutral-900: #151719;
117
- --color-neutral-950: #0c0d0e;
118
- --color-neutral-1000: #000000;
119
-
120
- /* ================================
121
- CORE BORDER TOKENS
122
- ================================ */
123
-
124
- --border-width-0: 0;
125
- --border-width-1: 1px;
126
- --border-width-2: 2px;
127
- --border-width-3: 3px;
128
- --border-width-4: 4px;
129
- --border-width-8: 8px;
130
-
131
- --radius-none: 0;
132
- --radius-sm: 0.25rem; /* 4px */
133
- --radius-md: 0.375rem; /* 6px */
134
- --radius-lg: 0.5rem; /* 8px */
135
- --radius-xl: 0.75rem; /* 12px */
136
- --radius-2xl: 1rem; /* 16px */
137
- --radius-3xl: 1.5rem; /* 24px */
138
- --radius-full: 9999px;
139
- /* ================================
140
- CORE DIMENSION TOKENS
141
- ================================ */
142
-
143
- --dimension-2px: 2px;
144
- --dimension-4px: 4px;
145
- --dimension-8px: 8px;
146
- --dimension-12px: 12px;
147
- --dimension-16px: 16px;
148
- --dimension-20px: 20px;
149
- --dimension-24px: 24px;
150
- --dimension-32px: 32px;
151
- --dimension-34px: 34px;
152
- --dimension-40px: 40px;
153
- --dimension-45px: 45px;
154
- --dimension-48px: 48px;
155
- --dimension-55px: 55px;
156
- --dimension-64px: 64px;
157
-
158
- /* ================================
159
- CORE TRANSITION TOKENS
160
- ================================ */
161
-
162
- --transition-duration-fast: 150ms;
163
- --transition-duration-normal: 200ms;
164
- --transition-duration-slow: 300ms;
165
- --transition-duration-slower: 500ms;
166
-
167
- --transition-easing-linear: linear;
168
- --transition-easing-smooth: ease-in-out;
169
- --transition-easing-ease-in: ease-in;
170
- --transition-easing-ease-out: ease-out;
171
- --transition-easing-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
172
-
173
- /* ================================
174
- CORE SHADOW TOKENS
175
- ================================ */
176
-
177
- --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
178
- --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
179
- --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1),
180
- 0 4px 6px -4px rgb(0 0 0 / 0.1);
181
- --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1),
182
- 0 8px 10px -6px rgb(0 0 0 / 0.1);
183
- --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
184
- --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);
185
-
186
- /* Focus Shadows - Box Shadow Version */
187
- --shadow-focus-outline-blue: 0 0 0 3px rgba(6, 109, 255, 0.15);
188
- --shadow-focus-outline-red: 0 0 0 3px rgba(239, 68, 68, 0.15);
189
- --shadow-focus-outline-green: 0 0 0 3px rgba(34, 197, 94, 0.15);
190
-
191
- /* Focus Outlines - Two-Color System for Universal Visibility */
192
- --focus-outline-primary: 0 0 0 2px var(--color-neutral-0),
193
- 0 0 0 4px var(--color-blue-500);
194
- --focus-outline-secondary: 0 0 0 2px var(--color-neutral-0),
195
- 0 0 0 4px var(--color-neutral-600);
196
- --focus-outline-error: 0 0 0 2px var(--color-neutral-0),
197
- 0 0 0 4px var(--color-red-500);
198
- --focus-outline-success: 0 0 0 2px var(--color-neutral-0),
199
- 0 0 0 4px var(--color-green-500);
200
-
201
- /* Traditional Outline Values for Fallback */
202
- --focus-outline-traditional: 2px solid var(--color-blue-500);
203
- --focus-outline-offset: 2px;
204
-
205
- /* ================================
206
- COMPONENT TOKENS - TYPOGRAPHY
207
- ================================ */
208
-
209
- /* Heading Tokens */
210
- --typography-heading-h1-fontSize: var(--typography-fontSize-5xl);
211
- --typography-heading-h1-fontWeight: var(--typography-fontWeight-bold);
212
- --typography-heading-h1-lineHeight: var(--typography-lineHeight-snug);
213
- --typography-heading-h1-letterSpacing: var(--typography-letterSpacing-normal);
214
- --typography-heading-h1-fontFamily: var(--typography-fontFamily-sans);
215
-
216
- --typography-heading-h2-fontSize: var(--typography-fontSize-4xl);
217
- --typography-heading-h2-fontWeight: var(--typography-fontWeight-bold);
218
- --typography-heading-h2-lineHeight: var(--typography-lineHeight-snug);
219
- --typography-heading-h2-letterSpacing: var(--typography-letterSpacing-normal);
220
- --typography-heading-h2-fontFamily: var(--typography-fontFamily-sans);
221
-
222
- --typography-heading-h3-fontSize: var(--typography-fontSize-3xl);
223
- --typography-heading-h3-fontWeight: var(--typography-fontWeight-semibold);
224
- --typography-heading-h3-lineHeight: var(--typography-lineHeight-snug);
225
- --typography-heading-h3-letterSpacing: var(--typography-letterSpacing-normal);
226
- --typography-heading-h3-fontFamily: var(--typography-fontFamily-sans);
227
-
228
- --typography-heading-h4-fontSize: var(--typography-fontSize-2xl);
229
- --typography-heading-h4-fontWeight: var(--typography-fontWeight-semibold);
230
- --typography-heading-h4-lineHeight: var(--typography-lineHeight-snug);
231
- --typography-heading-h4-letterSpacing: var(--typography-letterSpacing-normal);
232
- --typography-heading-h4-fontFamily: var(--typography-fontFamily-sans);
233
-
234
- --typography-heading-h5-fontSize: var(--typography-fontSize-xl);
235
- --typography-heading-h5-fontWeight: var(--typography-fontWeight-medium);
236
- --typography-heading-h5-lineHeight: var(--typography-lineHeight-normal);
237
- --typography-heading-h5-letterSpacing: var(--typography-letterSpacing-normal);
238
- --typography-heading-h5-fontFamily: var(--typography-fontFamily-sans);
239
-
240
- --typography-heading-h6-fontSize: var(--typography-fontSize-lg);
241
- --typography-heading-h6-fontWeight: var(--typography-fontWeight-medium);
242
- --typography-heading-h6-lineHeight: var(--typography-lineHeight-normal);
243
- --typography-heading-h6-letterSpacing: var(--typography-letterSpacing-normal);
244
- --typography-heading-h6-fontFamily: var(--typography-fontFamily-sans);
245
-
246
- /* Body Text Tokens */
247
- --typography-body-large-fontSize: var(--typography-fontSize-lg);
248
- --typography-body-large-fontWeight: var(--typography-fontWeight-normal);
249
- --typography-body-large-lineHeight: var(--typography-lineHeight-relaxed);
250
- --typography-body-large-letterSpacing: var(--typography-letterSpacing-normal);
251
- --typography-body-large-fontFamily: var(--typography-fontFamily-sans);
252
-
253
- --typography-body-regular-fontSize: var(--typography-fontSize-base);
254
- --typography-body-regular-fontWeight: var(--typography-fontWeight-normal);
255
- --typography-body-regular-lineHeight: var(--typography-lineHeight-normal);
256
- --typography-body-regular-letterSpacing: var(
257
- --typography-letterSpacing-normal
258
- );
259
- --typography-body-regular-fontFamily: var(--typography-fontFamily-sans);
260
-
261
- --typography-body-small-fontSize: var(--typography-fontSize-sm);
262
- --typography-body-small-fontWeight: var(--typography-fontWeight-normal);
263
- --typography-body-small-lineHeight: var(--typography-lineHeight-normal);
264
- --typography-body-small-letterSpacing: var(--typography-letterSpacing-normal);
265
- --typography-body-small-fontFamily: var(--typography-fontFamily-sans);
266
-
267
- --typography-body-lead-fontSize: var(--typography-fontSize-xl);
268
- --typography-body-lead-fontWeight: var(--typography-fontWeight-normal);
269
- --typography-body-lead-lineHeight: var(--typography-lineHeight-relaxed);
270
- --typography-body-lead-letterSpacing: var(--typography-letterSpacing-normal);
271
- --typography-body-lead-fontFamily: var(--typography-fontFamily-sans);
272
-
273
- /* Label Tokens */
274
- --typography-label-default-fontSize: var(--typography-fontSize-sm);
275
- --typography-label-default-fontWeight: var(--typography-fontWeight-medium);
276
- --typography-label-default-lineHeight: var(--typography-lineHeight-normal);
277
- --typography-label-default-letterSpacing: var(
278
- --typography-letterSpacing-normal
279
- );
280
- --typography-label-default-fontFamily: var(--typography-fontFamily-sans);
281
-
282
- --typography-label-small-fontSize: var(--typography-fontSize-xs);
283
- --typography-label-small-fontWeight: var(--typography-fontWeight-medium);
284
- --typography-label-small-lineHeight: var(--typography-lineHeight-normal);
285
- --typography-label-small-letterSpacing: var(--typography-letterSpacing-wide);
286
- --typography-label-small-fontFamily: var(--typography-fontFamily-sans);
287
-
1
+ /* =====================================================================
2
+ Design tokens — document scope, inside the `bd-tokens` cascade layer.
3
+
4
+ The layer is what lets an application override a token: anything in a
5
+ cascade layer loses to unlayered CSS, so a consumer's own
6
+ `:root { --color-blue-500: ... }` wins over these defaults.
7
+
8
+ AUTO-GENERATED from src/tokens/tokens.js — run `npm run build:tokens`.
9
+ ===================================================================== */
10
+
11
+ @layer bd-tokens {
12
+ :root {
13
+ --typography-fontFamily-sans: "IBM Plex Sans", system-ui, -apple-system,
14
+ BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
15
+ --typography-fontFamily-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular,
16
+ Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
17
+
18
+ --typography-fontSize-xxs: 0.6875rem; /* 11px */
19
+ --typography-fontSize-xs: 0.75rem; /* 12px */
20
+ --typography-fontSize-sm: 0.875rem; /* 14px */
21
+ --typography-fontSize-base: 1rem; /* 16px */
22
+ --typography-fontSize-lg: 1.125rem; /* 18px */
23
+ --typography-fontSize-xl: 1.25rem; /* 20px */
24
+ --typography-fontSize-2xl: 1.5rem; /* 24px */
25
+ --typography-fontSize-3xl: 2rem; /* 32px */
26
+ --typography-fontSize-4xl: 2.25rem; /* 36px */
27
+ --typography-fontSize-5xl: 3rem; /* 48px */
28
+ --typography-fontSize-6xl: 3.75rem; /* 60px */
29
+ --typography-fontSize-7xl: 4.5rem; /* 72px */
30
+ --typography-fontSize-8xl: 6rem; /* 96px */
31
+ --typography-fontSize-9xl: 8rem; /* 128px */
32
+
33
+ --typography-fontWeight-light: 300;
34
+ --typography-fontWeight-normal: 400;
35
+ --typography-fontWeight-medium: 500;
36
+ --typography-fontWeight-semibold: 600;
37
+ --typography-fontWeight-bold: 700;
38
+
39
+ --typography-lineHeight-none: 1;
40
+ --typography-lineHeight-tight: 1.25;
41
+ /* There is no snug (1.375). It was Tailwind's step, it carried the
42
+ heading roles until the leading was measured against IBM Plex Sans,
43
+ and once those moved to tight and 130 its only readers were four
44
+ documentation-chrome files setting 11px text. 11px is what
45
+ label-extra-small already answers, at normal, so they were repointed
46
+ there and the step was retired rather than kept alive by its own
47
+ documentation. */
48
+ --typography-lineHeight-normal: 1.5;
49
+ --typography-lineHeight-relaxed: 1.625;
50
+ --typography-lineHeight-loose: 2;
51
+
52
+ /* The three steps above named for a density -- none .. loose -- are
53
+ Tailwind's default scale, values and names both, and nothing in them
54
+ was derived from IBM Plex Sans. These three were, and they are named
55
+ numerically because that is what the rest of this system does for a
56
+ scale step: --spacing-14, --dimension-44, --border-width-2.
57
+
58
+ 130 the font's own declared line box. hhea, OS/2 sTypo and OS/2
59
+ usWin in IBMPlexSans-*.woff2 all state 1.30, which is both
60
+ unusual and deliberate -- it is why the same text does not
61
+ change height between macOS and Windows.
62
+ 140 IBM's own published value for Plex at 20px (@carbon/type,
63
+ productive-heading-03 and expressive-heading-03).
64
+ 145 between IBM's 1.5 at 16px and 1.4 at 20px.
65
+
66
+ The floor under all of them is ink, not taste. The deepest glyphs in
67
+ this family are the Romanian comma-below letters -- s-comma and
68
+ t-comma, -0.275em in Bold, a third deeper than g -- and the tallest
69
+ are grave and acute capitals at +0.977em. Measured per weight, ink
70
+ spans 1.174 Light, 1.194 Regular, 1.219 Medium, 1.235 SemiBold,
71
+ 1.252 Bold. Nothing may be set below the floor for its weight, which
72
+ is why the display roles stay at tight and are not tightened further.
73
+ Foundations/Typography/Vertical Rhythm reaches 1.231 for 48px Bold
74
+ from canvas metrics; this is the same number from outline bounds. */
75
+ --typography-lineHeight-130: 1.3;
76
+ --typography-lineHeight-140: 1.4;
77
+ --typography-lineHeight-145: 1.45;
78
+
79
+ --typography-letterSpacing-tighter: -0.05em;
80
+ --typography-letterSpacing-tight: -0.025em;
81
+ --typography-letterSpacing-normal: 0em;
82
+ --typography-letterSpacing-wide: 0.025em;
83
+ --typography-letterSpacing-wider: 0.05em;
84
+ --typography-letterSpacing-widest: 0.1em;
85
+
86
+ /* =====================
87
+ COLORS
88
+ ====================== */
89
+ --color-blue-50: #f0f7ff;
90
+ --color-blue-100: #d6e8ff;
91
+ --color-blue-200: #9ec8ff;
92
+ --color-blue-300: #6babff;
93
+ --color-blue-400: #338bff;
94
+ --color-blue-500: #006dff;
95
+ --color-blue-600: #0059d6;
96
+ --color-blue-700: #0045ad;
97
+ --color-blue-800: #003385;
98
+ --color-blue-900: #00225c;
99
+ --color-blue-950: #001947;
100
+
101
+ --color-red-50: #fff0f0;
102
+ --color-red-100: #ffd6d6;
103
+ --color-red-200: #ff9e9e;
104
+ --color-red-300: #ff6b6b;
105
+ --color-red-400: #ff3333;
106
+ --color-red-500: #ff0000;
107
+ --color-red-600: #d60000;
108
+ --color-red-700: #ad0000;
109
+ --color-red-800: #850000;
110
+ --color-red-900: #5c0000;
111
+ --color-red-950: #470000;
112
+
113
+ --color-green-50: #edfdf1;
114
+ --color-green-100: #d1fadc;
115
+ --color-green-200: #9af4b4;
116
+ --color-green-300: #63ee8d;
117
+ --color-green-400: #2ce767;
118
+ --color-green-500: #15c14f;
119
+ --color-green-600: #12a641;
120
+ --color-green-700: #0e8532;
121
+ --color-green-800: #0b6a26;
122
+ --color-green-900: #084a1a;
123
+ --color-green-950: #063c14;
124
+ --color-green-975: #011705;
125
+
126
+ --color-yellow-50: #fffbf0;
127
+ --color-yellow-100: #fff5d6;
128
+ --color-yellow-200: #ffe89e;
129
+ --color-yellow-300: #ffdc6b;
130
+ --color-yellow-400: #ffcf33;
131
+ --color-yellow-500: #ffc400;
132
+ --color-yellow-600: #d6a000;
133
+ --color-yellow-700: #ad7f00;
134
+ --color-yellow-800: #855f00;
135
+ --color-yellow-900: #5c4000;
136
+ --color-yellow-950: #473100;
137
+ --color-yellow-975: #1a0f00;
138
+
139
+ --color-neutral-0: #ffffff;
140
+ --color-neutral-25: #fafafa;
141
+ --color-neutral-50: #f1f2f3;
142
+ --color-neutral-100: #e1e3e5;
143
+ --color-neutral-200: #c5c9ce;
144
+ --color-neutral-300: #a6adb4;
145
+ --color-neutral-400: #88909b;
146
+ /* The five in-between steps -- 450, 850, 925 here, and the two 975s
147
+ above -- exist for a dark theme, and nothing in light reads them.
148
+ The dark mode study (Foundations/Theming/Dark mode) found the ramps
149
+ too coarse at the dark end: container and subtle had to share
150
+ neutral-900 (finding 2), no step kept text-subtle both quieter than
151
+ muted and over 4.5:1 (finding 3), and green-950 and yellow-950 sat
152
+ 1.5:1 off the dark page where every other tint sits near 1.1
153
+ (finding 5). Each is interpolated in OKLCH between its two
154
+ neighbours to the ratio the derivation asks for: 450 is 4.75:1 on
155
+ a dark card (4.93 on the dark page), midway between 500 and 400 at
156
+ 1.22:1 from each -- subtle text sits on a page or a card, so it is
157
+ measured on the card (decision 17); 925 and 850 are 1.04 and 1.12
158
+ off it, the light container and subtle steps; the 975s are 1.04
159
+ and 1.03, the light tints. Measured against neutral-950, the dark
160
+ page, in src/tokens/dark-derivation.js. */
161
+ --color-neutral-450: #78818c;
162
+ /* #6a737e, moved one step from #6c7580. neutral-500 is
163
+ --color-text-subtle, and at #6c7580 subtle text on a card
164
+ (--color-surface-container, neutral-25) measured 4.48:1 -- under
165
+ 4.5 on the ground most subtle text sits on. #6a737e gives 4.61 on a
166
+ card and 4.81 on the page, and stays a clear step above
167
+ neutral-600 (1.37:1 apart, the gap was 1.39). It does not clear
168
+ subtle on surface-subtle or the status tints (4.29 to 4.46):
169
+ that needs a step this ramp does not have, and is its own
170
+ decision. */
171
+ --color-neutral-500: #6a737e;
172
+ --color-neutral-600: #565e66;
173
+ --color-neutral-700: #41474d;
174
+ --color-neutral-800: #2c3035;
175
+ --color-neutral-850: #181b1d;
176
+ --color-neutral-900: #151719;
177
+ --color-neutral-925: #111214;
178
+ --color-neutral-950: #0c0d0e;
179
+ --color-neutral-1000: #000000;
180
+
181
+ /* ================================
182
+ CORE BORDER TOKENS
183
+ ================================ */
184
+ --border-width-0: 0;
185
+ --border-width-1: 1px;
186
+ --border-width-2: 2px;
187
+ --border-width-3: 3px;
188
+ --border-width-4: 4px;
189
+ --border-width-8: 8px;
190
+
191
+ --radius-none: 0;
192
+ --radius-sm: 0.25rem; /* 4px */
193
+ --radius-md: 0.375rem; /* 6px */
194
+ --radius-lg: 0.5rem; /* 8px */
195
+ --radius-xl: 0.75rem; /* 12px */
196
+ --radius-2xl: 1rem; /* 16px */
197
+ --radius-3xl: 1.5rem; /* 24px */
198
+ --radius-full: 9999px;
199
+
200
+ /* ================================
201
+ CORE DIMENSION TOKENS
202
+ ================================ */
203
+
204
+
205
+ --dimension-4: 4px;
206
+ --dimension-8: 8px;
207
+ --dimension-12: 12px;
208
+ --dimension-16: 16px;
209
+ --dimension-20: 20px;
210
+ --dimension-24: 24px;
211
+ --dimension-32: 32px;
212
+ --dimension-36: 36px;
213
+ --dimension-40: 40px;
214
+ --dimension-44: 44px;
215
+ --dimension-48: 48px;
216
+ --dimension-56: 56px;
217
+ --dimension-64: 64px;
218
+
219
+ /* ================================
220
+ CORE TRANSITION TOKENS
221
+ ================================ */
222
+
223
+ --transition-duration-fast: 150ms;
224
+ --transition-duration-normal: 200ms;
225
+ --transition-duration-slow: 300ms;
226
+ --transition-duration-slower: 500ms;
227
+
228
+ --transition-easing-linear: linear;
229
+ --transition-easing-smooth: ease-in-out;
230
+ /* The CSS default curve. It was missing, and its absence was the single
231
+ reason eleven component transitions could not be expressed in tokens:
232
+ ease is not ease-in-out — it front-loads, and swapping one for the
233
+ other is a visible change. Named after the keyword, as linear,
234
+ ease-in and ease-out beside it are; smooth is the outlier that
235
+ aliases a keyword rather than naming it. */
236
+ --transition-easing-ease: ease;
237
+ --transition-easing-ease-in: ease-in;
238
+ --transition-easing-ease-out: ease-out;
239
+ --transition-easing-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
240
+
241
+ /* ================================
242
+ CORE SHADOW TOKENS
243
+ ================================ */
244
+
245
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
246
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
247
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1),
248
+ 0 4px 6px -4px rgb(0 0 0 / 0.1);
249
+ --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1),
250
+ 0 8px 10px -6px rgb(0 0 0 / 0.1);
251
+ --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
252
+ --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);
253
+
254
+ /* Focus Shadows - Box Shadow Version */
255
+ --shadow-focus-outline-blue: 0 0 0 3px rgba(6, 109, 255, 0.15);
256
+ --shadow-focus-outline-red: 0 0 0 3px rgba(239, 68, 68, 0.15);
257
+ --shadow-focus-outline-green: 0 0 0 3px rgba(34, 197, 94, 0.15);
258
+
259
+ /* Focus Outlines - Two-Color System for Universal Visibility */
260
+ --focus-outline-primary: 0 0 0 2px var(--color-neutral-0),
261
+ 0 0 0 4px var(--color-blue-500);
262
+ --focus-outline-secondary: 0 0 0 2px var(--color-neutral-0),
263
+ 0 0 0 4px var(--color-neutral-600);
264
+ --focus-outline-error: 0 0 0 2px var(--color-neutral-0),
265
+ 0 0 0 4px var(--color-red-500);
266
+ --focus-outline-success: 0 0 0 2px var(--color-neutral-0),
267
+ 0 0 0 4px var(--color-green-500);
268
+
269
+ /* The four above put the WHITE band against the control, which is what
270
+ keeps them visible on a coloured hero. That fails on a control which
271
+ is itself white: bd-button-link variant="white" measured 1.00:1 for
272
+ the inner band against its own fill and 2.38:1 for the blue band
273
+ against a blue hero, so neither band reached the 3:1 WCAG 2.4.11
274
+ asks of a focus indicator. This one inverts the pair -- dark band
275
+ against the control, white band against the ground -- so the inner
276
+ band carries the contrast whatever the control is sitting on. */
277
+ --focus-outline-inverse: 0 0 0 2px var(--color-neutral-900),
278
+ 0 0 0 4px var(--color-neutral-0);
279
+
280
+ /* Traditional Outline Values for Fallback */
281
+ --focus-outline-traditional: 2px solid var(--color-blue-500);
282
+ --focus-outline-offset: 2px;
283
+
284
+ /* The ring is a box-shadow, so it already follows the radius of the
285
+ element it is on. This is the default for elements that have no
286
+ radius of their own — a link, a tab, an accordion header — so the
287
+ ring is not a hard rectangle. An element with its own radius should
288
+ set nothing and let the ring follow its shape. */
289
+ --focus-outline-radius: var(--radius-sm);
290
+
291
+ /* ================================
292
+ SEMANTIC ROLE - SELECTED INDICATOR
293
+ ================================
294
+ What marks the current item in a set. Two components already drew it
295
+ — Components/Tab List and the anchor nav — and they drifted apart on
296
+ easing while both used valid tokens. The role is named here so there
297
+ is one answer, not two spellings.
298
+
299
+ THE COLOUR IS NOT NAMED FOR A SHAPE, and that is the whole point of
300
+ the split below. It was --indicator-underline-color, which described
301
+ the underline three components happen to draw rather than the job the
302
+ value does. awards-flex marks its current slide with a DOT: same job,
303
+ same blue-500, and it could not adopt the token because a dot is not
304
+ an underline, so it reached for the primitive instead. Vocabulary
305
+ question E1 found that — see plans/reports/phase-2-vocab-e-has-role-pass.md.
306
+
307
+ Renamed with no back-compat alias, following the same convention as
308
+ --typography-label-xsmall becoming --typography-body-xsmall: rename
309
+ cleanly and say why here.
310
+
311
+ The geometry stays underline-specific, because it genuinely is — a
312
+ 3px height and a width transition describe a rule sliding under a
313
+ tab, and a dot scales instead. A fourth consumer needing dot
314
+ geometry should name it for the dot, not borrow these. */
315
+ --indicator-color: var(--color-blue-500);
316
+ --indicator-underline-height: var(--border-width-3);
317
+ --indicator-underline-duration: var(--transition-duration-slow);
318
+ --indicator-underline-easing: var(--transition-easing-smooth);
319
+
320
+ /* ================================
321
+ SEMANTIC ROLE - CARD SHAPE
322
+ ================================
323
+ The corner and the inset that make a card a card here. Eleven
324
+ card-shaped objects agree on both -- the Card box, CardFeatures,
325
+ LightCarousel, Bento, the Awards feature card, the TrustPanel card,
326
+ the CompareSection card, the Carousel item, the Comparison Panel
327
+ column and both Pricing cards -- and they only agree because the two
328
+ that did not were brought in one at a time.
329
+
330
+ This role is named now and was deliberately not named before, and
331
+ the difference is evidence rather than appetite. CLAUDE.md said
332
+ there was no semantic radius scale because "the components do not
333
+ agree closely enough for a shared role to be honest", which was true
334
+ when it was written: the compare card sat at --radius-3xl and the
335
+ carousel item at --radius-3xl with a 2em inset. Both have since been
336
+ measured, argued and moved. A role declared then would have imposed
337
+ a consensus; declared now it records one.
338
+
339
+ It is a role, not a scale. There is still no --card-* family and no
340
+ semantic step between radii -- naming the job is the whole point,
341
+ and the same reasoning is why --panel-radius is NOT here: the eight
342
+ --radius-xl consumers are a code block, a bar track, a table
343
+ container, a discount pill, two public image variants, a modal and a
344
+ terminal. That is not a family, and calling it one would be the
345
+ mistake this comment is describing.
346
+
347
+ scripts/card-shapes.json lists the eleven and lint:tokens checks it
348
+ both ways, so a card that stops using the role and a registry entry
349
+ that stops matching are both findings. */
350
+ --card-radius: var(--radius-2xl);
351
+ --card-padding: var(--spacing-32);
352
+
353
+ /* The inset a card takes when the viewport is too narrow to afford the
354
+ full one. Four cards reached for this independently before it had a
355
+ name -- Bento below sm, the Comparison Panel and Trust Panel below
356
+ md, and LightCarousel with an em literal -- and three of the four
357
+ picked exactly 24. That is the agreement that makes it a role rather
358
+ than four local decisions.
359
+
360
+ Two steps, not a scale. A card is either affording its inset or it
361
+ is not; there is no third size, and a component that wants one is
362
+ asking a design question rather than a token question. */
363
+ --card-padding-compact: var(--spacing-24);
364
+
365
+ /* ================================
366
+ SEMANTIC ROLES - COLOUR
367
+ ================================
368
+ The tier the architecture always described and the components never
369
+ had. Measured before this landed: 71.8% of the colour references in
370
+ the atom layer pointed straight at a palette step — 38 distinct
371
+ primitives across 233 references, where the roles underneath them
372
+ number about thirty. That gap is why four text atoms ended up with
373
+ four different inks, and why two components disagreed about which
374
+ green means "success".
375
+
376
+ None of these are new decisions. Every value is the step something
377
+ already uses, and the text roles are the ones COLOR_ROLES in
378
+ src/components/shared/token-scales.js had already chosen as clearing
379
+ 4.5:1 on white — that map should now resolve through these rather
380
+ than reaching past them into the palette.
381
+
382
+ Reach for the role, not the step. The palette stays available for
383
+ what no role covers yet; when that happens, add the role.
384
+
385
+ ---
386
+
387
+ NAME COLLISION WITH src/blog. The blog sub-system already declares
388
+ seven of these names with different values:
389
+
390
+ --color-text-secondary here neutral-700 blog neutral-600
391
+ --color-text-muted here neutral-600 blog neutral-500
392
+ --color-surface-brand here blue-500 blog blue-50 (!)
393
+ --color-surface-inverse here neutral-900 blog neutral-950
394
+ --color-border-default here neutral-400 blog neutral-300
395
+ --color-border-subtle here neutral-200 blog neutral-100
396
+ --color-border-strong here neutral-900 blog neutral-600
397
+
398
+ This is safe today and must not be assumed safe. The blog applies
399
+ its tokens on :host inside each blog component, so inside a blog
400
+ shadow tree the blog value wins, and outside it never applies.
401
+ Nothing in this system renders inside that tree.
402
+
403
+ It stops being safe if a page ever loads src/blog/tokens.css
404
+ globally alongside this file. That file is an unlayered :root block,
405
+ and unlayered CSS beats a cascade layer, so it would win — silently
406
+ turning --color-surface-brand from a saturated fill into a pale
407
+ tint under any component that had adopted it.
408
+
409
+ The two files share 616 names and disagree on 82 of them; all 58
410
+ shared palette primitives are identical, so the fork is entirely at
411
+ this tier and above. Reconciling it is its own piece of work. Until
412
+ it happens, do not load both globally. */
413
+
414
+ /* Text. -primary is the default ink for anything that reads as body
415
+ or heading copy. -brand is blue-600 rather than blue-500 on purpose:
416
+ blue-500 is 4.53:1 on pure white and fails on any tint. */
417
+ --color-text-primary: var(--color-neutral-900);
418
+ --color-text-secondary: var(--color-neutral-700);
419
+ --color-text-muted: var(--color-neutral-600);
420
+ /* Subtle sits on the page or a card, and nowhere else: on a band
421
+ (surface-subtle, surface-muted) or a status tint, step up to
422
+ -muted. No value can be both quieter than muted and 4.5:1 on every
423
+ ground -- on surface-muted it would have to be muted -- so the rule
424
+ is where it goes, not how dark it is. Dark mode decision 17. */
425
+ --color-text-subtle: var(--color-neutral-500);
426
+ --color-text-disabled: var(--color-neutral-400);
427
+ --color-text-inverse: var(--color-neutral-0);
428
+ /* Subordinate text on an inverse surface. --color-text-inverse is the
429
+ high-emphasis step there; this is the one below it, and until now the
430
+ system had no such step at all -- the light-side -secondary, -muted and
431
+ -subtle roles invert to 1.91, 2.73 and 3.85 against
432
+ --color-surface-inverse and cannot be used.
433
+
434
+ Two components had already invented it independently and spelled it
435
+ differently: bd-terminal-message with rgba(255,255,255,0.5) and
436
+ bd-process-steps with --color-neutral-300 twice. neutral-300 is the
437
+ value here because it is the portable one. Measured on the three
438
+ inverse grounds in use -- neutral-900, neutral-800 and the #0b1626 the
439
+ process-steps gradient ends on -- it reads 7.92, 5.85 and 8.00, while
440
+ the white-at-half-alpha spelling reads 5.27, 3.89 and 5.32 and only
441
+ clears 4.5 because the terminal's ground happens to be the darkest of
442
+ the three.
443
+
444
+ There is deliberately no -secondary-inverse: bd-cta-banner has a third
445
+ tier at white 0.85 and it is one consumer, which is not a
446
+ responsibility. An earlier draft of this note also called it a
447
+ contrast failure, from a worst-case calculation against the lightest
448
+ stop in its gradient. Sampling the pixels actually behind the text
449
+ disproved that -- the radial highlight sits at 78% -10% and is mostly
450
+ outside the banner, so the three tiers measure 4.60, 4.57 and 4.46 at
451
+ their worst pixel rather than the 3.35, 2.84 and 2.13 the arithmetic
452
+ predicted. The tier is fine; it is still not a role. */
453
+ --color-text-muted-inverse: var(--color-neutral-300);
454
+ /* Ink on --color-surface-media, fixed with it: a part that does not
455
+ switch needs ink that does not switch either (the white button
456
+ preset, dark mode finding 8). text-inverse and text-muted-inverse
457
+ flip in a dark theme and would put dark ink on the dark frame --
458
+ a video play icon at 3.13:1, a terminal's quieter lines at 1.91. */
459
+ --color-text-on-media: var(--color-neutral-0);
460
+ --color-text-on-media-muted: var(--color-neutral-300);
461
+ --color-text-brand: var(--color-blue-600);
462
+ /* Brand text, hovered: a link or a citation reference under the
463
+ pointer. Before this role existed, the hover read
464
+ --color-action-primary-active -- a pressed button fill used as ink.
465
+ The value is the same blue-700, so nothing moves in this theme; the
466
+ difference is that a fill and a text colour answer different
467
+ questions, and a dark theme has to answer them differently. Measured
468
+ in the Figma Dark mode study: the fill stays put on a dark page and
469
+ the link it borrowed falls to 2.27:1. */
470
+ --color-text-brand-hover: var(--color-blue-700);
471
+ --color-text-success: var(--color-green-800);
472
+ --color-text-warning: var(--color-yellow-800);
473
+ --color-text-error: var(--color-red-700);
474
+
475
+ /* Surfaces. The feedback four are the tints a message sits on, each
476
+ measured against the matching --color-text-* step above: success
477
+ 6.42, warning 5.59, error 6.83, info 5.72.
478
+
479
+ -brand is the one to watch. --color-text-inverse on it measures
480
+ 4.53:1 — it passes, with no headroom at all, and it is the same
481
+ blue-500 the contrast note warns about elsewhere. White on brand is
482
+ fine for a button label; do not build a tinted variant on top of it
483
+ without re-measuring. */
484
+ --color-surface-default: var(--color-neutral-0);
485
+ /* The ground a self-contained content object sits on: one step off the
486
+ page, so a card, tile or panel reads as its own object without
487
+ needing a border or a shadow to say so. Twelve components were
488
+ reaching past the surface family for this, eight of them declaring
489
+ the same local alias, because the role did not exist.
490
+
491
+ Container is not subtle. Subtle groups things that already belong
492
+ together and is meant to recede; container is the default ground of
493
+ an object that stands on its own. They also differ visibly -- the
494
+ step between them is the difference between an object on the page
495
+ and a wash behind a group -- so they are not interchangeable.
496
+
497
+ The name means a visual container for content. It has nothing to do
498
+ with CSS container queries. */
499
+ --color-surface-container: var(--color-neutral-25);
500
+ --color-surface-subtle: var(--color-neutral-50);
501
+ --color-surface-muted: var(--color-neutral-100);
502
+ --color-surface-inverse: var(--color-neutral-900);
503
+ /* The frame around media: a video letterbox, a terminal panel. Dark in
504
+ every theme, because what it frames is dark -- which is why it is
505
+ not --color-surface-inverse, the polarity flip, that both used to
506
+ read. Inverse turns light in a dark theme; a letterbox must not,
507
+ and the terminal's own palette (blue-400, the traffic-light green)
508
+ is only legible on a dark ground. Dark mode decision 15. */
509
+ --color-surface-media: var(--color-neutral-900);
510
+ --color-surface-brand: var(--color-blue-500);
511
+ --color-surface-disabled: var(--color-neutral-100);
512
+ /* The ground of a control while it is held down, one step below
513
+ -muted (its hover). bd-back read neutral-200 for this and said in a
514
+ no-token comment that the surface roles stopped at -muted; reading
515
+ the primitive meant it could not follow a theme, and on a dark page
516
+ it measured 1.48:1 under a label that did (dark mode finding 14). */
517
+ --color-surface-pressed: var(--color-neutral-200);
518
+ --color-surface-success: var(--color-green-50);
519
+ --color-surface-warning: var(--color-yellow-50);
520
+ --color-surface-error: var(--color-red-50);
521
+ --color-surface-info: var(--color-blue-50);
522
+
523
+ /* Borders, measured on --color-surface-default. Only the two that
524
+ bound a live control clear the 3:1 WCAG 1.4.11 asks of a UI
525
+ component: -default at 3.23 and -brand at 4.53.
526
+
527
+ -subtle (1.66) and -disabled (2.27) sit below it on purpose.
528
+ -subtle is a decorative hairline between things that already belong
529
+ together, not the edge of anything actionable, and disabled controls
530
+ are exempt under 1.4.3. Do not reach for -subtle to outline a
531
+ control. */
532
+ --color-border-subtle: var(--color-neutral-200);
533
+ --color-border-default: var(--color-neutral-400);
534
+ --color-border-strong: var(--color-neutral-900);
535
+ --color-border-brand: var(--color-blue-500);
536
+ --color-border-disabled: var(--color-neutral-300);
537
+
538
+ /* The boundary of a self-contained object -- a card, a panel, a
539
+ navigation band -- drawn only so the object is perceptible, never so
540
+ it looks operable. It is the border counterpart of
541
+ --color-surface-container, and the two answer the same question from
542
+ opposite sides: is this its own thing.
543
+
544
+ It exists because eight components needed it and none could ask for
545
+ it. Seven reached past the roles to --color-neutral-100 directly and
546
+ one more declared a private --border-card-grey alias in seven files
547
+ to say --color-neutral-50. Measured on --color-surface-default it is
548
+ 1.29:1, and on --color-surface-container 1.23:1 -- deliberately below
549
+ -subtle's 1.66, because -subtle is already spoken for as the hairline
550
+ between things that belong together, and a long way below the 3:1
551
+ WCAG 1.4.11 asks of anything actionable. That is the point: an object
552
+ boundary is not a control edge, and must not read as one.
553
+
554
+ -inverse is the same responsibility on an inverse surface, the way
555
+ --color-text-inverse and --color-surface-inverse are, and not a
556
+ second role. It is spelled as a proportion of --color-neutral-0
557
+ rather than a raw rgba for the same reason
558
+ --button-outline-white-border-default is: the value stays traceable
559
+ to a token when the palette moves. Over --color-surface-inverse it
560
+ measures 1.42:1, which puts it in the same perceptual band as the
561
+ light value rather than at the 10.8:1 --color-border-subtle would
562
+ give there.
563
+
564
+ This role says what a low-emphasis boundary looks like. It does not
565
+ say whether a component should have one -- that stays a component
566
+ decision, and the evidence says the components genuinely disagree. */
567
+ --color-border-container: var(--color-neutral-100);
568
+ --color-border-container-inverse: color-mix(in srgb, var(--color-neutral-0) 12%, transparent);
569
+
570
+ /* Action. The interactive ramp, one step down the palette per state.
571
+ accent is this system's conversion colour — Buy now and the like —
572
+ and is not a danger signal; see the bd-button story notes. */
573
+ --color-action-primary: var(--color-blue-500);
574
+ --color-action-primary-hover: var(--color-blue-600);
575
+ --color-action-primary-active: var(--color-blue-700);
576
+ --color-action-accent: var(--color-red-600);
577
+ --color-action-accent-hover: var(--color-red-700);
578
+ --color-action-accent-active: var(--color-red-800);
579
+ /* The neutral action fill: the secondary button, and the ghost
580
+ button's pressed state. Both read neutral-950 / 800 / 1000 straight
581
+ from the palette, which no theme can reach -- and the dark page is
582
+ neutral-950 too, so in a dark theme the fill would vanish into it
583
+ (dark mode finding 8). A role gives the fill a value of its own in
584
+ each theme. */
585
+ --color-action-secondary: var(--color-neutral-950);
586
+ --color-action-secondary-hover: var(--color-neutral-800);
587
+ --color-action-secondary-active: var(--color-neutral-1000);
588
+ /* Ink on an action fill: a button label, a checkmark, a radio dot, a
589
+ switch thumb. Before this role existed the buttons read
590
+ --color-text-inverse ("text on an inverse surface") and the controls
591
+ read --color-surface-default ("the page"). Both resolve to white in
592
+ this theme, which is why the borrowing never showed -- and both must
593
+ flip to near-black in a dark one, which would turn every label and
594
+ mark dark on its blue or red fill. White clears every action fill:
595
+ 4.53 to 10.51:1. Measured in the Figma Dark mode study. */
596
+ --color-action-on-fill: var(--color-neutral-0);
597
+
598
+ /* ================================
599
+ SEMANTIC ROLES - STACKING
600
+ ================================
601
+ Thirty z-index declarations across eight values that were never
602
+ chosen relative to one another: -1, 1, 2, 10, 200, 1000, 1001 and
603
+ 9999. Both bd-modal and the carousel sit on 9999, so there is no
604
+ answer to which of the two wins — that is what an unscaled ladder
605
+ costs.
606
+
607
+ The rungs are far apart on purpose, so a component can take a rung
608
+ and still stack its own internals inside it with a calc. A tooltip
609
+ opened from inside a dialog has to clear the dialog, which is why
610
+ it is the top rung rather than the first. */
611
+ --z-below: -1;
612
+ --z-base: 1;
613
+ --z-raised: 2;
614
+ --z-sticky: 200;
615
+ --z-overlay: 1000;
616
+ --z-modal: 1100;
617
+ --z-tooltip: 1200;
618
+
619
+ /* ================================
620
+ SEMANTIC ROLES - OPACITY
621
+ ================================
622
+ One role, because one role is what the evidence supports. The dim
623
+ end of a reduced-motion pulse is spelled three times in the atom
624
+ layer — bd-button and bd-spinner at 0.4, bd-skeleton at 0.45 — and
625
+ is the same intent each time: a mark that cannot spin should still
626
+ read as busy.
627
+
628
+ Disabled is deliberately absent. This system expresses disabled with
629
+ the neutral ramp rather than by dimming, and the one token that said
630
+ otherwise (--button-shared-disabled-opacity: 0.6) is unused. */
631
+ --opacity-pulse: 0.4;
632
+
633
+ /* ================================
634
+ SEMANTIC ROLE - STATUS TONES
635
+ ================================
636
+ bd-badge, bd-tag and bd-alert all say the same six things and each
637
+ spelled them out for itself. The text colours already matched across
638
+ badge and tag — the tag story says so — but by coincidence rather
639
+ than construction, and the one place they had drifted proves the
640
+ point: alert drew its success rule in green-600 where badge's
641
+ success dot used green-700.
642
+
643
+ Seven roles, because the three components need different weights of
644
+ the same tone:
645
+
646
+ -text ink on a tinted chip badge shade, tag
647
+ -surface the light tint tag, alert
648
+ -surface-strong the heavier tint badge shade
649
+ -border the hairline tag
650
+ -accent the saturated step badge dot, alert rule
651
+ -fill / -on-fill a saturated chip and its ink badge fill
652
+
653
+ What is deliberately *not* unified: a tag carries a border and sits
654
+ on -surface, a badge has no border and sits on -surface-strong. That
655
+ difference is documented in the tag story — the lighter fill is what
656
+ lets the tag's border read — so it is expressed as two roles rather
657
+ than flattened into one.
658
+
659
+ Brand has no -surface-strong. It would be blue-100, which is
660
+ info's, so a brand badge on it could not be told from an info badge.
661
+ Brand's badge sits on -surface like its tag, and that one collision
662
+ is the whole exception. */
663
+
664
+ --status-neutral-text: var(--color-neutral-700);
665
+ --status-neutral-surface: var(--color-neutral-50);
666
+ --status-neutral-surface-strong: var(--color-neutral-100);
667
+ --status-neutral-border: var(--color-neutral-200);
668
+ --status-neutral-accent: var(--color-neutral-700);
669
+ --status-neutral-fill: var(--color-neutral-900);
670
+ --status-neutral-on-fill: var(--color-neutral-0);
671
+
672
+ --status-brand-text: var(--color-blue-600);
673
+ --status-brand-surface: var(--color-blue-50);
674
+ --status-brand-border: var(--color-blue-200);
675
+ --status-brand-accent: var(--color-blue-600);
676
+ --status-brand-fill: var(--color-blue-500);
677
+ --status-brand-on-fill: var(--color-neutral-0);
678
+
679
+ --status-info-text: var(--color-blue-600);
680
+ --status-info-surface: var(--color-blue-50);
681
+ --status-info-surface-strong: var(--color-blue-100);
682
+ --status-info-border: var(--color-blue-200);
683
+ --status-info-accent: var(--color-blue-500);
684
+ --status-info-fill: var(--color-blue-500);
685
+ --status-info-on-fill: var(--color-neutral-0);
686
+
687
+ --status-success-text: var(--color-green-800);
688
+ --status-success-surface: var(--color-green-50);
689
+ --status-success-surface-strong: var(--color-green-100);
690
+ --status-success-border: var(--color-green-200);
691
+ --status-success-accent: var(--color-green-700);
692
+ --status-success-fill: var(--color-green-700);
693
+ --status-success-on-fill: var(--color-neutral-0);
694
+
695
+ --status-warning-text: var(--color-yellow-800);
696
+ --status-warning-surface: var(--color-yellow-50);
697
+ --status-warning-surface-strong: var(--color-yellow-100);
698
+ --status-warning-border: var(--color-yellow-200);
699
+ --status-warning-accent: var(--color-yellow-700);
700
+ --status-warning-fill: var(--color-yellow-500);
701
+ --status-warning-on-fill: var(--color-neutral-900);
702
+
703
+ --status-error-text: var(--color-red-700);
704
+ --status-error-surface: var(--color-red-50);
705
+ --status-error-surface-strong: var(--color-red-100);
706
+ --status-error-border: var(--color-red-200);
707
+ --status-error-accent: var(--color-red-600);
708
+ --status-error-fill: var(--color-red-600);
709
+ --status-error-on-fill: var(--color-neutral-0);
710
+
711
+ /* ================================
712
+ COMPONENT TOKENS - TYPOGRAPHY
713
+ ================================ */
714
+
715
+
716
+ /* ===============================================================
717
+ FLUID TYPE - the roles that cannot hold their size on a phone.
718
+
719
+ WHY. Measured in the Figma file (page "Type on mobile"), the
720
+ binding constraint on large type is not how many lines a sentence
721
+ takes, it is whether the longest UNBREAKABLE WORD fits the column.
722
+ The column is the viewport minus twice --grid-padding-*, so a 320px
723
+ phone gives type 288px -- 10% of the screen is gutter. Against that
724
+ column the ceiling for the worst realistic compound (Finnish
725
+ "Henkilollisyyssuoja", 9.07px of width per px of size) is 31px.
726
+ heading-h1 is 48. It overflowed at 375 as well as at 320, in German
727
+ and Finnish both.
728
+
729
+ WHY NOT A BREAKPOINT STEP. Tried first and abandoned, measured:
730
+ stepping h1 to 36 below sm still overflows at 320 (needs 327 of
731
+ 288) and changes nothing at 576-767 where the ceiling is already 54.
732
+ The constraint moves continuously with the column, because the
733
+ column is a function of viewport width -- a step function
734
+ approximates a line with a staircase. clamp() states the line.
735
+
736
+ THE WINDOW IS 320 -> 992. The minimum is reached at 320 and the
737
+ maximum at 992, which is the lg breakpoint. Above lg NOTHING
738
+ changes from the sizes this system shipped with, so every desktop
739
+ layout that has been reviewed stays exactly as reviewed, and the
740
+ whole change is confined to the widths where the failures were
741
+ measured.
742
+
743
+ THE MIDDLE TERM CARRIES A rem, AND THAT IS NOT OPTIONAL.
744
+ clamp(2rem, 4vw, 3rem) is the spelling everyone reaches for and it
745
+ breaks text resize: a size depending only on viewport width ignores
746
+ the reader's own font-size setting, which is WCAG 1.4.4. With a rem
747
+ in the middle term the type still grows when the reader enlarges
748
+ it. This package already refuses the equivalent mistake twice --
749
+ line-height is always unitless, and --spacing-* is rem precisely so
750
+ boxes grow with the text.
751
+
752
+ THE TWO LITERALS PER ROLE ARE DERIVED, NOT CHOSEN. For a role
753
+ running from min m to max M across the window V1..V2:
754
+
755
+ slope = (M - m) / (V2 - V1) px of size per px of width
756
+ vw term = slope x 100
757
+ rem term = (m - slope x V1) / 16
758
+
759
+ With V1=320 and V2=992 that is (M-m)/6.72 vw and
760
+ (m - (M-m)/2.1) / 16 rem. Every pair below is that arithmetic and
761
+ nothing else; each line states its own m and M so it can be checked
762
+ without re-deriving. Changing the mobile ladder means changing the
763
+ -fontSizeMin token and re-running the two formulas.
764
+
765
+ THE MOBILE LADDER IS THE DESIGN DECISION HERE, and it is these six
766
+ numbers: 30 27 24 21 18 16 for h1 through h6. Its ratios are 1.11,
767
+ 1.13, 1.14, 1.17, 1.13 -- near-even, against the desktop ladder's
768
+ irregular 1.33, 1.13, 1.33, 1.20, 1.11. A phone has less range to
769
+ spend (16 to the 31px ceiling, a factor of 1.94, where desktop has
770
+ 18 to 48, a factor of 2.67), so the ladder has to compress, and
771
+ compressing it evenly is what keeps six levels distinguishable.
772
+ Measured: h1 at 30 needs 272px of a 288px column, so there is 16px
773
+ of margin for a word longer than any tested.
774
+
775
+ WHAT IS DELIBERATELY NOT FLUID.
776
+ - Every role at 24px and below except body-lead. Nothing that small
777
+ overflows, and the small end's own failure is measure, not
778
+ overflow -- see below.
779
+ - display-lg, display-xl, display-2xl, display-3xl (60 to 128px).
780
+ Above display-md the family has NO mobile identity
781
+ to give it: five roles would all have to squeeze between 30 and
782
+ the 31px ceiling. They are desktop-only, and a component that
783
+ needs one of them on a phone should reach for a heading role
784
+ instead. Recorded rather than papered over.
785
+ - body-regular at 16px. It runs 40 characters per line on a 288px
786
+ column, which the study first called "below the comfortable
787
+ 45-75 band" -- and that band is a print and desktop yardstick.
788
+ Reaching 45 CPL on a 288px column needs 14.2px body text, and 50
789
+ CPL needs 12.8px; applying it to a phone trades the 16px
790
+ accessibility floor for a soft readability target. 40 characters
791
+ is what every phone does. body-lead is the one prose role that
792
+ does move, 20 -> 18, because at 20 it ran 32 characters -- five
793
+ or six words a line -- and an intro paragraph has no claim on
794
+ being the largest thing on a small screen.
795
+ =============================================================== */
796
+
797
+ /* Heading Tokens */
798
+ /* fluid: 30px at 320 -> 48px at 992. (48-30)/6.72=2.6786vw, (30-(48-30)/2.1)/16=1.33929rem */
799
+ --typography-heading-h1-fontSizeMin: 1.875rem; /* 30px */
800
+ --typography-heading-h1-fontSize: clamp(
801
+ var(--typography-heading-h1-fontSizeMin),
802
+ calc(1.33929rem + 2.6786vw),
803
+ var(--typography-fontSize-5xl)
804
+ );
805
+ --typography-heading-h1-fontWeight: var(--typography-fontWeight-bold);
806
+ --typography-heading-h1-lineHeight: var(--typography-lineHeight-tight);
807
+ --typography-heading-h1-letterSpacing: var(--typography-letterSpacing-normal);
808
+ --typography-heading-h1-fontFamily: var(--typography-fontFamily-sans);
809
+
810
+ /* fluid: 27px at 320 -> 36px at 992. (36-27)/6.72=1.3393vw, (27-(36-27)/2.1)/16=1.41964rem */
811
+ --typography-heading-h2-fontSizeMin: 1.6875rem; /* 27px */
812
+ --typography-heading-h2-fontSize: clamp(
813
+ var(--typography-heading-h2-fontSizeMin),
814
+ calc(1.41964rem + 1.3393vw),
815
+ var(--typography-fontSize-4xl)
816
+ );
817
+ --typography-heading-h2-fontWeight: var(--typography-fontWeight-bold);
818
+ --typography-heading-h2-lineHeight: var(--typography-lineHeight-tight);
819
+ --typography-heading-h2-letterSpacing: var(--typography-letterSpacing-normal);
820
+ --typography-heading-h2-fontFamily: var(--typography-fontFamily-sans);
821
+
822
+ /* fluid: 24px at 320 -> 32px at 992. (32-24)/6.72=1.1905vw, (24-(32-24)/2.1)/16=1.26190rem */
823
+ --typography-heading-h3-fontSizeMin: 1.5rem; /* 24px */
824
+ --typography-heading-h3-fontSize: clamp(
825
+ var(--typography-heading-h3-fontSizeMin),
826
+ calc(1.26190rem + 1.1905vw),
827
+ var(--typography-fontSize-3xl)
828
+ );
829
+ --typography-heading-h3-fontWeight: var(--typography-fontWeight-semibold);
830
+ --typography-heading-h3-lineHeight: var(--typography-lineHeight-130);
831
+ --typography-heading-h3-letterSpacing: var(--typography-letterSpacing-normal);
832
+ --typography-heading-h3-fontFamily: var(--typography-fontFamily-sans);
833
+
834
+ /* fluid: 21px at 320 -> 24px at 992. (24-21)/6.72=0.4464vw, (21-(24-21)/2.1)/16=1.22321rem */
835
+ --typography-heading-h4-fontSizeMin: 1.3125rem; /* 21px */
836
+ --typography-heading-h4-fontSize: clamp(
837
+ var(--typography-heading-h4-fontSizeMin),
838
+ calc(1.22321rem + 0.4464vw),
839
+ var(--typography-fontSize-2xl)
840
+ );
841
+ --typography-heading-h4-fontWeight: var(--typography-fontWeight-semibold);
842
+ --typography-heading-h4-lineHeight: var(--typography-lineHeight-130);
843
+ --typography-heading-h4-letterSpacing: var(--typography-letterSpacing-normal);
844
+ --typography-heading-h4-fontFamily: var(--typography-fontFamily-sans);
845
+
846
+ /* fluid: 18px at 320 -> 20px at 992. (20-18)/6.72=0.2976vw, (18-(20-18)/2.1)/16=1.06548rem */
847
+ --typography-heading-h5-fontSizeMin: 1.125rem; /* 18px */
848
+ --typography-heading-h5-fontSize: clamp(
849
+ var(--typography-heading-h5-fontSizeMin),
850
+ calc(1.06548rem + 0.2976vw),
851
+ var(--typography-fontSize-xl)
852
+ );
853
+ --typography-heading-h5-fontWeight: var(--typography-fontWeight-medium);
854
+ --typography-heading-h5-lineHeight: var(--typography-lineHeight-140);
855
+ --typography-heading-h5-letterSpacing: var(--typography-letterSpacing-normal);
856
+ --typography-heading-h5-fontFamily: var(--typography-fontFamily-sans);
857
+
858
+ /* fluid: 16px at 320 -> 18px at 992. (18-16)/6.72=0.2976vw, (16-(18-16)/2.1)/16=0.94048rem */
859
+ --typography-heading-h6-fontSizeMin: 1rem; /* 16px */
860
+ --typography-heading-h6-fontSize: clamp(
861
+ var(--typography-heading-h6-fontSizeMin),
862
+ calc(0.94048rem + 0.2976vw),
863
+ var(--typography-fontSize-lg)
864
+ );
865
+ --typography-heading-h6-fontWeight: var(--typography-fontWeight-medium);
866
+ --typography-heading-h6-lineHeight: var(--typography-lineHeight-145);
867
+ --typography-heading-h6-letterSpacing: var(--typography-letterSpacing-normal);
868
+ --typography-heading-h6-fontFamily: var(--typography-fontFamily-sans);
869
+
870
+ /* Body Text Tokens */
871
+ --typography-body-large-fontSize: var(--typography-fontSize-lg);
872
+ --typography-body-large-fontWeight: var(--typography-fontWeight-normal);
873
+ --typography-body-large-lineHeight: var(--typography-lineHeight-145);
874
+ --typography-body-large-letterSpacing: var(--typography-letterSpacing-normal);
875
+ --typography-body-large-fontFamily: var(--typography-fontFamily-sans);
876
+
877
+ --typography-body-regular-fontSize: var(--typography-fontSize-base);
878
+ --typography-body-regular-fontWeight: var(--typography-fontWeight-normal);
879
+ --typography-body-regular-lineHeight: var(--typography-lineHeight-normal);
880
+ --typography-body-regular-letterSpacing: var(
881
+ --typography-letterSpacing-normal
882
+ );
883
+ --typography-body-regular-fontFamily: var(--typography-fontFamily-sans);
884
+
885
+ --typography-body-small-fontSize: var(--typography-fontSize-sm);
886
+ --typography-body-small-fontWeight: var(--typography-fontWeight-normal);
887
+ --typography-body-small-lineHeight: var(--typography-lineHeight-145);
888
+ --typography-body-small-letterSpacing: var(--typography-letterSpacing-normal);
889
+ --typography-body-small-fontFamily: var(--typography-fontFamily-sans);
890
+
891
+ /* fluid: 18px at 320 -> 20px at 992. (20-18)/6.72=0.2976vw, (18-(20-18)/2.1)/16=1.06548rem */
892
+ --typography-body-lead-fontSizeMin: 1.125rem; /* 18px */
893
+ --typography-body-lead-fontSize: clamp(
894
+ var(--typography-body-lead-fontSizeMin),
895
+ calc(1.06548rem + 0.2976vw),
896
+ var(--typography-fontSize-xl)
897
+ );
898
+ --typography-body-lead-fontWeight: var(--typography-fontWeight-normal);
899
+ --typography-body-lead-lineHeight: var(--typography-lineHeight-140);
900
+ --typography-body-lead-letterSpacing: var(--typography-letterSpacing-normal);
901
+ --typography-body-lead-fontFamily: var(--typography-fontFamily-sans);
902
+
903
+ /* Label Tokens */
904
+ --typography-label-default-fontSize: var(--typography-fontSize-sm);
905
+ --typography-label-default-fontWeight: var(--typography-fontWeight-medium);
906
+ --typography-label-default-lineHeight: var(--typography-lineHeight-normal);
907
+ --typography-label-default-letterSpacing: var(
908
+ --typography-letterSpacing-normal
909
+ );
910
+ --typography-label-default-fontFamily: var(--typography-fontFamily-sans);
911
+
912
+ --typography-label-small-fontSize: var(--typography-fontSize-xs);
913
+ --typography-label-small-fontWeight: var(--typography-fontWeight-medium);
914
+ --typography-label-small-lineHeight: var(--typography-lineHeight-normal);
915
+ --typography-label-small-letterSpacing: var(--typography-letterSpacing-wide);
916
+ --typography-label-small-fontFamily: var(--typography-fontFamily-sans);
917
+
918
+ /* The only role for the 11px step, and it carried a size and nothing
919
+ else -- so anything using it inherited its leading from whatever it
920
+ happened to sit inside, which is not a typography contract. The four
921
+ missing axes match label-small, one step up. It has no consumers
922
+ today; the five components that render 11px reach past it for the
923
+ primitive, and moving them is a visual change this phase does not
924
+ make. */
288
925
  --typography-label-extra-small-fontSize: var(--typography-fontSize-xxs);
289
-
290
- --typography-label-large-fontSize: var(--typography-fontSize-base);
291
- --typography-label-large-fontWeight: var(--typography-fontWeight-medium);
292
- --typography-label-large-lineHeight: var(--typography-lineHeight-normal);
293
- --typography-label-large-letterSpacing: var(
294
- --typography-letterSpacing-normal
295
- );
296
- --typography-label-large-fontFamily: var(--typography-fontFamily-sans);
297
-
298
- --typography-label-xl-fontSize: var(--typography-fontSize-lg);
299
- --typography-label-xl-fontWeight: var(--typography-fontWeight-medium);
300
- --typography-label-xl-lineHeight: var(--typography-lineHeight-normal);
301
- --typography-label-xl-letterSpacing: var(--typography-letterSpacing-normal);
302
- --typography-label-xl-fontFamily: var(--typography-fontFamily-sans);
303
-
304
- /* Caption Tokens */
305
- --typography-caption-default-fontSize: var(--typography-fontSize-xs);
306
- --typography-caption-default-fontWeight: var(--typography-fontWeight-normal);
307
- --typography-caption-default-lineHeight: var(--typography-lineHeight-normal);
308
- --typography-caption-default-letterSpacing: var(
309
- --typography-letterSpacing-normal
310
- );
311
- --typography-caption-default-fontFamily: var(--typography-fontFamily-sans);
312
-
313
- --typography-caption-small-fontSize: var(--typography-fontSize-xs);
314
- --typography-caption-small-fontWeight: var(--typography-fontWeight-normal);
315
- --typography-caption-small-lineHeight: var(--typography-lineHeight-normal);
316
- --typography-caption-small-letterSpacing: var(
317
- --typography-letterSpacing-wide
318
- );
319
- --typography-caption-small-fontFamily: var(--typography-fontFamily-sans);
320
-
321
- /* Link Tokens */
322
- --typography-link-default-fontSize: inherit;
323
- --typography-link-default-fontWeight: var(--typography-fontWeight-normal);
324
- --typography-link-default-lineHeight: inherit;
325
- --typography-link-default-letterSpacing: inherit;
326
- --typography-link-default-fontFamily: inherit;
327
- --typography-link-default-textDecoration-default: underline;
328
- --typography-link-default-textDecoration-hover: none;
329
-
330
- --typography-link-standalone-fontSize: var(--typography-fontSize-base);
331
- --typography-link-standalone-fontWeight: var(--typography-fontWeight-medium);
332
- --typography-link-standalone-lineHeight: var(--typography-lineHeight-normal);
333
- --typography-link-standalone-letterSpacing: var(
334
- --typography-letterSpacing-normal
335
- );
336
- --typography-link-standalone-fontFamily: var(--typography-fontFamily-sans);
337
- --typography-link-standalone-textDecoration-default: underline;
338
- --typography-link-standalone-textDecoration-hover: none;
339
-
340
- /* Code Tokens */
341
- --typography-code-inline-fontSize: 0.875em;
342
- --typography-code-inline-fontWeight: var(--typography-fontWeight-normal);
343
- --typography-code-inline-lineHeight: inherit;
344
- --typography-code-inline-letterSpacing: var(
345
- --typography-letterSpacing-normal
346
- );
347
- --typography-code-inline-fontFamily: var(--typography-fontFamily-mono);
348
-
349
- --typography-code-block-fontSize: var(--typography-fontSize-sm);
350
- --typography-code-block-fontWeight: var(--typography-fontWeight-normal);
351
- --typography-code-block-lineHeight: var(--typography-lineHeight-relaxed);
352
- --typography-code-block-letterSpacing: var(--typography-letterSpacing-normal);
353
- --typography-code-block-fontFamily: var(--typography-fontFamily-mono);
354
-
355
- /* Display Typography Tokens */
356
- --typography-display-3xl-fontSize: var(--typography-fontSize-9xl);
357
- --typography-display-3xl-fontWeight: var(--typography-fontWeight-bold);
358
- --typography-display-3xl-lineHeight: var(--typography-lineHeight-tight);
359
- --typography-display-3xl-letterSpacing: var(--typography-letterSpacing-tight);
360
- --typography-display-3xl-fontFamily: var(--typography-fontFamily-sans);
361
-
362
- --typography-display-2xl-fontSize: var(--typography-fontSize-8xl);
363
- --typography-display-2xl-fontWeight: var(--typography-fontWeight-bold);
364
- --typography-display-2xl-lineHeight: var(--typography-lineHeight-tight);
365
- --typography-display-2xl-letterSpacing: var(--typography-letterSpacing-tight);
366
- --typography-display-2xl-fontFamily: var(--typography-fontFamily-sans);
367
-
368
- --typography-display-xl-fontSize: var(--typography-fontSize-7xl);
369
- --typography-display-xl-fontWeight: var(--typography-fontWeight-bold);
370
- --typography-display-xl-lineHeight: var(--typography-lineHeight-tight);
371
- --typography-display-xl-letterSpacing: var(--typography-letterSpacing-tight);
372
- --typography-display-xl-fontFamily: var(--typography-fontFamily-sans);
373
-
374
- --typography-display-lg-fontSize: var(--typography-fontSize-6xl);
375
- --typography-display-lg-fontWeight: var(--typography-fontWeight-bold);
376
- --typography-display-lg-lineHeight: var(--typography-lineHeight-tight);
377
- --typography-display-lg-letterSpacing: var(--typography-letterSpacing-tight);
378
- --typography-display-lg-fontFamily: var(--typography-fontFamily-sans);
379
-
380
- --typography-display-md-fontSize: var(--typography-fontSize-5xl);
381
- --typography-display-md-fontWeight: var(--typography-fontWeight-bold);
382
- --typography-display-md-lineHeight: var(--typography-lineHeight-tight);
383
- --typography-display-md-letterSpacing: var(--typography-letterSpacing-tight);
384
- --typography-display-md-fontFamily: var(--typography-fontFamily-sans);
385
-
386
- --typography-display-sm-fontSize: var(--typography-fontSize-4xl);
387
- --typography-display-sm-fontWeight: var(--typography-fontWeight-bold);
388
- --typography-display-sm-lineHeight: var(--typography-lineHeight-tight);
389
- --typography-display-sm-letterSpacing: var(--typography-letterSpacing-tight);
390
- --typography-display-sm-fontFamily: var(--typography-fontFamily-sans);
391
-
392
- /* ================================
393
- COMPONENT TOKENS - FORM
394
- ================================ */
395
-
396
- /* Form Label Tokens */
397
- --form-label-default-fontSize: var(--typography-fontSize-sm);
398
- --form-label-default-fontWeight: var(--typography-fontWeight-medium);
399
- --form-label-default-lineHeight: var(--typography-lineHeight-normal);
400
- --form-label-default-letterSpacing: var(--typography-letterSpacing-normal);
401
- --form-label-default-fontFamily: var(--typography-fontFamily-sans);
402
- --form-label-default-color: var(--color-neutral-900);
403
- --form-label-default-marginBottom: var(--spacing-1);
404
-
405
- --form-label-large-fontSize: var(--typography-fontSize-lg);
406
- --form-label-large-fontWeight: var(--typography-fontWeight-medium);
407
- --form-label-large-lineHeight: var(--typography-lineHeight-normal);
408
- --form-label-large-letterSpacing: var(--typography-letterSpacing-normal);
409
- --form-label-large-fontFamily: var(--typography-fontFamily-sans);
410
- --form-label-large-color: var(--color-neutral-900);
411
- --form-label-large-marginBottom: var(--spacing-2);
412
-
413
- --form-label-small-fontSize: var(--typography-fontSize-xs);
414
- --form-label-small-fontWeight: var(--typography-fontWeight-medium);
415
- --form-label-small-lineHeight: var(--typography-lineHeight-normal);
416
- --form-label-small-letterSpacing: var(--typography-letterSpacing-wide);
417
- --form-label-small-fontFamily: var(--typography-fontFamily-sans);
418
- --form-label-small-color: var(--color-neutral-900);
419
- --form-label-small-marginBottom: var(--spacing-1);
420
-
421
- --form-label-required-color: var(--color-red-500);
422
- --form-label-required-marginLeft: var(--spacing-1);
423
-
424
- /* Form Input Tokens */
425
- --form-input-small-height: var(--dimension-34px);
426
- --form-input-small-fontSize: var(--typography-fontSize-sm);
427
- --form-input-small-padding: var(--spacing-2) var(--spacing-3);
428
- --form-input-small-borderRadius: var(--radius-sm);
429
-
430
- --form-input-medium-height: var(--dimension-45px);
431
- --form-input-medium-fontSize: var(--typography-fontSize-base);
432
- --form-input-medium-padding: var(--spacing-3) var(--spacing-4);
433
- --form-input-medium-borderRadius: var(--radius-md);
434
-
435
- --form-input-large-height: var(--dimension-55px);
436
- --form-input-large-fontSize: var(--typography-fontSize-lg);
437
- --form-input-large-padding: var(--spacing-4) var(--spacing-5);
438
- --form-input-large-borderRadius: var(--radius-lg);
439
-
440
- --form-input-default-backgroundColor: var(--color-neutral-0);
441
- --form-input-default-borderColor: var(--color-neutral-300);
442
- --form-input-default-borderWidth: var(--border-width-1);
443
- --form-input-default-color: var(--color-neutral-900);
444
- --form-input-default-fontFamily: var(--typography-fontFamily-sans);
445
- --form-input-default-lineHeight: var(--typography-lineHeight-normal);
446
-
447
- --form-input-focus-borderColor: var(--color-blue-500);
448
- --form-input-focus-boxShadow: var(--shadow-focus-outline-blue);
449
-
450
- --form-input-error-backgroundColor: var(--color-red-50);
451
- --form-input-error-borderColor: var(--color-red-500);
452
- --form-input-error-placeholderColor: var(--color-red-400);
453
-
454
- --form-input-success-backgroundColor: var(--color-green-50);
455
- --form-input-success-borderColor: var(--color-green-500);
456
- --form-input-success-placeholderColor: var(--color-green-400);
457
-
458
- --form-input-disabled-backgroundColor: var(--color-neutral-100);
459
- --form-input-disabled-borderColor: var(--color-neutral-300);
460
- --form-input-disabled-color: var(--color-neutral-500);
461
- --form-input-disabled-placeholderColor: var(--color-neutral-400);
462
-
463
- /* Form Help Text Tokens */
464
- --form-help-text-default-fontSize: var(--typography-fontSize-xs);
465
- --form-help-text-default-fontWeight: var(--typography-fontWeight-normal);
466
- --form-help-text-default-lineHeight: var(--typography-lineHeight-normal);
467
- --form-help-text-default-letterSpacing: var(
468
- --typography-letterSpacing-normal
469
- );
470
- --form-help-text-default-fontFamily: var(--typography-fontFamily-sans);
471
- --form-help-text-default-color: var(--color-neutral-600);
472
- --form-help-text-default-marginTop: var(--spacing-1);
473
-
474
- --form-help-text-error-color: var(--color-red-600);
475
- --form-help-text-success-color: var(--color-green-600);
476
-
477
- /* Form Layout Tokens */
478
- --form-fieldSpacing: var(--spacing-6);
479
- --form-sectionSpacing: var(--spacing-8);
480
- --form-labelSpacing: var(--spacing-1);
481
- --form-helpTextSpacing: var(--spacing-1);
482
-
483
- /* ================================
484
- COMPONENT TOKENS - BUTTON
485
- ================================ */
486
-
487
- /* Button Size Tokens */
488
- --button-small-height: var(--dimension-34px);
489
- --button-small-fontSize: var(--typography-fontSize-sm);
490
- --button-small-padding: var(--spacing-2) var(--spacing-3);
491
- --button-small-borderRadius: var(--radius-sm);
492
-
493
- --button-medium-height: var(--dimension-45px);
494
- --button-medium-fontSize: var(--typography-fontSize-base);
495
- --button-medium-padding: var(--spacing-3) var(--spacing-4);
496
- --button-medium-borderRadius: var(--radius-md);
497
-
498
- --button-large-height: var(--dimension-55px);
499
- --button-large-fontSize: var(--typography-fontSize-lg);
500
- --button-large-padding: var(--spacing-4) var(--spacing-5);
501
- --button-large-borderRadius: var(--radius-lg);
502
-
503
- /* Button Default State */
504
- --button-default-backgroundColor: var(--color-neutral-0);
505
- --button-default-borderColor: var(--color-neutral-300);
506
- --button-default-borderWidth: var(--border-width-1);
507
- --button-default-color: var(--color-neutral-900);
508
- --button-default-fontFamily: var(--typography-fontFamily-sans);
509
- --button-default-fontWeight: var(--typography-fontWeight-medium);
510
- --button-default-lineHeight: var(--typography-lineHeight-normal);
511
-
512
- /* Button Shared Tokens */
513
- --button-shared-fontFamily: var(--typography-fontFamily-sans);
514
- --button-shared-fontWeight: var(--typography-fontWeight-medium);
515
- --button-shared-lineHeight: var(--typography-lineHeight-tight);
516
- --button-shared-letterSpacing: var(--typography-letterSpacing-normal);
517
- --button-shared-borderWidth: var(--border-width-1);
518
- --button-shared-transition-properties: background-color, border-color, color,
519
- box-shadow;
520
- --button-shared-transition-duration: var(--transition-duration-normal);
521
- --button-shared-transition-easing: var(--transition-easing-smooth);
522
- --button-shared-focus-outline: var(--focus-outline-traditional);
523
- --button-shared-focus-outlineOffset: var(--focus-outline-offset);
524
- --button-shared-focus-boxShadow: var(--focus-outline-primary);
525
- --button-shared-disabled-opacity: 0.6;
526
- --button-shared-disabled-cursor: not-allowed;
527
-
528
- /* Button Size Tokens */
529
- --button-size-small-padding-vertical: var(--spacing-2);
530
- --button-size-small-padding-horizontal: var(--spacing-4);
531
- --button-size-small-fontSize: var(--typography-fontSize-sm);
532
- --button-size-small-height: var(--dimension-34px);
533
- --button-size-small-borderRadius: var(--radius-sm);
534
- --button-size-small-gap: var(--spacing-1);
535
-
536
- --button-size-medium-padding-vertical: var(--spacing-3);
537
- --button-size-medium-padding-horizontal: var(--spacing-5);
538
- --button-size-medium-fontSize: var(--typography-fontSize-base);
539
- --button-size-medium-height: var(--dimension-45px);
540
- --button-size-medium-borderRadius: var(--radius-md);
541
- --button-size-medium-gap: var(--spacing-2);
542
-
543
- --button-size-large-padding-vertical: var(--spacing-4);
544
- --button-size-large-padding-horizontal: var(--spacing-6);
545
- --button-size-large-fontSize: var(--typography-fontSize-lg);
546
- --button-size-large-height: var(--dimension-55px);
547
- --button-size-large-borderRadius: var(--radius-lg);
548
- --button-size-large-gap: var(--spacing-2);
549
-
550
- /* Button Primary State */
551
- --button-primary-background-default: var(--color-blue-500);
552
- --button-primary-text-default: var(--color-neutral-0);
553
- --button-primary-border-default: var(--color-blue-500);
554
- --button-primary-background-hover: var(--color-blue-600);
555
- --button-primary-border-hover: var(--color-blue-600);
556
- --button-primary-background-active: var(--color-blue-700);
557
- --button-primary-border-active: var(--color-blue-700);
558
- --button-primary-border-focus: var(--color-blue-500);
559
- --button-primary-background-disabled: var(--color-neutral-300);
560
- --button-primary-text-disabled: var(--color-neutral-500);
561
- --button-primary-border-disabled: var(--color-neutral-300);
562
-
563
- /* Button Secondary State */
564
- --button-secondary-background-default: var(--color-neutral-950);
565
- --button-secondary-text-default: var(--color-neutral-0);
566
- --button-secondary-border-default: var(--color-neutral-950);
567
- --button-secondary-background-hover: var(--color-neutral-900);
568
- --button-secondary-text-hover: var(--color-neutral-0);
569
- --button-secondary-border-hover: var(--color-neutral-900);
570
- --button-secondary-background-active: var(--color-neutral-800);
571
- --button-secondary-text-active: var(--color-neutral-0);
572
- --button-secondary-border-active: var(--color-neutral-800);
573
- --button-secondary-border-focus: var(--color-neutral-950);
574
- --button-secondary-background-disabled: var(--color-neutral-300);
575
- --button-secondary-text-disabled: var(--color-neutral-500);
576
- --button-secondary-border-disabled: var(--color-neutral-300);
577
-
578
- /* Button Tertiary Primary State */
579
- --button-tertiaryPrimary-background-default: transparent;
580
- --button-tertiaryPrimary-text-default: var(--color-blue-500);
581
- --button-tertiaryPrimary-border-default: var(--color-blue-500);
582
- --button-tertiaryPrimary-borderWidth: var(--border-width-2);
583
- --button-tertiaryPrimary-background-hover: var(--color-blue-50);
584
- --button-tertiaryPrimary-text-hover: var(--color-blue-500);
585
- --button-tertiaryPrimary-border-hover: var(--color-blue-500);
586
- --button-tertiaryPrimary-background-active: var(--color-blue-500);
587
- --button-tertiaryPrimary-text-active: var(--color-neutral-0);
588
- --button-tertiaryPrimary-border-active: var(--color-blue-500);
589
- --button-tertiaryPrimary-border-focus: var(--color-blue-500);
590
- --button-tertiaryPrimary-background-disabled: transparent;
591
- --button-tertiaryPrimary-text-disabled: var(--color-neutral-400);
592
- --button-tertiaryPrimary-border-disabled: var(--color-neutral-300);
593
-
594
- /* Button Tertiary Secondary State */
595
- --button-tertiarySecondary-background-default: transparent;
596
- --button-tertiarySecondary-text-default: var(--color-neutral-900);
597
- --button-tertiarySecondary-border-default: var(--color-neutral-900);
598
- --button-tertiarySecondary-borderWidth: var(--border-width-2);
599
- --button-tertiarySecondary-background-hover: var(--color-neutral-100);
600
- --button-tertiarySecondary-text-hover: var(--color-neutral-900);
601
- --button-tertiarySecondary-border-hover: var(--color-neutral-900);
602
- --button-tertiarySecondary-background-active: var(--color-neutral-900);
603
- --button-tertiarySecondary-text-active: var(--color-neutral-0);
604
- --button-tertiarySecondary-border-active: var(--color-neutral-900);
605
- --button-tertiarySecondary-border-focus: var(--color-neutral-900);
606
- --button-tertiarySecondary-background-disabled: transparent;
607
- --button-tertiarySecondary-text-disabled: var(--color-neutral-400);
608
- --button-tertiarySecondary-border-disabled: var(--color-neutral-300);
609
-
610
- /* Button CTA State */
611
- --button-cta-background-default: var(--color-red-500);
612
- --button-cta-text-default: var(--color-neutral-0);
613
- --button-cta-border-default: var(--color-red-500);
614
- --button-cta-background-hover: var(--color-red-600);
615
- --button-cta-border-hover: var(--color-red-600);
616
- --button-cta-background-active: var(--color-red-700);
617
- --button-cta-border-active: var(--color-red-700);
618
- --button-cta-border-focus: var(--color-red-500);
619
- --button-cta-background-disabled: var(--color-neutral-300);
620
- --button-cta-text-disabled: var(--color-neutral-500);
621
- --button-cta-border-disabled: var(--color-neutral-300);
622
-
623
- /* Button Empty State */
624
- --button-empty-background-default: var(--color-neutral-200);
625
- --button-empty-text-default: transparent;
626
- --button-empty-border-default: var(--color-neutral-200);
627
-
628
- /* Button Disabled State */
629
- --button-disabled-backgroundColor: var(--color-neutral-100);
630
- --button-disabled-borderColor: var(--color-neutral-300);
631
- --button-disabled-color: var(--color-neutral-500);
632
-
633
- /* Button Focus State */
634
- --button-focus-boxShadow: var(--shadow-focus-outline-blue);
635
-
636
- /* ================================
637
- COMPONENT TOKENS - ANNOTATION
638
- ================================ */
639
-
640
- /* Footnote Tokens */
641
- --footnote-reference-fontSize: 0.75em;
642
- --footnote-reference-fontWeight: var(--typography-fontWeight-normal);
643
- --footnote-reference-lineHeight: 1;
644
- --footnote-reference-verticalAlign: super;
645
- --footnote-reference-color: inherit;
646
- --footnote-reference-marginLeft: 0.1em;
647
- --footnote-reference-marginRight: 0.2em;
648
-
649
- /* Citation Tokens */
650
- --citation-reference-fontSize: inherit;
651
- --citation-reference-fontWeight: var(--typography-fontWeight-normal);
652
- --citation-reference-lineHeight: inherit;
653
- --citation-reference-color: var(--color-blue-600);
654
- --citation-reference-textDecoration: underline;
655
- --citation-reference-hover-color: var(--color-blue-700);
656
- --citation-reference-hover-textDecoration: none;
657
-
658
- /* Mathematical Notation Tokens */
659
- --math-superscript-fontSize: 0.75em;
660
- --math-superscript-fontWeight: var(--typography-fontWeight-normal);
661
- --math-superscript-lineHeight: 1;
662
- --math-superscript-verticalAlign: super;
663
- --math-superscript-marginLeft: 0.05em;
664
-
665
- --math-subscript-fontSize: 0.75em;
666
- --math-subscript-fontWeight: var(--typography-fontWeight-normal);
667
- --math-subscript-lineHeight: 1;
668
- --math-subscript-verticalAlign: sub;
669
- --math-subscript-marginLeft: 0.05em;
670
-
671
- /* ================================
672
- COMPONENT TOKENS - ICON
673
- ================================ */
674
-
675
- /* Icon Size Tokens */
676
- --icon-xs-size: var(--dimension-12px);
677
- --icon-sm-size: var(--dimension-16px);
678
- --icon-md-size: var(--dimension-20px);
679
- --icon-lg-size: var(--dimension-24px);
680
- --icon-xl-size: var(--dimension-32px);
681
- --icon-2xl-size: var(--dimension-48px);
682
- --icon-3xl-size: var(--dimension-64px);
683
-
684
- /* Icon Context Tokens */
685
- --icon-button-small-size: var(--dimension-16px);
686
- --icon-button-medium-size: var(--dimension-20px);
687
- --icon-button-large-size: var(--dimension-24px);
688
-
689
- --icon-form-small-size: var(--dimension-16px);
690
- --icon-form-medium-size: var(--dimension-20px);
691
- --icon-form-large-size: var(--dimension-24px);
692
-
693
- /* Icon State Tokens */
694
- --icon-default-color: var(--color-neutral-600);
695
- --icon-hover-color: var(--color-neutral-700);
696
- --icon-active-color: var(--color-neutral-800);
697
- --icon-disabled-color: var(--color-neutral-400);
698
-
699
- --icon-primary-color: var(--color-blue-500);
700
- --icon-primary-hover-color: var(--color-blue-600);
701
- --icon-primary-active-color: var(--color-blue-700);
702
-
703
- --icon-success-color: var(--color-green-500);
704
- --icon-warning-color: var(--color-yellow-500);
705
- --icon-error-color: var(--color-red-500);
706
-
707
- /* ================================
708
- CORE SPACING TOKENS
709
- ================================ */
710
-
711
- --spacing-0: 0;
712
- --spacing-1: 0.0625rem; /* 1px */
713
- --spacing-2: 0.125rem; /* 2px */
714
- --spacing-4: 0.25rem; /* 4px */
715
- --spacing-6: 0.375rem; /* 6px */
716
- --spacing-8: 0.5rem; /* 8px */
717
- --spacing-10: 0.625rem; /* 10px */
718
- --spacing-12: 0.75rem; /* 12px */
719
- --spacing-14: 0.875rem; /* 14px */
720
- --spacing-16: 1rem; /* 16px */
721
- --spacing-18: 1.125rem; /* 18px */
722
- --spacing-20: 1.25rem; /* 20px */
723
- --spacing-22: 1.375rem; /* 22px */
724
- --spacing-24: 1.5rem; /* 24px */
725
- --spacing-28: 1.75rem; /* 28px */
726
- --spacing-32: 2rem; /* 32px */
727
- --spacing-36: 2.25rem; /* 36px */
728
- --spacing-40: 2.5rem; /* 40px */
729
- --spacing-44: 2.75rem; /* 44px */
730
- --spacing-48: 3rem; /* 48px */
731
- --spacing-52: 3.25rem; /* 52px */
732
- --spacing-56: 3.5rem; /* 56px */
733
- --spacing-64: 4rem; /* 64px */
734
- --spacing-80: 5rem; /* 80px */
735
- --spacing-96: 6rem; /* 96px */
736
- --spacing-112: 7rem; /* 112px */
737
- --spacing-128: 8rem; /* 128px */
738
-
739
- /* =====================
740
- OLD VALUES -------------------------------------------------------------------------------
741
- ====================== */
742
-
743
- /* Display default */
744
- --display-xxsmall: 44px; /* 58.652px = 3.666rem */
745
- --display-xsmall: 48px; /* 63.984px = 3.999rem */
746
- --display-small: 52px; /* 69.316px = 4.332rem */
747
- --display-medium: 56px; /* 74.648px = 4.666rem */
748
- --display-large: 60px; /* 79.98px = 5rem */
749
- --display-xlarge: 64px; /* 85.312px = 5.333rem */
750
-
751
- /* Display mobile */
752
- --display-xxsmall-mobile: 34px; /* 45.322px = 2.833rem */
753
- --display-xsmall-mobile: 36px; /* 47.988px = 2.999rem */
754
- --display-small-mobile: 38px; /* 50.654px = 3.167rem */
755
- --display-medium-mobile: 40px; /* 53.32px = 3.333rem */
756
- --display-large-mobile: 44px; /* 58.652px = 3.666rem */
757
- --display-xlarge-mobile: 48px; /* 63.984px = 3.999rem */
758
-
759
- /* Heading default */
760
- --heading-xxsmall: 18px; /* 23.994px = 1.5rem */
761
- --heading-xsmall: 20px; /* 26.66px = 1.667rem */
762
- --typography-heading-h4-fontSize: 24px; /* 31.992px = 2rem */
763
- --heading-medium: 28px; /* 37.324px = 2.333rem */
764
- --typography-fontSize-3xl: 32px; /* 42.656px = 2.667rem */
765
- --heading-xlarge: 36px; /* 47.988px = 2.999rem */
766
- --heading-xxlarge: 40px; /* 53.32px = 3.333rem */
767
-
768
- /* Body default */
769
- --body-small: 13px; /* 17.329px = 1.083rem */
770
- --typography-body-small-fontSize: 14px; /* 18.662px = 1.167rem */
771
- --typography-body-regular-fontSize: 16px; /* 21.328px = 1.333rem */
772
- --body-xlarge: 18px; /* 23.994px = 1.5rem */
773
-
774
- /* Caption default */
775
- --typography-label-extra-small-fontSize: 11px; /* 14.663px = 0.917rem */
776
- --typography-label-small-fontSize: 12px; /* 15.996px = 1rem */
777
-
778
- /* Display Default */
779
- --display-xlarge-line-height: 1.1; /* For 60px */
780
- --display-medium-line-height: 1.15; /* For 52px */
781
-
782
- /* Display Mobile */
783
- --display-xlarge-mobile-line-height: 1.15; /* For 44px */
784
- --display-medium-mobile-line-height: 1.2; /* For 38px */
785
-
786
- /* Heading */
787
- --heading-xlarge-line-height: 1.2; /* For 36px */
788
- --typography-heading-h4-fontSize-line-height: 1.3; /* For 24px */
789
-
790
- /* Body */
791
- --typography-body-regular-fontSize-line-height: 1.5; /* For 16px */
792
-
793
- /* Caption */
794
- --typography-label-small-fontSize-line-height: 1.35; /* For 12px */
795
-
796
- /* Spacing Tokens
797
- -----------------------------------------------*/
798
- /* Base spacing tokens - Based on 4px grid */
799
- --space-none: 0;
800
- --space-4xs: 0.125rem; /* 2px */
801
- --space-3xs: 0.25rem; /* 4px */
802
- --space-2xs: 0.5rem; /* 8px */
803
- --space-xs: 0.75rem; /* 12px */
804
- --space-sm: 1rem; /* 16px */
805
- --space-md: 1.5rem; /* 24px */
806
- --space-lg: 2rem; /* 32px */
807
- --space-xl: 2.5rem; /* 40px */
808
- --space-2xl: 3rem; /* 48px */
809
- --space-3xl: 4rem; /* 64px */
810
- --space-4xl: 6rem; /* 96px */
811
- --space-5xl: 8rem; /* 128px */
812
-
813
- /* Semantic Padding Tokens */
814
- --padding-button: var(--space-xs) var(--space-md);
815
- --padding-input: var(--space-xs);
816
- --padding-card: var(--space-md);
817
- --padding-card-sm: var(--space-sm);
818
- --padding-card-lg: var(--space-lg);
819
-
820
- --padding-section: var(--space-3xl) 0;
821
- --padding-section-sm: var(--space-2xl) 0;
822
- --padding-section-lg: var(--space-4xl) 0;
823
-
824
- /* Container and Layout Tokens */
825
- --container-padding: var(--space-md);
826
- --container-padding-sm: var(--space-sm);
827
- --container-padding-lg: var(--space-lg);
828
-
829
- /* Inset (Padding All Sides) Tokens */
830
- --inset-xs: var(--space-xs);
831
- --inset-sm: var(--space-sm);
832
- --inset-md: var(--space-md);
833
- --inset-lg: var(--space-lg);
834
-
835
- /* Stack (Vertical Spacing) Tokens */
836
- --stack-xs: var(--space-xs);
837
- --stack-sm: var(--space-sm);
838
- --stack-md: var(--space-md);
839
- --stack-lg: var(--space-lg);
840
- --stack-xl: var(--space-xl);
841
-
842
- /* Inline (Horizontal Spacing) Tokens */
843
- --inline-xs: var(--space-xs);
844
- --inline-sm: var(--space-sm);
845
- --inline-md: var(--space-md);
846
- --inline-lg: var(--space-lg);
847
-
848
- /* Accessibility Spacing Tokens
849
- -----------------------------------------------*/
850
- /* Touch Target Sizes - WCAG 2.1 Success Criterion 2.5.5 (AAA) and 2.5.8 (AA) */
851
- --touch-target-size: 44px; /* Minimum touch target size (44px × 44px) */
852
- --touch-target-spacing: 8px; /* Minimum space between touch targets */
853
-
854
- /* Readable Line Lengths - For optimal readability */
855
- --content-width-readable: 70ch; /* Approximately 70 characters per line */
856
- --content-width-max: 1200px; /* Maximum overall content width */
857
-
858
- /** GRID TOKENS
859
- */
860
- /* Grid container max widths */
861
- --grid-container-max-xs: 100%; /* mobile full width */
862
- --grid-container-max-sm: 540px;
863
- --grid-container-max-md: 720px;
864
- --grid-container-max-lg: 960px;
865
- --grid-container-max-xl: 1140px;
866
- --grid-container-max-xxl: 1320px;
867
-
868
- /* Column count (usually 12) */
869
- --grid-columns: 12;
870
-
871
- /* Gutter spacing between columns */
872
- --grid-gutter-xs: 16px;
873
- --grid-gutter-sm: 24px;
874
- --grid-gutter-md: 32px;
875
- --grid-gutter-lg: 40px;
876
-
877
- /* Container padding (horizontal spacing) */
878
- --grid-padding-xs: 16px;
879
- --grid-padding-sm: 24px;
880
- --grid-padding-md: 32px;
881
- --grid-padding-lg: 40px;
882
-
883
- /* Breakpoints */
884
- --breakpoint-xs: 0px;
885
- --breakpoint-sm: 576px;
886
- --breakpoint-md: 768px;
887
- --breakpoint-lg: 992px;
888
- --breakpoint-xl: 1200px;
889
- --breakpoint-xxl: 1400px;
890
- /* =====================
891
- FONT-FACE DEFINITIONS
892
- ====================== */
893
-
894
- @font-face {
895
- font-family: "IBM Plex Mono";
896
- font-style: normal;
897
- font-weight: 700;
898
- src: url("/assets/fonts/IBMPlexMono-Bold.woff2") format("woff2");
899
- }
900
- @font-face {
901
- font-family: "IBM Plex Mono";
902
- font-style: normal;
903
- font-weight: 700;
904
- src: url("/assets/fonts/IBMPlexMono-BoldItalic.woff2") format("woff2");
905
- }
906
-
907
- @font-face {
908
- font-family: "IBM Plex Mono";
909
- font-style: italic;
910
- font-weight: 300;
911
- src: url("/assets/fonts/IBMPlexMono-Italic.woff2") format("woff2");
912
- }
913
- @font-face {
914
- font-family: "IBM Plex Mono";
915
- font-style: normal;
916
- font-weight: 300;
917
- src: url("/assets/fonts/IBMPlexMono-Light.woff2") format("woff2");
918
- }
919
- @font-face {
920
- font-family: "IBM Plex Mono";
921
- font-style: italic;
922
- font-weight: 300;
923
- src: url("/assets/fonts/IBMPlexMono-LightItalic.woff2") format("woff2");
924
- }
925
-
926
- @font-face {
927
- font-family: "IBM Plex Mono";
928
- font-style: italic;
929
- font-weight: 500;
930
- src: url("/assets/fonts/IBMPlexMono-Medium.woff2") format("woff2");
931
- }
932
- @font-face {
933
- font-family: "IBM Plex Mono";
934
- font-style: italic;
935
- font-weight: 500;
936
- src: url("/assets/fonts/IBMPlexMono-MediumItalic.woff2") format("woff2");
937
- }
938
- @font-face {
939
- font-family: "IBM Plex Mono";
940
- font-style: italic;
941
- font-weight: 400;
942
- src: url("/assets/fonts/IBMPlexMono-Regular.woff2") format("woff2");
943
- }
944
- @font-face {
945
- font-family: "IBM Plex Mono";
946
- font-style: italic;
947
- font-weight: 600;
948
- src: url("/assets/fonts/IBMPlexMono-SemiBold.woff2") format("woff2");
949
- }
950
- @font-face {
951
- font-family: "IBM Plex Mono";
952
- font-style: italic;
953
- font-weight: 600;
954
- src: url("/assets/fonts/IBMPlexMono-SemiBoldItalic.woff2") format("woff2");
955
- }
956
-
957
- /*
958
- IBM PLEX SANS
959
- */
960
-
961
- @font-face {
962
- font-family: "IBMPlexSans";
963
- font-style: normal;
964
- font-weight: 700;
965
- src: url("/assets/fonts/IBMPlexSans-Bold.woff2") format("woff2");
966
- }
967
- @font-face {
968
- font-family: "IBMPlexSans";
969
- font-style: normal;
970
- font-weight: 700;
971
- src: url("/assets/fonts/IBMPlexSans-BoldItalic.woff2") format("woff2");
972
- }
973
-
974
- @font-face {
975
- font-family: "IBMPlexSans";
976
- font-style: italic;
977
- font-weight: 300;
978
- src: url("/assets/fonts/IBMPlexSans-Italic.woff2") format("woff2");
979
- }
980
- @font-face {
981
- font-family: "IBMPlexSans";
982
- font-style: normal;
983
- font-weight: 300;
984
- src: url("/assets/fonts/IBMPlexSans-Light.woff2") format("woff2");
985
- }
986
- @font-face {
987
- font-family: "IBMPlexSans";
988
- font-style: italic;
989
- font-weight: 300;
990
- src: url("/assets/fonts/IBMPlexSans-LightItalic.woff2") format("woff2");
926
+ --typography-label-extra-small-fontWeight: var(--typography-fontWeight-medium);
927
+ --typography-label-extra-small-lineHeight: var(--typography-lineHeight-normal);
928
+ --typography-label-extra-small-letterSpacing: var(--typography-letterSpacing-wide);
929
+ --typography-label-extra-small-fontFamily: var(--typography-fontFamily-sans);
930
+
931
+ /* Deliberately size-only: bd-p variant=xsmall composes it with
932
+ body-small's weight, leading and tracking, so giving it axes of its
933
+ own would create a second answer to those questions.
934
+
935
+ It lives in the body family, not the label one. It was
936
+ --typography-label-xsmall-fontSize, one character away from
937
+ label-extra-small, which is a complete 11px role with a weight, a
938
+ leading and a family. Two names that close, describing things that
939
+ different, is a trap: one is a role you can ask for and the other is
940
+ a bare size that matches any one-axis 12px declaration on size
941
+ alone. Naming it for the component that owns it says which is
942
+ which. */
943
+ --typography-body-xsmall-fontSize: var(--typography-fontSize-xs);
944
+
945
+ --typography-label-large-fontSize: var(--typography-fontSize-base);
946
+ --typography-label-large-fontWeight: var(--typography-fontWeight-medium);
947
+ --typography-label-large-lineHeight: var(--typography-lineHeight-normal);
948
+ --typography-label-large-letterSpacing: var(
949
+ --typography-letterSpacing-normal
950
+ );
951
+ --typography-label-large-fontFamily: var(--typography-fontFamily-sans);
952
+
953
+ /* Control Label Tokens
954
+
955
+ label-* at control leading. Every label-* rung is lineHeight-normal
956
+ (1.5); a control -- a badge, a button -- needs 1.25 so its box can be
957
+ padding-driven without the line box forcing it taller.
958
+ scripts/typography-pairings.json already records 16px at 1.25 as
959
+ physically valid "because control text needs it", and rule 8 says
960
+ that file is a technical boundary rather than authorization, so the
961
+ authorization is here: this is the role that means "a label on a
962
+ control".
963
+
964
+ Motivated by badge.css.js and button.css.js's .bd-contact-btn, which
965
+ each arrived independently at medium + tight and had no role to ask
966
+ for. The three rungs mirror label-small / label-default /
967
+ label-large step for step. The one place they do not mirror is
968
+ tracking on the small rung: label-small is letterSpacing-wide, but
969
+ badge -- the atom this rung exists for -- renders normal, so the rung
970
+ describes its consumer rather than its twin. Everywhere else the only
971
+ axis that differs from the label-* rung of the same name is the
972
+ leading. */
973
+ --typography-control-label-small-fontSize: var(--typography-fontSize-xs);
974
+ --typography-control-label-small-fontWeight: var(--typography-fontWeight-medium);
975
+ --typography-control-label-small-lineHeight: var(--typography-lineHeight-tight);
976
+ --typography-control-label-small-letterSpacing: var(--typography-letterSpacing-normal);
977
+ --typography-control-label-small-fontFamily: var(--typography-fontFamily-sans);
978
+
979
+ --typography-control-label-default-fontSize: var(--typography-fontSize-sm);
980
+ --typography-control-label-default-fontWeight: var(--typography-fontWeight-medium);
981
+ --typography-control-label-default-lineHeight: var(--typography-lineHeight-tight);
982
+ --typography-control-label-default-letterSpacing: var(--typography-letterSpacing-normal);
983
+ --typography-control-label-default-fontFamily: var(--typography-fontFamily-sans);
984
+
985
+ --typography-control-label-large-fontSize: var(--typography-fontSize-base);
986
+ --typography-control-label-large-fontWeight: var(--typography-fontWeight-medium);
987
+ --typography-control-label-large-lineHeight: var(--typography-lineHeight-tight);
988
+ --typography-control-label-large-letterSpacing: var(--typography-letterSpacing-normal);
989
+ --typography-control-label-large-fontFamily: var(--typography-fontFamily-sans);
990
+
991
+ /* The rung label-xl used to occupy. label-xl was lg/medium/normal and
992
+ documented in vertical-rhythm.stories.js as "the name of a large
993
+ control" -- the same job this family names, but at label leading
994
+ rather than control leading, and with no consumer in the package.
995
+ Retired in favour of this. Note it was byte-identical to heading-h6,
996
+ which stays: that pair was two questions with coincidentally equal
997
+ answers, and heading-h6 is the one bd-h actually renders. */
998
+ --typography-control-label-xl-fontSize: var(--typography-fontSize-lg);
999
+ --typography-control-label-xl-fontWeight: var(--typography-fontWeight-medium);
1000
+ --typography-control-label-xl-lineHeight: var(--typography-lineHeight-tight);
1001
+ --typography-control-label-xl-letterSpacing: var(--typography-letterSpacing-normal);
1002
+ --typography-control-label-xl-fontFamily: var(--typography-fontFamily-sans);
1003
+
1004
+ /* Caption Tokens */
1005
+ --typography-caption-default-fontSize: var(--typography-fontSize-xs);
1006
+ --typography-caption-default-fontWeight: var(--typography-fontWeight-normal);
1007
+ --typography-caption-default-lineHeight: var(--typography-lineHeight-normal);
1008
+ --typography-caption-default-letterSpacing: var(
1009
+ --typography-letterSpacing-normal
1010
+ );
1011
+ --typography-caption-default-fontFamily: var(--typography-fontFamily-sans);
1012
+ --typography-caption-default-color: var(--color-text-muted);
1013
+
1014
+ --typography-caption-small-fontSize: var(--typography-fontSize-xs);
1015
+ --typography-caption-small-fontWeight: var(--typography-fontWeight-normal);
1016
+ --typography-caption-small-lineHeight: var(--typography-lineHeight-normal);
1017
+ --typography-caption-small-letterSpacing: var(
1018
+ --typography-letterSpacing-wide
1019
+ );
1020
+ --typography-caption-small-fontFamily: var(--typography-fontFamily-sans);
1021
+
1022
+ /* Link Tokens */
1023
+ --typography-link-default-fontSize: inherit;
1024
+ --typography-link-default-fontWeight: var(--typography-fontWeight-normal);
1025
+ --typography-link-default-lineHeight: inherit;
1026
+ --typography-link-default-letterSpacing: inherit;
1027
+ --typography-link-default-fontFamily: inherit;
1028
+ --typography-link-default-textDecoration-default: underline;
1029
+ --typography-link-default-textDecoration-hover: none;
1030
+ /* The gap between the text and its underline. It was spelled as a 2px
1031
+ literal in seven places in bd-link, on a property the length rule
1032
+ does not check, so nothing could see it and nothing could change it
1033
+ in one move. */
1034
+ --typography-link-underlineOffset: var(--spacing-2);
1035
+ --typography-link-underlineThickness: var(--border-width-2);
1036
+
1037
+ --typography-link-standalone-fontSize: var(--typography-fontSize-base);
1038
+ --typography-link-standalone-fontWeight: var(--typography-fontWeight-medium);
1039
+ --typography-link-standalone-lineHeight: var(--typography-lineHeight-normal);
1040
+ --typography-link-standalone-letterSpacing: var(
1041
+ --typography-letterSpacing-normal
1042
+ );
1043
+ --typography-link-standalone-fontFamily: var(--typography-fontFamily-sans);
1044
+ --typography-link-standalone-textDecoration-default: underline;
1045
+ --typography-link-standalone-textDecoration-hover: none;
1046
+
1047
+ /* Code Tokens */
1048
+ --typography-code-inline-fontSize: 0.875em;
1049
+ --typography-code-inline-fontWeight: var(--typography-fontWeight-normal);
1050
+ --typography-code-inline-lineHeight: inherit;
1051
+ --typography-code-inline-letterSpacing: var(
1052
+ --typography-letterSpacing-normal
1053
+ );
1054
+ --typography-code-inline-fontFamily: var(--typography-fontFamily-mono);
1055
+
1056
+ --typography-code-block-fontSize: var(--typography-fontSize-sm);
1057
+ --typography-code-block-fontWeight: var(--typography-fontWeight-normal);
1058
+ --typography-code-block-lineHeight: var(--typography-lineHeight-relaxed);
1059
+ --typography-code-block-letterSpacing: var(--typography-letterSpacing-normal);
1060
+ --typography-code-block-fontFamily: var(--typography-fontFamily-mono);
1061
+
1062
+ /* Display Typography Tokens */
1063
+ --typography-display-3xl-fontSize: var(--typography-fontSize-9xl);
1064
+ --typography-display-3xl-fontWeight: var(--typography-fontWeight-bold);
1065
+ --typography-display-3xl-lineHeight: var(--typography-lineHeight-tight);
1066
+ --typography-display-3xl-letterSpacing: var(--typography-letterSpacing-tight);
1067
+ --typography-display-3xl-fontFamily: var(--typography-fontFamily-sans);
1068
+
1069
+ --typography-display-2xl-fontSize: var(--typography-fontSize-8xl);
1070
+ --typography-display-2xl-fontWeight: var(--typography-fontWeight-bold);
1071
+ --typography-display-2xl-lineHeight: var(--typography-lineHeight-tight);
1072
+ --typography-display-2xl-letterSpacing: var(--typography-letterSpacing-tight);
1073
+ --typography-display-2xl-fontFamily: var(--typography-fontFamily-sans);
1074
+
1075
+ --typography-display-xl-fontSize: var(--typography-fontSize-7xl);
1076
+ --typography-display-xl-fontWeight: var(--typography-fontWeight-bold);
1077
+ --typography-display-xl-lineHeight: var(--typography-lineHeight-tight);
1078
+ --typography-display-xl-letterSpacing: var(--typography-letterSpacing-tight);
1079
+ --typography-display-xl-fontFamily: var(--typography-fontFamily-sans);
1080
+
1081
+ --typography-display-lg-fontSize: var(--typography-fontSize-6xl);
1082
+ --typography-display-lg-fontWeight: var(--typography-fontWeight-bold);
1083
+ --typography-display-lg-lineHeight: var(--typography-lineHeight-tight);
1084
+ --typography-display-lg-letterSpacing: var(--typography-letterSpacing-tight);
1085
+ --typography-display-lg-fontFamily: var(--typography-fontFamily-sans);
1086
+
1087
+ /* fluid: 30px at 320 -> 48px at 992. (48-30)/6.72=2.6786vw, (30-(48-30)/2.1)/16=1.33929rem */
1088
+ --typography-display-md-fontSizeMin: 1.875rem; /* 30px */
1089
+ --typography-display-md-fontSize: clamp(
1090
+ var(--typography-display-md-fontSizeMin),
1091
+ calc(1.33929rem + 2.6786vw),
1092
+ var(--typography-fontSize-5xl)
1093
+ );
1094
+ --typography-display-md-fontWeight: var(--typography-fontWeight-bold);
1095
+ --typography-display-md-lineHeight: var(--typography-lineHeight-tight);
1096
+ --typography-display-md-letterSpacing: var(--typography-letterSpacing-tight);
1097
+ --typography-display-md-fontFamily: var(--typography-fontFamily-sans);
1098
+
1099
+ /* fluid: 30px at 320 -> 36px at 992. (36-30)/6.72=0.8929vw, (30-(36-30)/2.1)/16=1.69643rem */
1100
+ --typography-display-sm-fontSizeMin: 1.875rem; /* 30px */
1101
+ --typography-display-sm-fontSize: clamp(
1102
+ var(--typography-display-sm-fontSizeMin),
1103
+ calc(1.69643rem + 0.8929vw),
1104
+ var(--typography-fontSize-4xl)
1105
+ );
1106
+ --typography-display-sm-fontWeight: var(--typography-fontWeight-bold);
1107
+ --typography-display-sm-lineHeight: var(--typography-lineHeight-tight);
1108
+ --typography-display-sm-letterSpacing: var(--typography-letterSpacing-tight);
1109
+ --typography-display-sm-fontFamily: var(--typography-fontFamily-sans);
1110
+
1111
+ /* ================================
1112
+ COMPONENT TOKENS - FORM
1113
+ ================================ */
1114
+
1115
+ /* Form Label Tokens */
1116
+ --form-label-default-fontSize: var(--typography-fontSize-sm);
1117
+ --form-label-default-fontWeight: var(--typography-fontWeight-medium);
1118
+ --form-label-default-lineHeight: var(--typography-lineHeight-normal);
1119
+ --form-label-default-letterSpacing: var(--typography-letterSpacing-normal);
1120
+ --form-label-default-fontFamily: var(--typography-fontFamily-sans);
1121
+ --form-label-default-color: var(--color-text-primary);
1122
+ --form-label-default-marginBottom: var(--spacing-4);
1123
+
1124
+ --form-label-large-fontSize: var(--typography-fontSize-lg);
1125
+ --form-label-large-fontWeight: var(--typography-fontWeight-medium);
1126
+ --form-label-large-lineHeight: var(--typography-lineHeight-normal);
1127
+ --form-label-large-letterSpacing: var(--typography-letterSpacing-normal);
1128
+ --form-label-large-fontFamily: var(--typography-fontFamily-sans);
1129
+ --form-label-large-color: var(--color-text-primary);
1130
+ --form-label-large-marginBottom: var(--spacing-8);
1131
+
1132
+ --form-label-small-fontSize: var(--typography-fontSize-xs);
1133
+ --form-label-small-fontWeight: var(--typography-fontWeight-medium);
1134
+ --form-label-small-lineHeight: var(--typography-lineHeight-normal);
1135
+ --form-label-small-letterSpacing: var(--typography-letterSpacing-wide);
1136
+ --form-label-small-fontFamily: var(--typography-fontFamily-sans);
1137
+ --form-label-small-color: var(--color-text-primary);
1138
+ --form-label-small-marginBottom: var(--spacing-4);
1139
+
1140
+ --form-label-required-color: var(--status-error-accent);
1141
+ --form-label-required-marginLeft: var(--spacing-4);
1142
+
1143
+ /* Form Input Tokens */
1144
+
1145
+ /* The height of a control is derived, not chosen: padding, type step and
1146
+ line-height, the same three bd-button derives its own height from.
1147
+ That derivation is what keeps a field and a button of the same size
1148
+ the same height on one row of a form.
1149
+
1150
+ These three said --dimension-36/44/56 and stated a height the system
1151
+ does not draw. A small field renders 33.5px and a large one 54.5px;
1152
+ only medium agreed, and it agreed by coincidence. Nothing read them,
1153
+ so nothing surfaced the disagreement -- which is the argument for
1154
+ spelling the derivation here rather than a rounder number, and for
1155
+ shared/form-field.css.js reading these instead of repeating the calc
1156
+ three times. Changing them changes no pixel; it changes what the
1157
+ package tells a consumer the height is.
1158
+
1159
+ The line box these leave is 2px taller than the content box, because
1160
+ the derivation counts padding but not the 1px border on each edge.
1161
+ Measured at every size: no glyph clips, because an input centres its
1162
+ line and paints into the padding. Correcting it would move a field
1163
+ off its button, so it stays a recorded fact rather than a fix. */
1164
+ --form-input-small-height: calc(
1165
+ var(--spacing-8) * 2 + var(--typography-fontSize-sm) * var(--typography-lineHeight-tight)
1166
+ );
1167
+ --form-input-small-fontSize: var(--typography-fontSize-sm);
1168
+ --form-input-small-padding: var(--spacing-8) var(--spacing-12);
1169
+ --form-input-small-borderRadius: var(--radius-sm);
1170
+
1171
+ --form-input-medium-height: calc(
1172
+ var(--spacing-12) * 2 + var(--typography-fontSize-base) * var(--typography-lineHeight-tight)
1173
+ );
1174
+ --form-input-medium-fontSize: var(--typography-fontSize-base);
1175
+ --form-input-medium-padding: var(--spacing-12) var(--spacing-16);
1176
+ --form-input-medium-borderRadius: var(--radius-md);
1177
+
1178
+ --form-input-large-height: calc(
1179
+ var(--spacing-16) * 2 + var(--typography-fontSize-lg) * var(--typography-lineHeight-tight)
1180
+ );
1181
+ --form-input-large-fontSize: var(--typography-fontSize-lg);
1182
+ --form-input-large-padding: var(--spacing-16) var(--spacing-20);
1183
+ --form-input-large-borderRadius: var(--radius-lg);
1184
+
1185
+ --form-input-default-backgroundColor: var(--color-surface-default);
1186
+ --form-input-default-borderColor: var(--color-border-default);
1187
+ --form-input-default-borderWidth: var(--border-width-1);
1188
+ --form-input-default-color: var(--color-text-primary);
1189
+ --form-input-default-fontFamily: var(--typography-fontFamily-sans);
1190
+ /* There is deliberately no --form-input-default-lineHeight. There was
1191
+ one, it said normal (1.5), it had no consumer, and it described the
1192
+ opposite of what the control does: form-field.css.js sets tight and
1193
+ records why -- at normal the line box stood taller than the content
1194
+ box the derived height leaves, and the select clipped the descenders
1195
+ of its own option text.
1196
+
1197
+ It is not restored as tight either. The control's height is
1198
+ DERIVED from padding, type step and this leading, so exposing the
1199
+ leading as a component token would let a consuming page change the
1200
+ height by setting something that reads like a type preference. The
1201
+ primitive is used at the one site that needs it, with its reason on
1202
+ the line, which is what keeps the box and the text unable to
1203
+ disagree. */
1204
+
1205
+ --form-input-focus-borderColor: var(--color-border-brand);
1206
+ --form-input-focus-boxShadow: var(--shadow-focus-outline-blue);
1207
+
1208
+ --form-input-error-backgroundColor: var(--status-error-surface);
1209
+ --form-input-error-borderColor: var(--status-error-accent);
1210
+ --form-input-error-placeholderColor: var(--color-red-600);
1211
+
1212
+ --form-input-success-backgroundColor: var(--status-success-surface);
1213
+ --form-input-success-borderColor: var(--color-green-600);
1214
+ --form-input-success-placeholderColor: var(--color-green-700);
1215
+
1216
+ --form-input-disabled-backgroundColor: var(--color-surface-disabled);
1217
+ --form-input-disabled-borderColor: var(--color-border-disabled);
1218
+ --form-input-disabled-color: var(--color-text-subtle);
1219
+ --form-input-disabled-placeholderColor: var(--color-neutral-400);
1220
+
1221
+ /* Form Help Text Tokens */
1222
+ --form-help-text-default-fontSize: var(--typography-fontSize-xs);
1223
+ --form-help-text-default-fontWeight: var(--typography-fontWeight-normal);
1224
+ --form-help-text-default-lineHeight: var(--typography-lineHeight-normal);
1225
+ --form-help-text-default-letterSpacing: var(
1226
+ --typography-letterSpacing-normal
1227
+ );
1228
+ --form-help-text-default-fontFamily: var(--typography-fontFamily-sans);
1229
+ --form-help-text-default-color: var(--color-text-muted);
1230
+ --form-help-text-default-marginTop: var(--spacing-4);
1231
+
1232
+ /* Measured against the tint the field itself takes in each state, not
1233
+ against white — that is the background this text actually sits
1234
+ beside. red-600 on red-50 is 4.92 and needs nothing.
1235
+
1236
+ success was green-700, which is 4.75 on white but only 4.51 on
1237
+ green-50: passing by a hundredth, and the kind of margin that stops
1238
+ passing the moment a tint moves. green-800 is 6.42 there, and is
1239
+ already the step --color-text-success names for this role. */
1240
+ --form-help-text-error-color: var(--status-error-accent);
1241
+ --form-help-text-success-color: var(--color-text-success);
1242
+
1243
+ /* Form Layout Tokens
1244
+
1245
+ These were written against a step-indexed spacing scale, where the
1246
+ number is the position on the scale, and never converted when the
1247
+ scale became pixel-named, where the number is the value. So
1248
+ --spacing-6 stopped meaning "the sixth step, 24px" and started
1249
+ meaning 6px, silently — every token still resolved, and the lint has
1250
+ no way to see it.
1251
+
1252
+ bd-fieldset consumes fieldSpacing, so a form built from it has been
1253
+ stacking its fields 6px apart. Decoded as indices these read 24 and
1254
+ 32, which is what a form actually wants and what the value is set to
1255
+ here. */
1256
+ --form-fieldSpacing: var(--spacing-24);
1257
+ --form-sectionSpacing: var(--spacing-32);
1258
+ --form-labelSpacing: var(--spacing-4);
1259
+ --form-helpTextSpacing: var(--spacing-4);
1260
+
1261
+ /* ================================
1262
+ COMPONENT TOKENS - BUTTON
1263
+ ================================ */
1264
+
1265
+ /* Button Size Tokens */
1266
+ /* One size family. There were two — this one and --button-size-*, with
1267
+ different padding in each and neither matching what the component
1268
+ rendered. bd-button reads these.
1269
+
1270
+ No -height. The component derives its height from padding, type step
1271
+ and line-height rather than pinning it, which is what keeps it equal
1272
+ to a field of the same size; a height token here would be a second
1273
+ answer that could disagree. */
1274
+ --button-small-fontSize: var(--typography-fontSize-sm);
1275
+ --button-small-padding: var(--spacing-8) var(--spacing-16);
1276
+ --button-small-gap: var(--spacing-4);
1277
+ --button-small-borderRadius: var(--radius-sm);
1278
+
1279
+ --button-medium-fontSize: var(--typography-fontSize-base);
1280
+ --button-medium-padding: var(--spacing-12) var(--spacing-24);
1281
+ --button-medium-gap: var(--spacing-8);
1282
+ --button-medium-borderRadius: var(--radius-md);
1283
+
1284
+ --button-large-fontSize: var(--typography-fontSize-lg);
1285
+ --button-large-padding: var(--spacing-16) var(--spacing-32);
1286
+ --button-large-gap: var(--spacing-8);
1287
+ --button-large-borderRadius: var(--radius-lg);
1288
+
1289
+ /* Button Default State */
1290
+ --button-default-backgroundColor: var(--color-neutral-0);
1291
+ --button-default-borderColor: var(--color-neutral-400);
1292
+ --button-default-borderWidth: var(--border-width-1);
1293
+ --button-default-color: var(--color-neutral-900);
1294
+ --button-default-fontFamily: var(--typography-fontFamily-sans);
1295
+ --button-default-fontWeight: var(--typography-fontWeight-medium);
1296
+ --button-default-lineHeight: var(--typography-lineHeight-normal);
1297
+
1298
+ /* Button Shared Tokens */
1299
+ --button-shared-fontFamily: var(--typography-fontFamily-sans);
1300
+ --button-shared-fontWeight: var(--typography-fontWeight-medium);
1301
+ --button-shared-lineHeight: var(--typography-lineHeight-tight);
1302
+ --button-shared-letterSpacing: var(--typography-letterSpacing-normal);
1303
+ --button-shared-borderWidth: var(--border-width-1);
1304
+ --button-shared-transition-properties: background-color, border-color, color,
1305
+ box-shadow;
1306
+ --button-shared-transition-duration: var(--transition-duration-normal);
1307
+ --button-shared-transition-easing: var(--transition-easing-smooth);
1308
+ --button-shared-focus-outline: var(--focus-outline-traditional);
1309
+ --button-shared-focus-outlineOffset: var(--focus-outline-offset);
1310
+ --button-shared-focus-boxShadow: var(--focus-outline-primary);
1311
+ --button-shared-disabled-opacity: 0.6;
1312
+ --button-shared-disabled-cursor: not-allowed;
1313
+
1314
+ /* ---- variant colours -------------------------------------------
1315
+ Named for the kind attribute they serve, because that is the public
1316
+ vocabulary: primary, secondary, tertiary, ghost, accent, white and
1317
+ outline-white. They used to be named tertiaryPrimary,
1318
+ tertiarySecondary and cta, which no consumer could map onto the
1319
+ component without reading its source.
1320
+
1321
+ bd-button aliases each of these onto a --button-*-bg property on its
1322
+ own :host, so there are two override points and they do different
1323
+ jobs: set the token on :root to move every button in the document,
1324
+ or the alias on the bd-button element to move one. The alias is also what
1325
+ surface="dark" switches, which is why the component keeps it.
1326
+
1327
+ Every value here is what the component already renders. The old
1328
+ values had drifted apart from it in four places — secondary's hover
1329
+ and active, tertiary's hover border and ghost's active fill — so
1330
+ wiring them up unchanged would have moved pixels.
1331
+
1332
+ The per-variant -focus and -disabled sets are gone. The component
1333
+ draws one focus ring for every variant, from --focus-outline-primary,
1334
+ and one shared disabled treatment; thirty tokens described per-variant
1335
+ versions of both that nothing rendered. --button-empty-* went with
1336
+ them: there is no empty kind. */
1337
+
1338
+ /* primary: blue fill */
1339
+ --button-primary-background-default: var(--color-action-primary);
1340
+ --button-primary-background-hover: var(--color-action-primary-hover);
1341
+ --button-primary-background-active: var(--color-action-primary-active);
1342
+ --button-primary-text-default: var(--color-action-on-fill);
1343
+
1344
+ /* secondary: near-black fill */
1345
+ --button-secondary-background-default: var(--color-action-secondary);
1346
+ --button-secondary-background-hover: var(--color-action-secondary-hover);
1347
+ --button-secondary-background-active: var(--color-action-secondary-active);
1348
+ --button-secondary-text-default: var(--color-action-on-fill);
1349
+
1350
+ /* tertiary: blue outline. text-hover is blue-600, not blue-500: on the
1351
+ blue-50 hover fill the lighter step measures 4.20:1 and fails 1.4.3,
1352
+ where blue-600 gives 5.72.
1353
+ .
1354
+ text-default is blue-600 for the same reason, applied to the state a
1355
+ reader actually sits in. The line above fixed hover, where blue-500
1356
+ failed outright, and left the resting state on blue-500 at 4.53:1 --
1357
+ passing 4.5 by 0.03 on pure white and failing on any tint, which is
1358
+ the margin CLAUDE.md says is not real. Both states now name the same
1359
+ ink role, and the role is the category-correct one: --color-action-primary
1360
+ is an interaction role for fills, not ink, and it was being read by a
1361
+ color: property. Measured 4.53:1 -> 6.18:1 on all six consumers.
1362
+ The ring is deliberately NOT changed here and stays blue-500: it is
1363
+ non-text UI at a 3:1 bar, it passes, and moving it would mean naming a
1364
+ blue-600 border role that does not exist. See the plan's backlog. */
1365
+ --button-tertiary-text-default: var(--color-text-brand);
1366
+ --button-tertiary-border-default: var(--color-border-brand);
1367
+ --button-tertiary-background-hover: var(--color-surface-info);
1368
+ --button-tertiary-text-hover: var(--color-text-brand);
1369
+ --button-tertiary-border-hover: var(--color-action-primary-hover);
1370
+ --button-tertiary-background-active: var(--color-action-primary);
1371
+ --button-tertiary-text-active: var(--color-action-on-fill);
1372
+
1373
+ /* ghost: dark outline */
1374
+ --button-ghost-text-default: var(--color-text-primary);
1375
+ --button-ghost-border-default: var(--color-border-strong);
1376
+ --button-ghost-background-hover: var(--color-surface-muted);
1377
+ --button-ghost-text-hover: var(--color-text-primary);
1378
+ --button-ghost-background-active: var(--color-action-secondary);
1379
+ --button-ghost-text-active: var(--color-action-on-fill);
1380
+
1381
+ /* accent: red fill. This system's conversion colour — Buy now and the
1382
+ like — not a danger signal; there is deliberately no danger variant.
1383
+ red-600, not red-500: white on red-500 measures 4.00:1 and fails. */
1384
+ --button-accent-background-default: var(--color-action-accent);
1385
+ --button-accent-background-hover: var(--color-action-accent-hover);
1386
+ --button-accent-background-active: var(--color-action-accent-active);
1387
+ --button-accent-text-default: var(--color-action-on-fill);
1388
+ --button-accent-ring-default: transparent;
1389
+
1390
+ /* white and outline-white: fixed presets for a solid-colour banner,
1391
+ where even a surface="dark" primary would sit too close in tone.
1392
+ They ignore surface on purpose.
1393
+
1394
+ text-default is blue-600 rather than blue-500: white is the fill
1395
+ here, and blue-500 on white is 4.53:1 — the marginal step the
1396
+ contrast note warns against for text.
1397
+
1398
+ The translucent whites were rgba(255,255,255,…) and #ffffff8c
1399
+ literals, which no theme could reach. color-mix keeps the alpha and
1400
+ puts the colour back on the palette. */
1401
+ --button-white-background-default: var(--color-neutral-0);
1402
+ --button-white-background-hover: var(--color-blue-50);
1403
+ --button-white-background-active: var(--color-blue-100);
1404
+ /* blue-600 by name, not --color-text-brand. The preset is fixed --
1405
+ a white fill on a brand band, in any theme -- so its ink must be
1406
+ fixed too. Reading the role mixed a fill that never switches with a
1407
+ label that does: text-brand goes light in a dark theme and measured
1408
+ 2.36:1 on the white fill (dark mode finding 8). */
1409
+ --button-white-text-default: var(--color-blue-600);
1410
+
1411
+ --button-outline-white-text-default: var(--color-action-on-fill);
1412
+ /* 71% rather than 55%. This edge is the only thing bounding an
1413
+ outline-white button, so it carries the 3:1 of WCAG 1.4.11 on its
1414
+ own. Measured over the grounds the preset is actually used on, 55%
1415
+ gave 2.34 on blue-500 and 2.90 on blue-600 and only cleared on
1416
+ blue-700 at 3.65. 71% is the lowest value that clears all three
1417
+ with one number, so the token stops depending on which blue is
1418
+ behind it. */
1419
+ --button-outline-white-border-default: color-mix(in srgb, var(--color-neutral-0) 71%, transparent);
1420
+ /* Hover and press DARKEN the band, they do not wash it white. A white
1421
+ wash lightened the blue under a white label: 3.91:1 on hover and
1422
+ 3.38 pressed over blue-500, and 4.22 pressed over blue-600 -- under
1423
+ the 4.5 the label needs. 10% and 20% black take blue-500 to 5.40
1424
+ and 6.49 and give the 71% edge more ground (3.46 and 4.03); every
1425
+ ground the preset sits on now clears, the CTA gradient included.
1426
+ Darker on hover is also what every filled button already does.
1427
+ .
1428
+ The trade-off, chosen knowingly: on the navy end of the CTA
1429
+ gradient (#061a5c) darkening barely shows, a 1.05 step where the
1430
+ white wash gave 1.31. The label is what must pass; the hover there
1431
+ is carried by the cursor. A white wash cannot work on blue-500 at
1432
+ all, where the label clears 4.5 at rest by 0.03. */
1433
+ --button-outline-white-background-hover: color-mix(in srgb, var(--color-neutral-1000) 10%, transparent);
1434
+ --button-outline-white-background-active: color-mix(in srgb, var(--color-neutral-1000) 20%, transparent);
1435
+
1436
+ /* Shared across every variant. Filled kinds go grey; outlined ones keep
1437
+ a transparent fill and take the subtle border. Contrast is exempt
1438
+ here under WCAG 1.4.3.
1439
+
1440
+ borderColor is --color-border-disabled: the role named for the state
1441
+ it expresses, and the one disabled-edge value the whole control
1442
+ family now shares. It read neutral-300 once, then moved to
1443
+ neutral-200 to match what the component drew; bd-checkbox and
1444
+ bd-radio have since moved to neutral-300, so token and component
1445
+ agree again -- a step darker, 2.27:1 against the page where
1446
+ neutral-200 gave 1.66, and still lighter than any enabled edge. */
1447
+ --button-disabled-backgroundColor: var(--color-surface-disabled);
1448
+ --button-disabled-borderColor: var(--color-border-disabled);
1449
+ --button-disabled-color: var(--color-text-subtle);
1450
+
1451
+ /* ================================
1452
+ COMPONENT TOKENS - ANNOTATION
1453
+ ================================ */
1454
+
1455
+ /* Footnote Tokens */
1456
+ --footnote-reference-fontSize: 0.75em;
1457
+ --footnote-reference-fontWeight: var(--typography-fontWeight-normal);
1458
+ --footnote-reference-lineHeight: 1;
1459
+ --footnote-reference-verticalAlign: super;
1460
+ --footnote-reference-color: inherit;
1461
+ --footnote-reference-marginLeft: 0.1em;
1462
+ --footnote-reference-marginRight: 0.2em;
1463
+
1464
+ /* Citation Tokens */
1465
+ --citation-reference-fontSize: inherit;
1466
+ --citation-reference-fontWeight: var(--typography-fontWeight-normal);
1467
+ --citation-reference-lineHeight: inherit;
1468
+ --citation-reference-color: var(--color-text-brand);
1469
+ --citation-reference-textDecoration: underline;
1470
+ --citation-reference-hover-color: var(--color-text-brand-hover);
1471
+ --citation-reference-hover-textDecoration: none;
1472
+
1473
+ /* Mathematical Notation Tokens */
1474
+ --math-superscript-fontSize: 0.75em;
1475
+ --math-superscript-fontWeight: var(--typography-fontWeight-normal);
1476
+ --math-superscript-lineHeight: 1;
1477
+ --math-superscript-verticalAlign: super;
1478
+ --math-superscript-marginLeft: 0.05em;
1479
+
1480
+ --math-subscript-fontSize: 0.75em;
1481
+ --math-subscript-fontWeight: var(--typography-fontWeight-normal);
1482
+ --math-subscript-lineHeight: 1;
1483
+ --math-subscript-verticalAlign: sub;
1484
+ --math-subscript-marginLeft: 0.05em;
1485
+
1486
+ /* ================================
1487
+ COMPONENT TOKENS - ICON
1488
+ ================================ */
1489
+
1490
+ /* Icon Size Tokens */
1491
+ --icon-xs-size: var(--dimension-12);
1492
+ --icon-sm-size: var(--dimension-16);
1493
+ --icon-md-size: var(--dimension-20);
1494
+ --icon-lg-size: var(--dimension-24);
1495
+ --icon-xl-size: var(--dimension-32);
1496
+ --icon-2xl-size: var(--dimension-48);
1497
+ --icon-3xl-size: var(--dimension-64);
1498
+
1499
+ /* The context aliases (--icon-button-*, --icon-form-*) and the ten
1500
+ --icon-*-color tokens were removed when the icon elements moved onto
1501
+ the size scale and currentColor. The aliases said the same thing as a
1502
+ step — --icon-button-small-size and --icon-sm-size were both 16px —
1503
+ and the colours described states an icon no longer has: it takes the
1504
+ colour of the text it sits in, so there is nothing per-state to keep
1505
+ in step. */
1506
+
1507
+ /* ================================
1508
+ CORE SPACING TOKENS
1509
+ ================================ */
1510
+
1511
+ --spacing-0: 0;
1512
+ --spacing-1: 0.0625rem; /* 1px */
1513
+ --spacing-2: 0.125rem; /* 2px */
1514
+ --spacing-4: 0.25rem; /* 4px */
1515
+ --spacing-6: 0.375rem; /* 6px */
1516
+ --spacing-8: 0.5rem; /* 8px */
1517
+ --spacing-10: 0.625rem; /* 10px */
1518
+ --spacing-12: 0.75rem; /* 12px */
1519
+ --spacing-14: 0.875rem; /* 14px */
1520
+ --spacing-16: 1rem; /* 16px */
1521
+ --spacing-18: 1.125rem; /* 18px */
1522
+ --spacing-20: 1.25rem; /* 20px */
1523
+ --spacing-22: 1.375rem; /* 22px */
1524
+ --spacing-24: 1.5rem; /* 24px */
1525
+ --spacing-28: 1.75rem; /* 28px */
1526
+ --spacing-32: 2rem; /* 32px */
1527
+ --spacing-36: 2.25rem; /* 36px */
1528
+ --spacing-40: 2.5rem; /* 40px */
1529
+ --spacing-44: 2.75rem; /* 44px */
1530
+ --spacing-48: 3rem; /* 48px */
1531
+ --spacing-52: 3.25rem; /* 52px */
1532
+ --spacing-56: 3.5rem; /* 56px */
1533
+ --spacing-64: 4rem; /* 64px */
1534
+ --spacing-80: 5rem; /* 80px */
1535
+ --spacing-96: 6rem; /* 96px */
1536
+ --spacing-112: 7rem; /* 112px */
1537
+ --spacing-128: 8rem; /* 128px */
1538
+
1539
+ /* The OLD VALUES block stood here: --display-*, --heading-*, --body-* and
1540
+ --caption-* as pixel font sizes, and a second spacing vocabulary in
1541
+ --space-*, --padding-*, --container-*, --inset-*, --stack-* and
1542
+ --inline-*. Forty-nine tokens, every one a duplicate of something on
1543
+ a live scale under a different name, and not one of them referenced
1544
+ by any component. They are gone. Type comes from
1545
+ --typography-fontSize-* and the component type tokens above it;
1546
+ spacing comes from --spacing-*. */
1547
+
1548
+ /* Accessibility Spacing Tokens
1549
+ -----------------------------------------------*/
1550
+ /* Touch Target Sizes - WCAG 2.1 Success Criterion 2.5.5 (AAA) and 2.5.8 (AA) */
1551
+ --touch-target-size: 44px; /* Minimum touch target size (44px × 44px) */
1552
+ --touch-target-spacing: 8px; /* Minimum space between touch targets */
1553
+
1554
+ /* Readable Line Lengths - For optimal readability */
1555
+ --content-width-readable: 70ch; /* Approximately 70 characters per line */
1556
+ --content-width-max: 1200px; /* Maximum overall content width */
1557
+
1558
+ /** GRID AND BREAKPOINT TOKENS
1559
+
1560
+ These have no consumer in this package and are kept deliberately.
1561
+ A media condition cannot read a custom property — @media
1562
+ (max-width: var(--breakpoint-sm)) is not valid CSS — so a breakpoint
1563
+ token can never be referenced the way a colour is. It exists so the
1564
+ six values have one place to be read from, by the lint that checks
1565
+ media queries against them and by anything generating CSS. The grid
1566
+ tokens are the same case: a layout that wants them reads them, and
1567
+ nothing in the atom layer does.
1568
+
1569
+ They are the exception. Everything else here that nothing references
1570
+ is dead weight, and the OLD VALUES and FONT TOKENS blocks that used
1571
+ to sit below were removed for exactly that reason.
1572
+ */
1573
+ /* Grid container max widths */
1574
+ --grid-container-max-xs: 100%; /* mobile full width */
1575
+ --grid-container-max-sm: 540px;
1576
+ --grid-container-max-md: 720px;
1577
+ --grid-container-max-lg: 960px;
1578
+ --grid-container-max-xl: 1140px;
1579
+ --grid-container-max-xxl: 1320px;
1580
+
1581
+ /* Column count (usually 12) */
1582
+ --grid-columns: 12;
1583
+
1584
+ /* Gutter spacing between columns */
1585
+ --grid-gutter-xs: 16px;
1586
+ --grid-gutter-sm: 24px;
1587
+ --grid-gutter-md: 32px;
1588
+ --grid-gutter-lg: 40px;
1589
+
1590
+ /* Container padding (horizontal spacing) */
1591
+ --grid-padding-xs: 16px;
1592
+ --grid-padding-sm: 24px;
1593
+ --grid-padding-md: 32px;
1594
+ --grid-padding-lg: 40px;
1595
+
1596
+ /* Breakpoints */
1597
+ --breakpoint-xs: 0px;
1598
+ --breakpoint-sm: 576px;
1599
+ --breakpoint-md: 768px;
1600
+ --breakpoint-lg: 992px;
1601
+ --breakpoint-xl: 1200px;
1602
+ --breakpoint-xxl: 1400px;
1603
+ /* =====================
1604
+ FONT-FACE DEFINITIONS
1605
+ Intentionally NOT here. @font-face nested inside a :host rule is
1606
+ discarded at parse time, and even at the top level of a shadow-root
1607
+ stylesheet it never reaches document.fonts. Font faces must be
1608
+ loaded in document scope: see src/tokens/fonts.css.
1609
+ ====================== */
1610
+
1611
+ /* The FONT TOKENS block stood here: --font-weight-mono-*,
1612
+ --font-weight-sans-*, --font-style-mono-* and --font-style-sans-*.
1613
+ Thirteen tokens duplicating --typography-fontWeight-* under a second
1614
+ name, with regular where the live scale says normal, and nothing
1615
+ consuming any of them. --font-family-mono went earlier, with bd-li.
1616
+ A weight is a weight whichever face it is set in. */
1617
+
1618
+ /* Awards section — Orbit Frame 14 (node 1882:9342) */
1619
+ --layout-awards-section-background: var(--color-blue-50);
1620
+ --layout-awards-banner-max-width: 37.5rem; /* legacy narrow cap; prefer cluster */
1621
+ --layout-awards-cluster-max-width: 49.5625rem; /* 793px — trust banner column */
1622
+ --layout-awards-intro-max-width: 39.4375rem; /* 631px — headline stack */
1623
+ /* Legacy: narrow lower block from Orbit; prefer --layout-ensemble-content-max for compare-aligned grids */
1624
+ --layout-awards-content-max-width: 53.0625rem; /* 849px */
1625
+ /* There is no page-width token. The page column is an implementation --
1626
+ src/components/shared/ensemble.css.js -- on the grid container scale
1627
+ above (--grid-container-max-* with --grid-padding-*), which is what
1628
+ Foundations/Grid System documented and nothing had built. A width token
1629
+ here is how six ensembles came to hold one literal each and seven other
1630
+ modules a different one. This padding step stays only because the blog
1631
+ still reads it. */
1632
+ --layout-ensemble-inline-padding: var(--spacing-24);
1633
+
1634
+
991
1635
  }
992
-
993
- @font-face {
994
- font-family: "IBMPlexSans";
995
- font-style: italic;
996
- font-weight: 500;
997
- src: url("/assets/fonts/IBMPlexSans-Medium.woff2") format("woff2");
998
- }
999
- @font-face {
1000
- font-family: "IBMPlexSans";
1001
- font-style: italic;
1002
- font-weight: 500;
1003
- src: url("/assets/fonts/IBMPlexSans-MediumItalic.woff2") format("woff2");
1004
- }
1005
- @font-face {
1006
- font-family: "IBMPlexSans";
1007
- font-style: italic;
1008
- font-weight: 400;
1009
- src: url("/assets/fonts/IBMPlexSans-Regular.woff2") format("woff2");
1010
- }
1011
- @font-face {
1012
- font-family: "IBMPlexSans";
1013
- font-style: italic;
1014
- font-weight: 600;
1015
- src: url("/assets/fonts/IBMPlexSans-SemiBold.woff2") format("woff2");
1016
- }
1017
- @font-face {
1018
- font-family: "IBMPlexSans";
1019
- font-style: italic;
1020
- font-weight: 600;
1021
- src: url("/assets/fonts/IBMPlexSans-SemiBoldItalic.woff2") format("woff2");
1022
- }
1023
-
1024
- /* =====================
1025
- FONT TOKENS
1026
- ====================== */
1027
- /* IBM Plex Mono */
1028
- --font-family-mono: "IBM Plex Mono", monospace;
1029
- --font-weight-mono-light: 300;
1030
- --font-weight-mono-regular: 400;
1031
- --font-weight-mono-medium: 500;
1032
- --font-weight-mono-semibold: 600;
1033
- --font-weight-mono-bold: 700;
1034
-
1035
- --font-style-mono-normal: normal;
1036
- --font-style-mono-italic: italic;
1037
-
1038
- /* IBMPlexSans */
1039
- --typography-fontFamily-sans: "IBM Plex Sans", sans-serif;
1040
- --font-weight-sans-light: 300;
1041
- --typography-body-large-fontWeight: 400;
1042
- --font-weight-sans-medium: 500;
1043
- --typography-fontWeight-semibold: 600;
1044
- --typography-fontWeight-bold: 700;
1045
-
1046
- --font-style-sans-normal: normal;
1047
- --font-style-sans-italic: italic;
1048
1636
  }