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