@repobit/dex-system-design 0.25.12 → 1.0.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 +204 -0
  2. package/README.md +131 -8
  3. package/package.json +96 -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
@@ -14,7 +14,7 @@ export default css`
14
14
  border: none;
15
15
  background: none;
16
16
  cursor: pointer;
17
- border-radius: var(--radius-lg, 16px);
17
+ border-radius: var(--radius-lg);
18
18
  overflow: hidden;
19
19
  }
20
20
 
@@ -22,8 +22,8 @@ export default css`
22
22
  width: 100%;
23
23
  height: auto;
24
24
  display: block;
25
- border-radius: var(--radius-lg, 16px);
26
- transition: transform 300ms ease;
25
+ border-radius: var(--radius-lg);
26
+ transition: transform var(--transition-duration-slow) var(--transition-easing-ease);
27
27
  }
28
28
 
29
29
  .bd-video-thumb:hover img {
@@ -39,7 +39,7 @@ export default css`
39
39
  height: 64px;
40
40
  pointer-events: none;
41
41
  filter: drop-shadow(0 4px 12px rgba(0,0,0,0.3));
42
- transition: transform 300ms ease;
42
+ transition: transform var(--transition-duration-slow) var(--transition-easing-ease);
43
43
  }
44
44
 
45
45
  .bd-video-thumb:hover .bd-video-play-btn {
@@ -55,9 +55,12 @@ export default css`
55
55
  position: relative;
56
56
  width: 100%;
57
57
  padding-bottom: 56.25%;
58
- border-radius: var(--radius-lg, 16px);
58
+ border-radius: var(--radius-lg);
59
59
  overflow: hidden;
60
- background: var(--color-neutral-900);
60
+ /* The media frame, --color-surface-media: around a video, dark in every theme.
61
+ This read --color-surface-inverse until dark mode decision 15 -- the
62
+ polarity flip, which would turn a letterbox light in a dark theme. */
63
+ background: var(--color-surface-media);
61
64
  }
62
65
 
63
66
  .bd-video-player iframe,
@@ -78,18 +81,71 @@ export default css`
78
81
  height: 32px;
79
82
  border-radius: 50%;
80
83
  border: none;
81
- background: rgba(0,0,0,0.6);
82
- color: white;
84
+ /* no role: NOT a scrim, though it looks like one next to the modal's. This
85
+ is the close button's own ground -- a 32px circle that has to carry a
86
+ white glyph over whatever frame the video happens to be showing, so the
87
+ darkness is doing contrast work for the icon rather than dimming content
88
+ behind a dialog. Two declarations, one control, no role.
89
+ .
90
+ Mixed over the palette rather than written as a raw rgba, for the same
91
+ reason as the modal's scrim: this follows --color-neutral-1000 where a
92
+ literal black follows nothing. Pixel-identical to the rgba it replaces. */
93
+ background: color-mix(in srgb, var(--color-neutral-1000) 60%, transparent);
94
+ color: var(--color-text-on-media);
83
95
  font-size: 16px;
84
96
  cursor: pointer;
85
97
  display: flex;
86
98
  align-items: center;
87
99
  justify-content: center;
88
- z-index: 10;
89
- transition: background 150ms ease;
100
+ /* Above the video surface it sits on; nothing else in this shadow root
101
+ is positioned. */
102
+ z-index: var(--z-raised);
103
+ transition: background var(--transition-duration-fast) var(--transition-easing-ease);
90
104
  }
91
105
 
92
106
  .bd-video-close:hover {
93
- background: rgba(0,0,0,0.9);
107
+ /* no role: the same control ground at 90% under the pointer -- it gets more
108
+ opaque rather than changing hue. Same reasoning as the rest state above,
109
+ and no role for the same reason. Pixel-identical to the rgba it
110
+ replaces. */
111
+ background: color-mix(in srgb, var(--color-neutral-1000) 90%, transparent);
112
+ }
113
+
114
+ /* The one focus ring, on both controls. This sheet had no :focus-visible
115
+ rule at all, so the two buttons fell back to the browser's outline:
116
+ measured on the thumbnail with a real Tab, outline 1px auto
117
+ rgb(0, 95, 204) and box-shadow none, where every other control in this
118
+ package draws --focus-outline-primary. The two-colour ring also matters
119
+ more here than most places -- the close button sits on video, so a
120
+ single-colour outline has no guaranteed ground to contrast against, and
121
+ the white inner band is what makes it visible on any frame.
122
+
123
+ The ring follows each control's own shape: the thumbnail keeps its
124
+ --radius-lg corner and the close button is a circle. */
125
+ .bd-video-thumb:focus-visible,
126
+ .bd-video-close:focus-visible {
127
+ outline: none;
128
+ box-shadow: var(--focus-outline-primary);
129
+ }
130
+
131
+ /* The thumbnail lifts on hover and the play mark grows. Measured before
132
+ this: with prefers-reduced-motion: reduce both still reported a 0.3s
133
+ transition, so the scale ran for a reader who asked for less motion.
134
+ The transform is dropped as well as the transition -- a scale that
135
+ arrives instantly is still motion the reader did not ask for. */
136
+ @media (prefers-reduced-motion: reduce) {
137
+ .bd-video-thumb img,
138
+ .bd-video-play-btn,
139
+ .bd-video-close {
140
+ transition: none;
141
+ }
142
+
143
+ .bd-video-thumb:hover img {
144
+ transform: none;
145
+ }
146
+
147
+ .bd-video-thumb:hover .bd-video-play-btn {
148
+ transform: translate(-50%, -50%);
149
+ }
94
150
  }
95
151
  `;
@@ -1,5 +1,7 @@
1
1
  import { LitElement, html } from "lit";
2
- import { tokens } from "../../tokens/tokens.js";
2
+ // Installs the design tokens into document scope; see src/tokens/tokens.js
3
+ import "../../tokens/tokens.js";
4
+ import "../icons/close-icon.js";
3
5
  import videoPlayerCSS from "./video-player.css.js";
4
6
 
5
7
  class BdVideoPlayer extends LitElement {
@@ -10,7 +12,7 @@ class BdVideoPlayer extends LitElement {
10
12
  _open : { state: true }
11
13
  };
12
14
 
13
- static styles = [tokens, videoPlayerCSS];
15
+ static styles = [videoPlayerCSS];
14
16
 
15
17
  constructor() {
16
18
  super();
@@ -24,12 +26,39 @@ class BdVideoPlayer extends LitElement {
24
26
  return this.src.includes("youtube.com") || this.src.includes("youtu.be");
25
27
  }
26
28
 
29
+ /**
30
+ * Opening replaces the thumbnail button with the player, which destroys the
31
+ * element that had focus. Measured with a real keyboard: Tab to the
32
+ * thumbnail, Enter, and document.activeElement was body -- the keyboard user
33
+ * was dropped to the top of the document by the act of pressing Play.
34
+ *
35
+ * Focus goes to the close button, which is the one control this component
36
+ * owns once the player is up. That also answers a reachability problem it
37
+ * would otherwise have: the close button follows the iframe in DOM order, so
38
+ * reaching it by Tab means traversing the embedded player's own tab stops
39
+ * first -- measured, six Tabs after opening never left the iframe. Landing on
40
+ * it directly means the way out is the first thing the keyboard has.
41
+ *
42
+ * Only when there is a thumbnail: without one the component renders the
43
+ * player immediately, owns no close button, and nothing has been displaced.
44
+ */
27
45
  _openVideo() {
28
46
  this._open = true;
47
+ if (!this.thumb) return;
48
+ this.updateComplete.then(() => {
49
+ this.renderRoot?.querySelector(".bd-video-close")?.focus();
50
+ });
29
51
  }
30
52
 
53
+ /**
54
+ * Closing destroys the close button the same way, so focus returns to the
55
+ * thumbnail it came from.
56
+ */
31
57
  _closeVideo() {
32
58
  this._open = false;
59
+ this.updateComplete.then(() => {
60
+ this.renderRoot?.querySelector(".bd-video-thumb")?.focus();
61
+ });
33
62
  }
34
63
 
35
64
  render() {
@@ -61,7 +90,9 @@ class BdVideoPlayer extends LitElement {
61
90
  class="bd-video-close"
62
91
  @click=${this._closeVideo}
63
92
  aria-label="Close video"
64
- >✕</button>
93
+ >
94
+ <bd-close-icon size="xs" aria-hidden="true"></bd-close-icon>
95
+ </button>
65
96
  `
66
97
  : ""}
67
98
  </div>
@@ -82,7 +113,7 @@ class BdVideoPlayer extends LitElement {
82
113
  <span class="bd-video-play-btn" aria-hidden="true">
83
114
  <svg viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
84
115
  <circle cx="32" cy="32" r="32" fill="white" fill-opacity="0.9"/>
85
- <path d="M26 20L46 32L26 44V20Z" fill="#006DFF"/>
116
+ <path d="M26 20L46 32L26 44V20Z" fill="var(--color-blue-500)"/>
86
117
  </svg>
87
118
  </span>
88
119
  </button>
@@ -136,7 +136,7 @@ export const YouTubeAutoplayVideo = {
136
136
  export const DifferentThumbnails = {
137
137
  name : 'Different Thumbnails',
138
138
  render: () => html`
139
- <div style="display:grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 24px; max-width: 1200px; margin: 0 auto; padding: 20px;">
139
+ <div style="display:grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); gap: 24px; max-width: 1200px; margin: 0 auto; padding: 20px;">
140
140
  <div>
141
141
  <h4 style="margin-bottom: 8px;">Thumbnail 1</h4>
142
142
  <bd-video-player
@@ -0,0 +1,411 @@
1
+ import { html } from 'lit';
2
+
3
+ import './alert/alert.js';
4
+ import './anchor/anchor-nav.js';
5
+ import './back/back.js';
6
+ import './badge/badge.js';
7
+ import './bento-grid/bento-item.js';
8
+ import './breadcrumb/breadcrumb.js';
9
+ import './card-features/card-features.js';
10
+ import './cards/card.js';
11
+ import './carousel/carousel.js';
12
+ import './compare/compare.js';
13
+ import './divider/divider-vertical.js';
14
+ import './footer/footer-nav-menu.js';
15
+ import './heading/heading.js';
16
+ import './light-carousel/light-carousel.js';
17
+ import './page-switcher/page-switcher.js';
18
+ import './paragraph/paragraph.js';
19
+ import './tab-list/tab-list.js';
20
+ import './tag/tag.js';
21
+ import { tabListCSS } from './tab-list/tab-list.css.js';
22
+
23
+ /**
24
+ * Composed components rendered next to the components they are supposed to
25
+ * agree with.
26
+ *
27
+ * `Atoms/Control Alignment` does this for atoms and says why: the lint can
28
+ * prove every value came from a token and still cannot prove two components
29
+ * ended up looking the same. The same gap exists a layer up, and it is where
30
+ * the section title came to mean 48, 36, 32 and 24 at once, and where one card
31
+ * in the family kept a corner the other five had stopped using.
32
+ *
33
+ * These exist to be looked at. Nothing here is a usage example — do not copy
34
+ * these compositions into a page.
35
+ */
36
+ export default {
37
+ title : 'Foundations/Visual Alignment',
38
+ tags : ['autodocs'],
39
+ parameters: {
40
+ layout: 'padded',
41
+ docs : {
42
+ description: {
43
+ component: `
44
+ Cross-component comparisons. Each story puts components that share a visual
45
+ role in one frame, so the system can be judged as a system.
46
+
47
+ Read each one by asking whether these look like they came from the same place.
48
+ Where they do not, the difference is either a decision or a finding — and the
49
+ point of the story is that you can tell which.
50
+ `
51
+ }
52
+ }
53
+ }
54
+ };
55
+
56
+ const label = text => html`
57
+ <p style="margin:0 0 var(--spacing-8);font:var(--typography-fontWeight-semibold) var(--typography-fontSize-xs)/1.4 var(--typography-fontFamily-mono);color:var(--color-text-muted)">
58
+ ${text}
59
+ </p>`;
60
+
61
+ /* Several of these components carry their own fixed width -- the carousel item
62
+ is 350px -- so a row of them is wider than a phone no matter how it wraps.
63
+ It scrolls inside its own container rather than taking the page with it,
64
+ which is what this package already does for wide reference tables. */
65
+ const row = children => html`
66
+ <div style="overflow-x:auto">
67
+ <div style="display:flex;flex-wrap:wrap;gap:var(--spacing-24);align-items:flex-start;min-width:min-content">
68
+ ${children}
69
+ </div>
70
+ </div>`;
71
+
72
+ const cell = (name, node) => html`
73
+ <div style="flex:0 1 auto;min-width:0">${label(name)}${node}</div>`;
74
+
75
+ /* ---------------------------------------------------------------- cards --- */
76
+
77
+ export const CardFamily = {
78
+ name : 'Card family',
79
+ render: () => html`
80
+ <p style="max-width:70ch;color:var(--color-text-secondary)">
81
+ Every card in the family sits on <code>--color-surface-container</code> with
82
+ 32px of padding and no resting shadow, and none of them draws an edge. Every
83
+ cell below measures the same at desktop width: 16px corner, no border, 32px
84
+ inset. This page used to exist because they differed.
85
+ </p>
86
+ <p style="max-width:70ch;color:var(--color-text-secondary)">
87
+ <b>The inset holds at every width.</b> LightCarousel used to be the one exception,
88
+ dropping its padding to 1.5em at 1024 and 1em at 480 while every other card held
89
+ <code>--spacing-32</code> — so at this page's own default viewport that cell
90
+ measured 24px, not 32. It was never a decision, just two em literals carried
91
+ forward, and it is gone. A card in a narrowing track is still a card: the track
92
+ gives way, not the card's own breathing room.
93
+ </p>
94
+ <p style="max-width:70ch;color:var(--color-text-secondary)">
95
+ Whether a card has an edge is no longer a component decision. It follows from
96
+ what the card sits on — no edge on the page ground, where the tonal step is the
97
+ separation; an edge on a tinted section, where no tonal step is available. See
98
+ <i>A card's ground and its edge</i> in the package README, and
99
+ <code>Foundations/Surfaces</code>. The two cards that drew an edge on the page
100
+ ground — Bento and the Carousel item — dropped it under that rule. Interactivity
101
+ never predicted an edge and still does not.
102
+ </p>
103
+ ${row(html`
104
+ ${cell('bd-card-item · 16px, no border', html`
105
+ <bd-card-item title="Machine Learning">
106
+ <bd-p variant="small">Behaviour learned from millions of daily threats.</bd-p>
107
+ </bd-card-item>`)}
108
+ ${cell('bd-card-features-item · 16px, no border', html`
109
+ <bd-card-features-item title="Scam Copilot">
110
+ <bd-p variant="small">Behaviour learned from millions of daily threats.</bd-p>
111
+ </bd-card-features-item>`)}
112
+ ${cell('bd-light-carousel-item · 16px, no border', html`
113
+ <bd-light-carousel-item title="Machine Learning">
114
+ <bd-p variant="small">Behaviour learned from millions of daily threats.</bd-p>
115
+ </bd-light-carousel-item>`)}
116
+ ${cell('bd-bento-item · 16px, no border — was 1px', html`
117
+ <bd-bento-item title="Machine Learning">
118
+ <bd-p variant="small">Behaviour learned from millions of daily threats.</bd-p>
119
+ </bd-bento-item>`)}
120
+ ${cell('bd-carousel-item · 16px, no border — was 24px and 2px', html`
121
+ <bd-carousel-item title="Machine Learning" modalText="Opens a modal.">
122
+ <bd-p variant="small">Behaviour learned from millions of daily threats.</bd-p>
123
+ </bd-carousel-item>`)}
124
+ ${cell('compare-card · 16px, no border — was 24px', html`
125
+ <compare-card
126
+ title="Best Protection"
127
+ description="Scale of 0-6. Higher is better."
128
+ ></compare-card>`)}
129
+ `)}`,
130
+ parameters: {
131
+ docs: {
132
+ description: {
133
+ story: `Nothing differs any more, and the two that used to are worth keeping
134
+ on the page for the reasons they gave.
135
+
136
+ The compare card had no argument: same surface, same inset, no elevation,
137
+ no card-level interaction, no recorded reason. It went first.
138
+
139
+ The carousel item did have one — it is draggable and its plus button opens
140
+ a modal, where the others are static — and it went anyway. Behaviour earns
141
+ a state, a cue or a control; it does not earn a different corner. The
142
+ question the two of them settle is what counts as a reason to leave a
143
+ family, and behaving differently turned out not to be enough on its own.`
144
+ }
145
+ }
146
+ }
147
+ };
148
+
149
+ /* ----------------------------------------------------------- section titles - */
150
+
151
+ export const SectionTitles = {
152
+ name : 'Section title roles',
153
+ render: () => html`
154
+ <p style="max-width:70ch;color:var(--color-text-secondary)">
155
+ Two roles, and the question that picks between them: would the page still make
156
+ sense with this title deleted and its content left in place? If not it is
157
+ anchoring a region, and it is a page section.
158
+ </p>
159
+ <div style="display:grid;gap:var(--spacing-40);max-width:80ch">
160
+ <div>
161
+ ${label('PAGE SECTION · bd-h visual-level="h2" · 36/700')}
162
+ <bd-h as="h2" visual-level="h2">What is AI Guardian?</bd-h>
163
+ <bd-p variant="small">Overview, Process Steps, Trust Panel, Comparison Panel.</bd-p>
164
+ </div>
165
+ <div>
166
+ ${label('COMPONENT SECTION · bd-h visual-level="h3" · 32/600')}
167
+ <bd-h as="h2" visual-level="h3">Need help? We have answers.</bd-h>
168
+ <bd-p variant="small">LightCarousel, CardFeatures, Awards, Tabs, Terms.</bd-p>
169
+ </div>
170
+ <div>
171
+ ${label('ITEM TITLE · bd-h visual-level="h5" fontWeight="bold" · 20/700')}
172
+ <bd-h as="h3" visual-level="h5" fontWeight="bold">Machine Learning</bd-h>
173
+ <bd-p variant="small">The title of one card inside a collection.</bd-p>
174
+ </div>
175
+ <div>
176
+ ${label('LONG TITLE · the component section, wrapping')}
177
+ <bd-h as="h2" visual-level="h3">
178
+ A section title long enough to wrap onto a second and very probably a third line
179
+ </bd-h>
180
+ </div>
181
+ </div>`,
182
+ parameters: {
183
+ docs: {
184
+ description: {
185
+ story: `The level and the size are separate: every heading here is semantically
186
+ what its position requires, and visually what its responsibility requires.
187
+ Two components render a section title at 48/700 — the card section and the
188
+ hero — and both are recorded P4 exceptions rather than a third role.`
189
+ }
190
+ }
191
+ }
192
+ };
193
+
194
+ /* -------------------------------------------------------------- navigation - */
195
+
196
+ const NAV_ITEMS = [
197
+ { title: 'AI Guardian', href: '#one', active: true },
198
+ { title: 'Skill Scanner', href: '#two' }
199
+ ];
200
+
201
+ export const NavigationStates = {
202
+ name : 'Navigation current state',
203
+ render: () => html`
204
+ <p style="max-width:70ch;color:var(--color-text-secondary)">
205
+ Two models, and they are not the same question. The link navigations mark where
206
+ you are; the tab list marks which panel is showing. Every one of them carries a
207
+ cue that is not colour.
208
+ </p>
209
+ <div style="display:grid;gap:var(--spacing-40)">
210
+ <div>
211
+ ${label('bd-page-switcher · current is heavier and darker')}
212
+ <bd-page-switcher .items=${NAV_ITEMS}></bd-page-switcher>
213
+ </div>
214
+ <div>
215
+ ${label('bd-breadcrumb · current is heavier, larger and darker')}
216
+ <bd-breadcrumb>
217
+ <bd-breadcrumb-item href="/">Home</bd-breadcrumb-item>
218
+ <bd-breadcrumb-item href="/products">Products</bd-breadcrumb-item>
219
+ <bd-breadcrumb-item current>Total Security</bd-breadcrumb-item>
220
+ </bd-breadcrumb>
221
+ </div>
222
+ </div>`,
223
+ parameters: {
224
+ docs: {
225
+ description: {
226
+ story: `Tabs used to run the opposite way and be left alone here, on the argument
227
+ that its items are buttons with role="tab" and aria-selected inside a
228
+ tablist rather than links. The ARIA contract is still exactly that and does
229
+ not change. What changed is the ink: a label with an action behind it is
230
+ painted like a link in this package, whatever element carries it, so the
231
+ unselected tabs are brand blue and the selected one settles to plain text
232
+ at bold — the same three-step contract the link navigations use. Measured
233
+ across all three: resting is blue-600 at 400, current is text-primary at
234
+ 700, both at 16px. Its underline carries the state either way.
235
+
236
+ The two rows above read alike, and measurement is why. The page
237
+ switcher's current item is darker and heavier than its neighbours, which
238
+ are brand blue rather than muted — the sizes match at 16px. The
239
+ breadcrumb's current item is the same 14px as its links and one weight
240
+ step above them, which is a change P6C.2 made: the links asked bd-link for
241
+ \`size="small"\`, a property bd-link does not have, so they rendered 16px
242
+ against a 14px current item, and the current item's medium weight was
243
+ declared on a span whose text lives inside bd-p and never arrived.`
244
+ }
245
+ }
246
+ }
247
+ };
248
+
249
+ /* The whole family in one frame, grouped by what each member is responsible for
250
+ rather than by what it looks like. The point of the grouping is that two of
251
+ these are not supposed to converge with the others.
252
+
253
+ bd-footer-nav sits on the masthead blue it is always used on. It is the one
254
+ member whose links are the consumer's own anchors rather than bd-link, which
255
+ is why it is the only one that had to be given the focus ring explicitly —
256
+ tab through it here and the ring should be the same two-colour ring as
257
+ everywhere else, white band inside blue. */
258
+ const FAMILY_TABS = [
259
+ { label: 'Windows' }, { label: 'macOS' }, { label: 'iOS' }
260
+ ];
261
+
262
+ const group = (title, note, node) => html`
263
+ <section style="display:grid;gap:var(--spacing-8)">
264
+ <h3 style="margin:0;font:var(--typography-fontWeight-semibold) var(--typography-fontSize-base)/var(--typography-lineHeight-tight) var(--typography-fontFamily-sans);color:var(--color-text-primary)">
265
+ ${title}
266
+ </h3>
267
+ <p style="margin:0;max-width:74ch;font:var(--typography-fontWeight-normal) var(--typography-fontSize-sm)/var(--typography-lineHeight-normal) var(--typography-fontFamily-sans);color:var(--color-text-secondary)">
268
+ ${note}
269
+ </p>
270
+ <div style="padding-top:var(--spacing-8)">${node}</div>
271
+ </section>`;
272
+
273
+ export const NavigationFamily = {
274
+ name : 'Navigation family',
275
+ render: () => html`
276
+ <style>${tabListCSS.cssText}</style>
277
+ <p style="max-width:74ch;color:var(--color-text-secondary)">
278
+ Seven components, five responsibilities. They share a vocabulary — one focus ring,
279
+ one selected-underline role, one ink scale — and they are not meant to share an
280
+ appearance: a breadcrumb answers "where am I", a tab list answers "which panel is
281
+ showing", and a back control answers neither.
282
+ </p>
283
+ <div style="display:grid;gap:var(--spacing-48)">
284
+ ${group(
285
+ '1 · Current location, in a set of pages',
286
+ 'bd-page-switcher. aria-current="page". The current item is the darkest and the heaviest and carries the 3px selected underline; the others are brand blue, because they are links. Three cues, none of them colour alone.',
287
+ html`<bd-page-switcher .items=${NAV_ITEMS}></bd-page-switcher>`
288
+ )}
289
+ ${group(
290
+ '2 · Current location, inside one page',
291
+ 'bd-anchor-nav. aria-current="location" — a different claim from "page", and the reason the two do not share the attribute value. Below md the same nav becomes a disclosure: the trigger takes a control edge and the expanded panel and its chevron take the one blue that means expanded.',
292
+ html`<bd-anchor-nav .items=${NAV_ITEMS.map(i => ({ title: i.title, href: i.href }))}></bd-anchor-nav>`
293
+ )}
294
+ ${group(
295
+ '3 · Path to the current location',
296
+ 'bd-breadcrumb. aria-current="page" on the last item, which is text rather than a link. One type size across the row; the links are brand blue and the current item is default ink one weight step up. Hover adds an underline — the cue that is not colour — and at mobile widths the row becomes a stack of full-width targets.',
297
+ html`
298
+ <bd-breadcrumb>
299
+ <bd-breadcrumb-item href="/">Home</bd-breadcrumb-item>
300
+ <bd-breadcrumb-item href="/products">Products</bd-breadcrumb-item>
301
+ <bd-breadcrumb-item current>Total Security</bd-breadcrumb-item>
302
+ </bd-breadcrumb>`
303
+ )}
304
+ ${group(
305
+ '4 · Selection, not location',
306
+ 'bd-tab-list. role="tablist", aria-selected, roving tabindex, arrow keys. The polarity is deliberately the other way round: the unselected tabs are the actionable ones and read as brand blue, and the selected one settles to plain ink. It shares the underline role with 1 and 2 and shares nothing else, because it is not saying where you are.',
307
+ html`<bd-tab-list .tabs=${FAMILY_TABS} .selected=${0} label="Platform"></bd-tab-list>`
308
+ )}
309
+ ${group(
310
+ '5 · Leaving, rather than arriving',
311
+ 'bd-back. A button, not a link — it may call history.back() and have no href at all — so it has no current state to show and takes a control shape instead: a filled hover, a pressed state, and its own 8px corner that the focus ring follows. Below md it steps up a type size and gains vertical padding, which is the touch target growing where fingers are.',
312
+ html`<bd-back label="Back"></bd-back>`
313
+ )}
314
+ ${group(
315
+ '6 · Global navigation, on the masthead',
316
+ 'bd-footer-nav. The links here are the page\'s own anchors, slotted in, with bd-divider-vertical between them — so the composed rhythm is 33px in a row (16 either side of a 1px divider) and 16px stacked, where the declared gap is 16 at both. Tab into it: the ring is the same one, which it was not before P6C.2.',
317
+ html`
318
+ <div style="background:var(--color-blue-600);padding:var(--spacing-24) var(--spacing-16)">
319
+ <bd-footer-nav>
320
+ <a href="/legal">Legal Information</a>
321
+ <bd-divider-vertical></bd-divider-vertical>
322
+ <a href="/privacy">Privacy Policy</a>
323
+ <bd-divider-vertical></bd-divider-vertical>
324
+ <a href="/cookies">Cookies</a>
325
+ </bd-footer-nav>
326
+ </div>`
327
+ )}
328
+ </div>`,
329
+ parameters: {
330
+ layout: 'padded',
331
+ docs : {
332
+ description: {
333
+ story: `Read this at 375 and at 1440. Four of the six change shape between those
334
+ widths and each change is a different mechanism: the anchor nav swaps a row
335
+ of links for a disclosure, the breadcrumb swaps a row for a stack of
336
+ full-width targets, the footer nav drops its dividers and stacks, and the
337
+ back control changes type size. The page switcher and the tab list both
338
+ simply wrap.
339
+
340
+ What should NOT differ across the six: the focus ring, the 3px underline
341
+ where there is one, and the ink scale. What should: everything that follows
342
+ from the responsibility — whether there is a current state at all, whether
343
+ the item is a link or a button, and whether hover is an invitation or a
344
+ no-op.`
345
+ }
346
+ }
347
+ }
348
+ };
349
+
350
+ /* ------------------------------------------------------- feedback & status - */
351
+
352
+ const TONES = ['info', 'success', 'warning', 'error'];
353
+
354
+ export const StatusFamily = {
355
+ name : 'Status Family',
356
+ render: () => html`
357
+ <p style="max-width:74ch;color:var(--color-text-secondary)">
358
+ One message surface, one filled chip and one outlined label, carrying the same four
359
+ tones. Every value here is read from the shared --status-* roles rather than from the
360
+ palette steps those roles happen to point at today.
361
+ </p>
362
+ <div style="display:grid;gap:var(--spacing-32)">
363
+ <div>
364
+ ${label('bd-alert · the feedback message: neutral ink, a 4px tone rule, --radius-md')}
365
+ <div style="display:grid;gap:var(--spacing-12)">
366
+ ${TONES.map(tone => html`
367
+ <bd-alert tone=${tone} heading="Heading.">A message that explains what happened.</bd-alert>
368
+ `)}
369
+ </div>
370
+ </div>
371
+ <div>
372
+ ${label('bd-badge · the filled status chip, above bd-tag · the outlined label')}
373
+ <div style="display:flex;flex-wrap:wrap;align-items:center;gap:var(--spacing-12)">
374
+ ${TONES.map(tone => html`<bd-badge tone=${tone}>${tone}</bd-badge>`)}
375
+ </div>
376
+ <div style="display:flex;flex-wrap:wrap;align-items:center;gap:var(--spacing-12);margin-top:var(--spacing-12)">
377
+ ${TONES.map(tone => html`<bd-tag tone=${tone}>${tone}</bd-tag>`)}
378
+ </div>
379
+ </div>
380
+ </div>`,
381
+ parameters: {
382
+ layout: 'padded',
383
+ docs : {
384
+ description: {
385
+ story: `Three components, four tones, one semantic system. Read down a column rather
386
+ than across a row: the info surface under bd-alert and the info tint under
387
+ bd-tag are the same value because both name \`--status-info-surface\`, not
388
+ because someone matched two palette steps by eye.
389
+
390
+ bd-badge and bd-tag are deliberately not identical, and P7C left both alone.
391
+ A tag is an outlined label — 1px \`--status-*-border\` around the plain tint.
392
+ A badge is a filled chip — no border, the stronger tint. Measured at 1440
393
+ they stand 24px and 23px tall, which is arithmetic rather than drift: the tag
394
+ spends its extra pixel on the border it draws. The difference you can see
395
+ maps to a difference that is real.
396
+
397
+ This story replaced a Banner vs Alert comparison that P6C.3 left here to put
398
+ a decision in front of a person. P7C answered it, and bd-banner was retired.
399
+ It was not in \`package.json\` exports and not in the component manifest, so
400
+ it was never part of the published surface; it had no consumer anywhere in
401
+ this repository outside its own stories; its first commit is titled "banner
402
+ component for testing"; and it drew the same four tinted surfaces as bd-alert
403
+ by naming \`--color-blue-50\` and its neighbours directly. That last point is
404
+ what made it worth removing rather than polishing. Retinting
405
+ \`--status-info-surface\` would have moved bd-alert, bd-tag and bd-badge and
406
+ left bd-banner behind, so the duplication was not only visual — it was
407
+ invisible to the token system that is supposed to hold this family together.`
408
+ }
409
+ }
410
+ }
411
+ };
@@ -0,0 +1,24 @@
1
+ import { css } from 'lit';
2
+
3
+ /** Styled entirely from design tokens — see npm run lint:tokens. */
4
+ export const visuallyHiddenCSS = css`
5
+ /* Removed from view but kept in the accessibility tree. Not display:none,
6
+ which would remove it from the tree as well. */
7
+ :host {
8
+ position: absolute;
9
+ /* no token: 1px is the clip idiom's own measure, not a border. It was
10
+ spelled --border-width-1, which resolves to the same pixel and reads as
11
+ a category error — the lint already sanctions the literal here, as it
12
+ does the -1px below. */
13
+ width: 1px;
14
+ height: 1px;
15
+ margin: -1px;
16
+ padding: 0;
17
+ overflow: hidden;
18
+ clip-path: inset(50%);
19
+ white-space: nowrap;
20
+ border: 0;
21
+ }
22
+ `;
23
+
24
+ export default visuallyHiddenCSS;
@@ -0,0 +1,16 @@
1
+ import { LitElement, html } from 'lit';
2
+ // Installs the design tokens into document scope; see src/tokens/tokens.js
3
+ import '../../tokens/tokens.js';
4
+ import { visuallyHiddenCSS } from './visually-hidden.css.js';
5
+
6
+ export class BdVisuallyHidden extends LitElement {
7
+ static styles = [visuallyHiddenCSS];
8
+
9
+ render() {
10
+ return html`
11
+ <slot></slot>
12
+ `;
13
+ }
14
+ }
15
+
16
+ customElements.define('bd-visually-hidden', BdVisuallyHidden);