@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
@@ -0,0 +1,503 @@
1
+ /**
2
+ * Shared chrome for the Design Tokens stories.
3
+ *
4
+ * Every page in that section uses this module so they stay consistent by
5
+ * construction rather than by five copies of the same CSS. It also carries the
6
+ * token-discovery and contrast helpers, so a docs page never hardcodes a scale
7
+ * that could drift from the tokens themselves.
8
+ *
9
+ * Not a story file: Storybook only globs *.stories.js.
10
+ */
11
+ import { html } from 'lit';
12
+
13
+ /* ============================================================
14
+ Token discovery — read the real values out of the loaded CSS
15
+ ============================================================ */
16
+
17
+ /** Concatenated text of every readable stylesheet in the document. */
18
+ export function readAllCssText() {
19
+ let text = '';
20
+ for (const sheet of Array.from(document.styleSheets)) {
21
+ let rules;
22
+ try {
23
+ rules = sheet.cssRules;
24
+ } catch {
25
+ continue; // cross-origin sheet, skip
26
+ }
27
+ for (const rule of Array.from(rules)) text += `${rule.cssText}\n`;
28
+ }
29
+ return text;
30
+ }
31
+
32
+ /** Resolves a custom property to its computed value on :root. */
33
+ export function resolve(token) {
34
+ return getComputedStyle(document.documentElement).getPropertyValue(token)
35
+ .trim();
36
+ }
37
+
38
+ /**
39
+ * Finds every custom property whose name matches `pattern`, in declaration
40
+ * order, de-duplicated. `pattern` must have the token name as group 1.
41
+ */
42
+ export function discoverTokens(cssText, pattern) {
43
+ const seen = new Set();
44
+ const found = [];
45
+ for (const match of cssText.matchAll(pattern)) {
46
+ const token = match[1];
47
+ if (seen.has(token)) continue;
48
+ seen.add(token);
49
+ found.push(match);
50
+ }
51
+ return found;
52
+ }
53
+
54
+ /** Maps each palette/primitive token to the tokens that reference it. */
55
+ export function discoverConsumers(cssText) {
56
+ const consumers = new Map();
57
+ const pattern = /(--[A-Za-z0-9-]+)\s*:\s*var\(\s*(--[A-Za-z0-9-]+)\s*\)/g;
58
+ for (const [, token, referenced] of cssText.matchAll(pattern)) {
59
+ if (!consumers.has(referenced)) consumers.set(referenced, new Set());
60
+ consumers.get(referenced).add(token);
61
+ }
62
+ return consumers;
63
+ }
64
+
65
+ /* ============================================================
66
+ Colour maths — WCAG 2.1 relative luminance and contrast
67
+ ============================================================ */
68
+
69
+ export const INK = '#151719'; // --color-neutral-900
70
+ export const PAPER = '#ffffff'; // --color-neutral-0
71
+
72
+ /** Resolves any CSS colour notation to [r, g, b] via the browser. */
73
+ export function toRgb(value) {
74
+ const probe = document.createElement('span');
75
+ probe.style.cssText = 'position:absolute;visibility:hidden';
76
+ probe.style.color = value;
77
+ document.body.appendChild(probe);
78
+ const computed = getComputedStyle(probe).color;
79
+ probe.remove();
80
+ const parts = computed.match(/-?[\d.]+/g);
81
+ return parts ? parts.slice(0, 3).map(Number) : [0, 0, 0];
82
+ }
83
+
84
+ function luminance([r, g, b]) {
85
+ const [lr, lg, lb] = [r, g, b]
86
+ .map(channel => channel / 255)
87
+ .map(channel => (channel <= 0.03928 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4));
88
+ return 0.2126 * lr + 0.7152 * lg + 0.0722 * lb;
89
+ }
90
+
91
+ export function contrast(a, b) {
92
+ const [hi, lo] = [luminance(toRgb(a)), luminance(toRgb(b))].sort((x, y) => y - x);
93
+ return (hi + 0.05) / (lo + 0.05);
94
+ }
95
+
96
+ export function toHex(value) {
97
+ return `#${toRgb(value)
98
+ .map(channel => Math.round(channel).toString(16)
99
+ .padStart(2, '0'))
100
+ .join('')}`;
101
+ }
102
+
103
+ /** WCAG level reached by a contrast ratio for normal-size body text. */
104
+ export function wcagLevel(ratio) {
105
+ if (ratio >= 7) return { label: 'AAA', pass: true };
106
+ if (ratio >= 4.5) return { label: 'AA', pass: true };
107
+ if (ratio >= 3) return { label: '18pt', pass: true }; // large text / UI edges only
108
+ return { label: 'fail', pass: false };
109
+ }
110
+
111
+ export function levelBadge(ratio) {
112
+ const { label, pass } = wcagLevel(ratio);
113
+ return html`<span class="level" data-pass=${pass}>${label}</span>`;
114
+ }
115
+
116
+ /* ============================================================
117
+ Shared styles
118
+ ============================================================ */
119
+
120
+ export const chromeStyles = html`
121
+ <style>
122
+ /* The Storybook canvas is transparent, so it inherits the OS colour
123
+ scheme. Paint an explicit surface: there are no dark-mode tokens yet. */
124
+ .docs {
125
+ font-family: var(--typography-fontFamily-sans);
126
+ color: var(--color-neutral-900);
127
+ background: var(--color-neutral-0);
128
+ padding: var(--spacing-24);
129
+ box-sizing: border-box;
130
+ }
131
+
132
+ .docs-inner {
133
+ max-width: 1180px;
134
+ }
135
+
136
+ .docs h1 {
137
+ font-size: var(--typography-fontSize-2xl);
138
+ font-weight: var(--typography-fontWeight-semibold);
139
+ margin: 0 0 var(--spacing-8);
140
+ }
141
+
142
+ .docs-lede {
143
+ font-size: var(--typography-fontSize-sm);
144
+ line-height: var(--typography-lineHeight-normal);
145
+ color: var(--color-neutral-600);
146
+ margin: 0 0 var(--spacing-16);
147
+ max-width: 68ch;
148
+ }
149
+
150
+ .docs-note {
151
+ font-size: var(--typography-fontSize-xs);
152
+ line-height: var(--typography-lineHeight-normal);
153
+ color: var(--color-neutral-700);
154
+ background: var(--color-neutral-50);
155
+ border-radius: var(--radius-md);
156
+ padding: var(--spacing-12) var(--spacing-16);
157
+ margin-bottom: var(--spacing-32);
158
+ }
159
+
160
+ .docs-note b {
161
+ font-weight: var(--typography-fontWeight-semibold);
162
+ color: var(--color-neutral-900);
163
+ }
164
+
165
+ .docs-note code,
166
+ .docs-lede code {
167
+ font-family: var(--typography-fontFamily-mono);
168
+ font-size: var(--typography-code-inline-fontSize);
169
+ }
170
+
171
+ /* --- sections --- */
172
+ .section {
173
+ margin-bottom: var(--spacing-40);
174
+ }
175
+
176
+ .section-head {
177
+ display: flex;
178
+ align-items: baseline;
179
+ gap: var(--spacing-8);
180
+ margin-bottom: var(--spacing-12);
181
+ }
182
+
183
+ .section-name {
184
+ font-size: var(--typography-fontSize-lg);
185
+ font-weight: var(--typography-fontWeight-semibold);
186
+ margin: 0;
187
+ }
188
+
189
+ .section-meta {
190
+ font-size: var(--typography-fontSize-xs);
191
+ font-family: var(--typography-fontFamily-mono);
192
+ color: var(--color-neutral-500);
193
+ }
194
+
195
+ /* --- reference tables --- */
196
+ /* Wide content scrolls inside its own container, never the page. */
197
+ .table-scroll {
198
+ overflow-x: auto;
199
+ }
200
+
201
+ .docs table {
202
+ border-collapse: collapse;
203
+ width: 100%;
204
+ font-size: var(--typography-fontSize-xs);
205
+ }
206
+
207
+ .docs caption {
208
+ /* the visible heading is .section-head; this is for screen readers */
209
+ position: absolute;
210
+ width: 1px;
211
+ height: 1px;
212
+ overflow: hidden;
213
+ clip-path: inset(50%);
214
+ }
215
+
216
+ .docs th {
217
+ text-align: left;
218
+ font-weight: var(--typography-fontWeight-semibold);
219
+ color: var(--color-neutral-600);
220
+ font-size: var(--typography-fontSize-xxs);
221
+ text-transform: uppercase;
222
+ letter-spacing: var(--typography-letterSpacing-wide);
223
+ padding: 0 var(--spacing-12) var(--spacing-8);
224
+ border-bottom: var(--border-width-1) solid var(--color-neutral-200);
225
+ white-space: nowrap;
226
+ }
227
+
228
+ .docs td {
229
+ padding: var(--spacing-8) var(--spacing-12);
230
+ border-bottom: var(--border-width-1) solid var(--color-neutral-100);
231
+ vertical-align: middle;
232
+ }
233
+
234
+ .docs tbody tr:last-child td {
235
+ border-bottom: 0;
236
+ }
237
+
238
+ /* --- cell primitives --- */
239
+ .mono {
240
+ font-family: var(--typography-fontFamily-mono);
241
+ white-space: nowrap;
242
+ }
243
+
244
+ .num {
245
+ font-family: var(--typography-fontFamily-mono);
246
+ font-variant-numeric: tabular-nums;
247
+ white-space: nowrap;
248
+ color: var(--color-neutral-700);
249
+ }
250
+
251
+ /* the rendered pixel value beside a rem one, so a step is recognisable
252
+ without doing the arithmetic */
253
+ .px-hint {
254
+ margin-left: var(--spacing-8);
255
+ color: var(--color-neutral-500);
256
+ font-size: var(--typography-fontSize-xxs);
257
+ }
258
+
259
+ .muted {
260
+ color: var(--color-neutral-500);
261
+ }
262
+
263
+ .unused {
264
+ color: var(--color-neutral-400);
265
+ }
266
+
267
+ .token-copy {
268
+ font-family: var(--typography-fontFamily-mono);
269
+ font-size: var(--typography-fontSize-xs);
270
+ color: var(--color-neutral-900);
271
+ background: none;
272
+ border: 0;
273
+ padding: 0;
274
+ cursor: copy;
275
+ text-align: left;
276
+ white-space: nowrap;
277
+ }
278
+
279
+ .token-copy:hover {
280
+ color: var(--color-blue-600);
281
+ text-decoration: underline;
282
+ }
283
+
284
+ .token-copy:focus-visible {
285
+ outline: var(--focus-outline-traditional);
286
+ outline-offset: var(--focus-outline-offset);
287
+ border-radius: var(--radius-sm);
288
+ }
289
+
290
+ .copied {
291
+ color: var(--color-green-700);
292
+ font-weight: var(--typography-fontWeight-semibold);
293
+ }
294
+
295
+ /* --- WCAG level badge --- */
296
+ .level {
297
+ display: inline-block;
298
+ min-width: 3.2em;
299
+ margin-left: var(--spacing-6);
300
+ padding: 1px var(--spacing-6);
301
+ border-radius: var(--radius-sm);
302
+ font-family: var(--typography-fontFamily-sans);
303
+ font-size: var(--typography-fontSize-xxs);
304
+ font-weight: var(--typography-fontWeight-semibold);
305
+ text-align: center;
306
+ }
307
+
308
+ .level[data-pass='true'] {
309
+ color: var(--color-green-800);
310
+ background: var(--color-green-50);
311
+ }
312
+
313
+ .level[data-pass='false'] {
314
+ color: var(--color-red-800);
315
+ background: var(--color-red-50);
316
+ }
317
+
318
+ /* --- usage disclosure --- */
319
+ details.usage summary {
320
+ cursor: pointer;
321
+ white-space: nowrap;
322
+ }
323
+
324
+ details.usage summary:focus-visible {
325
+ outline: var(--focus-outline-traditional);
326
+ outline-offset: var(--focus-outline-offset);
327
+ border-radius: var(--radius-sm);
328
+ }
329
+
330
+ details.usage ul {
331
+ margin: var(--spacing-6) 0 0;
332
+ padding-left: var(--spacing-16);
333
+ font-family: var(--typography-fontFamily-mono);
334
+ font-size: var(--typography-fontSize-xxs);
335
+ color: var(--color-neutral-600);
336
+ line-height: var(--typography-lineHeight-normal);
337
+ }
338
+
339
+ .usage-count {
340
+ font-weight: var(--typography-fontWeight-semibold);
341
+ color: var(--color-blue-700);
342
+ }
343
+
344
+ /* --- specimen frame, for stories that show rendered output --- */
345
+ .specimen {
346
+ background: var(--color-neutral-25);
347
+ border: var(--border-width-1) solid var(--color-neutral-100);
348
+ border-radius: var(--radius-md);
349
+ padding: var(--spacing-16);
350
+ }
351
+ </style>
352
+ `;
353
+
354
+ /* ============================================================
355
+ Page and section shells
356
+ ============================================================ */
357
+
358
+ export function docsPage({ title, lede, note, children }) {
359
+ return html`
360
+ ${chromeStyles}
361
+ <div class="docs">
362
+ <div class="docs-inner">
363
+ <h1>${title}</h1>
364
+ ${lede ? html`<p class="docs-lede">${lede}</p>` : ''}
365
+ ${note ? html`<div class="docs-note">${note}</div>` : ''}
366
+ ${children}
367
+ </div>
368
+ </div>
369
+ `;
370
+ }
371
+
372
+ export function refSection({ name, meta, children }) {
373
+ return html`
374
+ <section class="section">
375
+ <div class="section-head">
376
+ <h2 class="section-name">${name}</h2>
377
+ ${meta ? html`<span class="section-meta">${meta}</span>` : ''}
378
+ </div>
379
+ ${children}
380
+ </section>
381
+ `;
382
+ }
383
+
384
+ /** A token name that copies its var() reference when clicked. */
385
+ export function copyToken(token) {
386
+ const copy = async event => {
387
+ const button = event.currentTarget;
388
+ const original = button.textContent;
389
+ try {
390
+ // Rejects in an insecure context, on denied permission, or when the
391
+ // document is not focused.
392
+ await navigator.clipboard.writeText(`var(${token})`);
393
+ button.innerHTML = '<span class="copied">copied</span>';
394
+ } catch {
395
+ button.innerHTML = '<span class="copied">copy blocked</span>';
396
+ }
397
+ setTimeout(() => {
398
+ button.textContent = original;
399
+ }, 1200);
400
+ };
401
+
402
+ return html`
403
+ <button class="token-copy" @click=${copy} title="Copy var(${token})">${token}</button>
404
+ `;
405
+ }
406
+
407
+ /** Lists the tokens that consume a given token, behind a disclosure. */
408
+ export function usageCell(consumerSet) {
409
+ if (!consumerSet || !consumerSet.size) return html`<span class="unused">unused</span>`;
410
+ const names = [...consumerSet].sort();
411
+ return html`
412
+ <details class="usage">
413
+ <summary>
414
+ <span class="usage-count">${names.length}</span> token${names.length === 1 ? '' : 's'}
415
+ </summary>
416
+ <ul>
417
+ ${names.map(name => html`<li>${name}</li>`)}
418
+ </ul>
419
+ </details>
420
+ `;
421
+ }
422
+
423
+ /**
424
+ * Standard caveat for the "Referenced by" column.
425
+ *
426
+ * This page can only see stylesheets in the document. Component CSS lives
427
+ * inside shadow roots and is unreachable, so the column counts token-to-token
428
+ * references only — a primitive with no listed references may still be used
429
+ * directly by components.
430
+ */
431
+ export const referenceNote = html`<b>Referenced by</b> counts other
432
+ <em>tokens</em> that point at this one. Component CSS lives inside shadow
433
+ roots and cannot be read from this page, so a token listed as unreferenced
434
+ may still be used directly in a component.`;
435
+
436
+ /**
437
+ * Token / value / optional visual / references table, shared by the primitive
438
+ * pages. `visual` receives (token, value) and returns the cell contents.
439
+ */
440
+ export function primitiveTable({ caption, tokens, consumers, visual, visualHeader = 'Preview', valueClass = 'num' }) {
441
+ const rows = tokens
442
+ .map(token => {
443
+ const value = resolve(token);
444
+ return { token, value, px: toPx(value) };
445
+ })
446
+ .filter(row => row.value);
447
+
448
+ return html`
449
+ <div class="table-scroll">
450
+ <table>
451
+ <caption>${caption}</caption>
452
+ <thead>
453
+ <tr>
454
+ <th scope="col">Token</th>
455
+ <th scope="col">Value</th>
456
+ ${visual ? html`<th scope="col">${visualHeader}</th>` : ''}
457
+ <th scope="col">Referenced by</th>
458
+ </tr>
459
+ </thead>
460
+ <tbody>
461
+ ${rows.map(
462
+ ({ token, value, px }) => html`
463
+ <tr>
464
+ <td>${copyToken(token)}</td>
465
+ <td class=${valueClass}>
466
+ ${value}${px ? html`<span class="px-hint">${px}</span>` : ''}
467
+ </td>
468
+ ${visual ? html`<td>${visual(token, value)}</td>` : ''}
469
+ <td>${usageCell(consumers.get(token))}</td>
470
+ </tr>
471
+ `
472
+ )}
473
+ </tbody>
474
+ </table>
475
+ </div>
476
+ `;
477
+ }
478
+
479
+ /**
480
+ * The rendered pixel value of a rem length, measured rather than assumed, so a
481
+ * browser at a non-default root font size reports its own truth.
482
+ *
483
+ * rem only. An em value is relative to the element's own font size, so there
484
+ * is no single pixel equivalent to state — quoting one would be wrong rather
485
+ * than merely imprecise. px values, 0, unitless numbers, keywords and colours
486
+ * are left alone too.
487
+ */
488
+ export function toPx(value) {
489
+ const v = String(value ?? '').trim();
490
+ if (!/^[\d.]+rem$/.test(v)) return '';
491
+ const probe = document.createElement('div');
492
+ probe.style.cssText = `position:absolute;visibility:hidden;height:0;width:${v}`;
493
+ document.body.appendChild(probe);
494
+ const px = getComputedStyle(probe).width;
495
+ probe.remove();
496
+ return px === v ? '' : px;
497
+ }
498
+
499
+ /** Tokens matching a prefix, in declaration order, read from the loaded CSS. */
500
+ export function tokensFor(cssText, prefix) {
501
+ const pattern = new RegExp(`(--${prefix}[A-Za-z0-9-]*)\\s*:`, 'g');
502
+ return discoverTokens(cssText, pattern).map(match => match[1]);
503
+ }