@repobit/dex-system-design 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/README.md +43 -12
  3. package/package.json +6 -4
  4. package/schemas/component-manifest.json +207 -49
  5. package/schemas/manifest-omissions.json +2 -0
  6. package/src/components/accordion/accordion.css.js +12 -1
  7. package/src/components/agent-endpoints/agent-endpoints.js +1 -1
  8. package/src/components/alert/alert.css.js +22 -1
  9. package/src/components/anchor/anchor-nav.css.js +6 -1
  10. package/src/components/annotation/annotation.css.js +6 -1
  11. package/src/components/architecture.stories.js +6 -4
  12. package/src/components/avatar/avatar.js +37 -11
  13. package/src/components/avatar/avatar.stories.js +10 -6
  14. package/src/components/awards/awards-flex.css.js +31 -129
  15. package/src/components/awards/awards-flex.js +66 -116
  16. package/src/components/awards/awards-flex.stories.js +8 -6
  17. package/src/components/back/back.css.js +6 -1
  18. package/src/components/back/back.js +24 -12
  19. package/src/components/back/back.stories.js +3 -3
  20. package/src/components/badge/badge.js +6 -3
  21. package/src/components/badge/badge.stories.js +13 -9
  22. package/src/components/bento-grid/bento-grid.js +1 -1
  23. package/src/components/blockquote/blockquote.css.js +12 -3
  24. package/src/components/blockquote/blockquote.js +12 -5
  25. package/src/components/blockquote/blockquote.stories.js +6 -4
  26. package/src/components/button/button.css.js +46 -25
  27. package/src/components/button/button.js +44 -43
  28. package/src/components/button/button.stories.js +2 -2
  29. package/src/components/caption/caption.css.js +10 -0
  30. package/src/components/caption/caption.stories.js +4 -4
  31. package/src/components/carousel/carousel.css.js +19 -116
  32. package/src/components/carousel/carousel.js +70 -74
  33. package/src/components/carousel/carousel.stories.js +9 -8
  34. package/src/components/checkbox/checkbox.css.js +6 -1
  35. package/src/components/code/code.css.js +6 -1
  36. package/src/components/code/code.js +48 -7
  37. package/src/components/code/code.stories.js +7 -4
  38. package/src/components/divider/divider-horizontal.js +11 -3
  39. package/src/components/divider/divider-vertical.js +12 -5
  40. package/src/components/divider/divider.css.js +4 -1
  41. package/src/components/divider/divider.stories.js +6 -6
  42. package/src/components/dropdown/dropdown.js +67 -13
  43. package/src/components/dropdown/dropdown.stories.js +15 -14
  44. package/src/components/fieldset/fieldset.stories.js +41 -16
  45. package/src/components/footer/footer-nav-menu.css.js +6 -1
  46. package/src/components/footer/footer.css.js +6 -1
  47. package/src/components/header/header-code.js +1 -1
  48. package/src/components/header/header.css.js +9 -4
  49. package/src/components/heading/heading.stories.js +64 -31
  50. package/src/components/highlight/highlight.js +74 -34
  51. package/src/components/highlight/highlight.stories.js +5 -4
  52. package/src/components/icons/icon-element.js +49 -6
  53. package/src/components/icons/icons.stories.js +7 -0
  54. package/src/components/image/image.css.js +9 -98
  55. package/src/components/image/image.js +7 -2
  56. package/src/components/input/custom-form.stories.js +14 -19
  57. package/src/components/input/input-clipboard.css.js +6 -1
  58. package/src/components/input/input-clipboard.js +56 -8
  59. package/src/components/input/input.js +19 -2
  60. package/src/components/label/label.js +87 -1
  61. package/src/components/label/label.stories.js +21 -12
  62. package/src/components/link/link.css.js +52 -3
  63. package/src/components/link/link.js +52 -17
  64. package/src/components/link/link.stories.js +114 -3
  65. package/src/components/list/list-item/list-item.css.js +4 -6
  66. package/src/components/list/list-item/list-item.js +53 -5
  67. package/src/components/list/list-item/list-item.stories.js +22 -0
  68. package/src/components/list/list.js +27 -0
  69. package/src/components/modal/modal.css.js +6 -1
  70. package/src/components/pagination-dots/pagination-dots.css.js +161 -0
  71. package/src/components/pagination-dots/pagination-dots.js +202 -0
  72. package/src/components/pagination-dots/pagination-dots.stories.js +171 -0
  73. package/src/components/paragraph/paragraph.css.js +37 -1
  74. package/src/components/paragraph/paragraph.js +19 -2
  75. package/src/components/paragraph/paragraph.stories.js +40 -6
  76. package/src/components/picture/picture.css.js +8 -67
  77. package/src/components/picture/picture.js +15 -8
  78. package/src/components/pricing-cards/pricing-card.css.js +12 -2
  79. package/src/components/pricing-cards/pricing-card.js +4 -4
  80. package/src/components/progress/progress.js +24 -4
  81. package/src/components/progress/progress.stories.js +8 -6
  82. package/src/components/radio/radio.css.js +6 -1
  83. package/src/components/radio/radio.js +48 -3
  84. package/src/components/radio/radio.stories.js +1 -1
  85. package/src/components/shared/form-field.css.js +30 -4
  86. package/src/components/shared/token-scales.js +16 -0
  87. package/src/components/spinner/spinner.css.js +31 -4
  88. package/src/components/spinner/spinner.js +26 -4
  89. package/src/components/spinner/spinner.stories.js +10 -7
  90. package/src/components/switch/switch.css.js +21 -3
  91. package/src/components/switch/switch.js +8 -1
  92. package/src/components/switch/switch.stories.js +2 -1
  93. package/src/components/tab-list/tab-list.css.js +6 -1
  94. package/src/components/terminal/terminal-cursor.js +11 -0
  95. package/src/components/terminal/terminal-message.js +1 -1
  96. package/src/components/termsOfUse/terms.css.js +6 -1
  97. package/src/components/textarea/textarea.stories.js +23 -0
  98. package/src/components/tooltip/tooltip.css.js +24 -1
  99. package/src/components/tooltip/tooltip.js +135 -5
  100. package/src/components/tooltip/tooltip.stories.js +20 -14
  101. package/src/components/trust-panel/trust-panel.js +2 -2
  102. package/src/components/video/video.js +38 -3
  103. package/src/components/video/video.stories.js +10 -5
  104. package/src/components/video-player/video-player.css.js +6 -1
  105. package/src/tokens/elevation.stories.js +2 -3
  106. package/src/tokens/focus.stories.js +81 -15
  107. package/src/tokens/motion.stories.js +0 -6
  108. package/src/tokens/tokens.css +174 -97
  109. package/src/tokens/tokens.js +174 -97
  110. package/src/tokens/vertical-rhythm.stories.js +1 -1
  111. package/src/stories/Button.js +0 -20
  112. package/src/stories/Button.stories.js +0 -46
  113. package/src/stories/Configure.mdx +0 -364
  114. package/src/stories/Header.js +0 -45
  115. package/src/stories/Header.stories.js +0 -24
  116. package/src/stories/Page.js +0 -62
  117. package/src/stories/Page.stories.js +0 -20
  118. package/src/stories/assets/accessibility.png +0 -0
  119. package/src/stories/assets/accessibility.svg +0 -1
  120. package/src/stories/assets/addon-library.png +0 -0
  121. package/src/stories/assets/assets.png +0 -0
  122. package/src/stories/assets/avif-test-image.avif +0 -0
  123. package/src/stories/assets/context.png +0 -0
  124. package/src/stories/assets/discord.svg +0 -1
  125. package/src/stories/assets/docs.png +0 -0
  126. package/src/stories/assets/figma-plugin.png +0 -0
  127. package/src/stories/assets/github.svg +0 -1
  128. package/src/stories/assets/share.png +0 -0
  129. package/src/stories/assets/styling.png +0 -0
  130. package/src/stories/assets/testing.png +0 -0
  131. package/src/stories/assets/theming.png +0 -0
  132. package/src/stories/assets/tutorials.svg +0 -1
  133. package/src/stories/assets/youtube.svg +0 -1
  134. package/src/stories/button.css +0 -30
  135. package/src/stories/header.css +0 -32
  136. package/src/stories/page.css +0 -68
@@ -68,8 +68,11 @@
68
68
  t-comma, -0.275em in Bold, a third deeper than g -- and the tallest
69
69
  are grave and acute capitals at +0.977em. Measured per weight, ink
70
70
  spans 1.174 Light, 1.194 Regular, 1.219 Medium, 1.235 SemiBold,
71
- 1.252 Bold. Nothing may be set below the floor for its weight, which
72
- is why the display roles stay at tight and are not tightened further.
71
+ 1.252 Bold. Tight, 1.25, sits 0.002 under the Bold floor -- the
72
+ tallest accented capital and the deepest comma-below letter would
73
+ have to fall in consecutive lines, one above the other, to touch --
74
+ which is why the display roles stay at tight and are never tightened
75
+ further.
73
76
  Foundations/Typography/Vertical Rhythm reaches 1.231 for 48px Bold
74
77
  from canvas metrics; this is the same number from outline bounds. */
75
78
  --typography-lineHeight-130: 1.3;
@@ -230,13 +233,12 @@
230
233
  /* The CSS default curve. It was missing, and its absence was the single
231
234
  reason eleven component transitions could not be expressed in tokens:
232
235
  ease is not ease-in-out — it front-loads, and swapping one for the
233
- other is a visible change. Named after the keyword, as linear,
234
- ease-in and ease-out beside it are; smooth is the outlier that
235
- aliases a keyword rather than naming it. */
236
+ other is a visible change. Named after the keyword, as linear and
237
+ ease-out beside it are; smooth is the outlier that aliases a keyword
238
+ rather than naming it. ease-in and a bounce curve stood here too and
239
+ went on 2026-10-15, because nothing read either. */
236
240
  --transition-easing-ease: ease;
237
- --transition-easing-ease-in: ease-in;
238
241
  --transition-easing-ease-out: ease-out;
239
- --transition-easing-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
240
242
 
241
243
  /* ================================
242
244
  CORE SHADOW TOKENS
@@ -248,37 +250,62 @@
248
250
  0 4px 6px -4px rgb(0 0 0 / 0.1);
249
251
  --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1),
250
252
  0 8px 10px -6px rgb(0 0 0 / 0.1);
251
- --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
252
- --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);
253
+ /* The ladder stops at xl. --shadow-2xl and the inset --shadow-inner
254
+ stood beside it until 2026-10-15, and nothing read either. */
253
255
 
254
- /* Focus Shadows - Box Shadow Version */
255
- --shadow-focus-outline-blue: 0 0 0 3px rgba(6, 109, 255, 0.15);
256
- --shadow-focus-outline-red: 0 0 0 3px rgba(239, 68, 68, 0.15);
257
- --shadow-focus-outline-green: 0 0 0 3px rgba(34, 197, 94, 0.15);
256
+ /* The focus glow: --color-blue-500 at 15%, mixed from the palette. It
257
+ was rgba(6, 109, 255, 0.15) -- a blue one unit off blue-500 -- with a
258
+ red and a green beside it that were Tailwind's red-500 and green-500,
259
+ in no palette here. Nothing read the red or the green, so they went;
260
+ --form-input-focus-boxShadow reads this one. */
261
+ --shadow-focus-outline-blue: 0 0 0 3px color-mix(in srgb, var(--color-blue-500) 15%, transparent);
258
262
 
259
263
  /* Focus Outlines - Two-Color System for Universal Visibility */
260
264
  --focus-outline-primary: 0 0 0 2px var(--color-neutral-0),
261
265
  0 0 0 4px var(--color-blue-500);
262
- --focus-outline-secondary: 0 0 0 2px var(--color-neutral-0),
263
- 0 0 0 4px var(--color-neutral-600);
264
- --focus-outline-error: 0 0 0 2px var(--color-neutral-0),
265
- 0 0 0 4px var(--color-red-500);
266
- --focus-outline-success: 0 0 0 2px var(--color-neutral-0),
267
- 0 0 0 4px var(--color-green-500);
268
-
269
- /* The four above put the WHITE band against the control, which is what
270
- keeps them visible on a coloured hero. That fails on a control which
266
+
267
+ /* Secondary, error and success rings stood here until 2026-10-15.
268
+ Nothing read them -- every component rings with primary -- and the
269
+ success ring was green-500, 2.39:1 against white, under the 3:1 a
270
+ focus indicator needs. */
271
+
272
+ /* The one above puts the WHITE band against the control, which is what
273
+ keeps it visible on a coloured hero. That fails on a control which
271
274
  is itself white: bd-button-link variant="white" measured 1.00:1 for
272
275
  the inner band against its own fill and 2.38:1 for the blue band
273
276
  against a blue hero, so neither band reached the 3:1 WCAG 2.4.11
274
277
  asks of a focus indicator. This one inverts the pair -- dark band
275
278
  against the control, white band against the ground -- so the inner
276
- band carries the contrast whatever the control is sitting on. */
279
+ band carries the contrast whatever the control is sitting on.
280
+
281
+ This is also what the Figma library draws around a filled or
282
+ bordered button on a dark or brand ground (focus/ring-inverse).
283
+ Figma builds a ring from spread shadows, so every band in it is a
284
+ painted colour, and the band between control and ring has to be
285
+ chosen per surface. On a brand hero that painted neutral-900 band
286
+ reads as a black outline. bd-button does not use this one; it draws
287
+ the outline below, whose gap is not painted at all. */
277
288
  --focus-outline-inverse: 0 0 0 2px var(--color-neutral-900),
278
289
  0 0 0 4px var(--color-neutral-0);
279
290
 
280
- /* Traditional Outline Values for Fallback */
291
+ /* The CTA ring in code: one band, held off the control by
292
+ --focus-outline-offset. The offset leaves the gap TRANSPARENT, so it
293
+ is always the surface the control sits on -- white on a light page,
294
+ neutral-900 on a dark hero, blue on a brand one -- and never merges
295
+ into a white fill or a white border, which is the job the painted
296
+ inner band of every two-band ring above does by hand. Figma has no
297
+ offset outline, which is why its rings paint that gap and need one
298
+ style per surface; code does not.
299
+
300
+ Only the band's colour follows the ground. Blue on light, 4.53:1
301
+ against white. White on dark and brand, the one colour that clears
302
+ 3:1 on both: 4.53:1 on blue-500, 6.18 on blue-600, 8.56 on blue-700,
303
+ 17.97 on neutral-900. A blue band on a brand hero is 1.00:1.
304
+
305
+ An outline also survives forced-colors mode, where a box-shadow ring
306
+ is not drawn at all. bd-button reads these; see its FOCUS block. */
281
307
  --focus-outline-traditional: 2px solid var(--color-blue-500);
308
+ --focus-outline-traditional-inverse: 2px solid var(--color-neutral-0);
282
309
  --focus-outline-offset: 2px;
283
310
 
284
311
  /* The ring is a box-shadow, so it already follows the radius of the
@@ -428,7 +455,7 @@
428
455
  /* Subordinate text on an inverse surface. --color-text-inverse is the
429
456
  high-emphasis step there; this is the one below it, and until now the
430
457
  system had no such step at all -- the light-side -secondary, -muted and
431
- -subtle roles invert to 1.91, 2.73 and 3.85 against
458
+ -subtle roles invert to 1.91, 2.73 and 3.74 against
432
459
  --color-surface-inverse and cannot be used.
433
460
 
434
461
  Two components had already invented it independently and spelled it
@@ -469,6 +496,14 @@
469
496
  the link it borrowed falls to 2.27:1. */
470
497
  --color-text-brand-hover: var(--color-blue-700);
471
498
  --color-text-success: var(--color-green-800);
499
+ /* Warning text sits on the page, a card, surface-subtle (5.16) or its
500
+ own tint (--color-surface-warning, 5.59) -- not on surface-muted,
501
+ where it measures 4.49:1, a hair under 4.5. The same rule as
502
+ -subtle above: the role is right and the ground is wrong, so the
503
+ fix is the ground. Nothing in the package draws the pair today:
504
+ bd-tag and bd-badge draw this yellow through --status-warning-text,
505
+ on --status-warning-surface. The way a page reaches it is the
506
+ color="warning" value the text atoms take (token-scales.js). */
472
507
  --color-text-warning: var(--color-yellow-800);
473
508
  --color-text-error: var(--color-red-700);
474
509
 
@@ -528,7 +563,18 @@
528
563
  -subtle is a decorative hairline between things that already belong
529
564
  together, not the edge of anything actionable, and disabled controls
530
565
  are exempt under 1.4.3. Do not reach for -subtle to outline a
531
- control. */
566
+ control.
567
+
568
+ -default's 3.23 holds on white and nowhere darker: on a band it is
569
+ 2.88 (surface-subtle) and 2.51 (surface-muted), and on the brand
570
+ tint 2.99. So a control drawn in it carries a fill of its own --
571
+ surface-default, the ground it was measured on -- and its edge is
572
+ read against that fill wherever it is placed. A field already does
573
+ (--form-input-default-backgroundColor). A control with no fill, or
574
+ whose fill IS this colour (the switch's off track), belongs on the
575
+ page or a card, not on a band. The rule is where it goes; a darker
576
+ -default would move every field edge in the system to fix a case
577
+ nothing in the package draws. */
532
578
  --color-border-subtle: var(--color-neutral-200);
533
579
  --color-border-default: var(--color-neutral-400);
534
580
  --color-border-strong: var(--color-neutral-900);
@@ -592,7 +638,9 @@
592
638
  this theme, which is why the borrowing never showed -- and both must
593
639
  flip to near-black in a dark one, which would turn every label and
594
640
  mark dark on its blue or red fill. White clears every action fill:
595
- 4.53 to 10.51:1. Measured in the Figma Dark mode study. */
641
+ 4.53 to 10.51:1 on the blue and red ones, 13.28 to 21:1 on the
642
+ near-black secondary ones. Measured in the Figma Dark mode study,
643
+ and re-measured on the live tokens 2026-10-15. */
596
644
  --color-action-on-fill: var(--color-neutral-0);
597
645
 
598
646
  /* ================================
@@ -721,10 +769,14 @@
721
769
  takes, it is whether the longest UNBREAKABLE WORD fits the column.
722
770
  The column is the viewport minus twice --grid-padding-*, so a 320px
723
771
  phone gives type 288px -- 10% of the screen is gutter. Against that
724
- column the ceiling for the worst realistic compound (Finnish
725
- "Henkilollisyyssuoja", 9.07px of width per px of size) is 31px.
726
- heading-h1 is 48. It overflowed at 375 as well as at 320, in German
727
- and Finnish both.
772
+ column, the widest real words in the nine shipping languages --
773
+ harvested from live localized copy, see type-ceiling-words.js and
774
+ plans/LATER.md entry 8 -- set two ceilings: 28px for any copy
775
+ (Swedish "kalenderinbjudningar", 10.16px of width per px of size)
776
+ and 31px for headline copy (German "Gründungsmitglied", 9.05).
777
+ heading-h1 is 48. It overflowed at 375 as well as at 320. (This
778
+ rested on a Finnish word once; Finnish is not a market, and three
779
+ real words beat it.)
728
780
 
729
781
  WHY NOT A BREAKPOINT STEP. Tried first and abandoned, measured:
730
782
  stepping h1 to 36 below sm still overflows at 320 (needs 327 of
@@ -766,20 +818,24 @@
766
818
  numbers: 30 27 24 21 18 16 for h1 through h6. Its ratios are 1.11,
767
819
  1.13, 1.14, 1.17, 1.13 -- near-even, against the desktop ladder's
768
820
  irregular 1.33, 1.13, 1.33, 1.20, 1.11. A phone has less range to
769
- spend (16 to the 31px ceiling, a factor of 1.94, where desktop has
770
- 18 to 48, a factor of 2.67), so the ladder has to compress, and
771
- compressing it evenly is what keeps six levels distinguishable.
772
- Measured: h1 at 30 needs 272px of a 288px column, so there is 16px
773
- of margin for a word longer than any tested.
821
+ spend (16 to the 31px headline ceiling, a factor of 1.94, where
822
+ desktop has 18 to 48, a factor of 2.67), so the ladder has to
823
+ compress, and compressing it evenly is what keeps six levels
824
+ distinguishable. Measured on the harvest: h1 at 30 sets the widest
825
+ headline word in 272px of a 288px column. The widest word of any
826
+ tier would need 305, so a headline word wider than 960px per 100px
827
+ of size is a stated copy constraint (LATER.md entry 8) rather than
828
+ a margin the ladder holds -- none of the five such words is a
829
+ headline today.
774
830
 
775
831
  WHAT IS DELIBERATELY NOT FLUID.
776
832
  - Every role at 24px and below except body-lead. Nothing that small
777
833
  overflows, and the small end's own failure is measure, not
778
834
  overflow -- see below.
779
835
  - display-lg, display-xl, display-2xl, display-3xl (60 to 128px).
780
- Above display-md the family has NO mobile identity
781
- to give it: five roles would all have to squeeze between 30 and
782
- the 31px ceiling. They are desktop-only, and a component that
836
+ Above display-md the family has NO mobile identity to give it:
837
+ four roles would all have to squeeze between 30 and the 31px
838
+ headline ceiling. They are desktop-only, and a component that
783
839
  needs one of them on a phone should reach for a heading role
784
840
  instead. Recorded rather than papered over.
785
841
  - body-regular at 16px. It runs 40 characters per line on a 288px
@@ -1011,6 +1067,11 @@
1011
1067
  --typography-caption-default-fontFamily: var(--typography-fontFamily-sans);
1012
1068
  --typography-caption-default-color: var(--color-text-muted);
1013
1069
 
1070
+ /* "small" is not smaller. It is caption-default with the tracking
1071
+ opened to wide -- 0.025em, which is the design's caption/small at
1072
+ 2.5% -- and every other axis equal. The repeated axes are the role
1073
+ being complete, as every role is, not a second copy to remove;
1074
+ bd-caption size="sm" reads all five. */
1014
1075
  --typography-caption-small-fontSize: var(--typography-fontSize-xs);
1015
1076
  --typography-caption-small-fontWeight: var(--typography-fontWeight-normal);
1016
1077
  --typography-caption-small-lineHeight: var(--typography-lineHeight-normal);
@@ -1112,28 +1173,43 @@
1112
1173
  COMPONENT TOKENS - FORM
1113
1174
  ================================ */
1114
1175
 
1115
- /* Form Label Tokens */
1116
- --form-label-default-fontSize: var(--typography-fontSize-sm);
1117
- --form-label-default-fontWeight: var(--typography-fontWeight-medium);
1118
- --form-label-default-lineHeight: var(--typography-lineHeight-normal);
1119
- --form-label-default-letterSpacing: var(--typography-letterSpacing-normal);
1120
- --form-label-default-fontFamily: var(--typography-fontFamily-sans);
1176
+ /* Form Label Tokens
1177
+
1178
+ The type of a field's label is the label role's, read through: the
1179
+ default and small rungs were the same five values as
1180
+ --typography-label-default-* and -small-*, written out a second time,
1181
+ so a change to the role would have reached bd-text and missed every
1182
+ form. Colour and margin stay here; they are the form's own and no
1183
+ role carries them.
1184
+
1185
+ Large differs on one axis. Its size is 18px where label-large is
1186
+ 16px, set to the large field's own text (--form-input-large-fontSize)
1187
+ so the label and the value read at the same step; a field's own
1188
+ label at size lg, bd-label size=lg and the bd-fieldset legend all
1189
+ render it. That size stays a
1190
+ primitive -- no label role sits at 18px -- and the other four axes
1191
+ are label-large's. */
1192
+ --form-label-default-fontSize: var(--typography-label-default-fontSize);
1193
+ --form-label-default-fontWeight: var(--typography-label-default-fontWeight);
1194
+ --form-label-default-lineHeight: var(--typography-label-default-lineHeight);
1195
+ --form-label-default-letterSpacing: var(--typography-label-default-letterSpacing);
1196
+ --form-label-default-fontFamily: var(--typography-label-default-fontFamily);
1121
1197
  --form-label-default-color: var(--color-text-primary);
1122
1198
  --form-label-default-marginBottom: var(--spacing-4);
1123
1199
 
1124
1200
  --form-label-large-fontSize: var(--typography-fontSize-lg);
1125
- --form-label-large-fontWeight: var(--typography-fontWeight-medium);
1126
- --form-label-large-lineHeight: var(--typography-lineHeight-normal);
1127
- --form-label-large-letterSpacing: var(--typography-letterSpacing-normal);
1128
- --form-label-large-fontFamily: var(--typography-fontFamily-sans);
1201
+ --form-label-large-fontWeight: var(--typography-label-large-fontWeight);
1202
+ --form-label-large-lineHeight: var(--typography-label-large-lineHeight);
1203
+ --form-label-large-letterSpacing: var(--typography-label-large-letterSpacing);
1204
+ --form-label-large-fontFamily: var(--typography-label-large-fontFamily);
1129
1205
  --form-label-large-color: var(--color-text-primary);
1130
1206
  --form-label-large-marginBottom: var(--spacing-8);
1131
1207
 
1132
- --form-label-small-fontSize: var(--typography-fontSize-xs);
1133
- --form-label-small-fontWeight: var(--typography-fontWeight-medium);
1134
- --form-label-small-lineHeight: var(--typography-lineHeight-normal);
1135
- --form-label-small-letterSpacing: var(--typography-letterSpacing-wide);
1136
- --form-label-small-fontFamily: var(--typography-fontFamily-sans);
1208
+ --form-label-small-fontSize: var(--typography-label-small-fontSize);
1209
+ --form-label-small-fontWeight: var(--typography-label-small-fontWeight);
1210
+ --form-label-small-lineHeight: var(--typography-label-small-lineHeight);
1211
+ --form-label-small-letterSpacing: var(--typography-label-small-letterSpacing);
1212
+ --form-label-small-fontFamily: var(--typography-label-small-fontFamily);
1137
1213
  --form-label-small-color: var(--color-text-primary);
1138
1214
  --form-label-small-marginBottom: var(--spacing-4);
1139
1215
 
@@ -1156,11 +1232,14 @@
1156
1232
  three times. Changing them changes no pixel; it changes what the
1157
1233
  package tells a consumer the height is.
1158
1234
 
1159
- The line box these leave is 2px taller than the content box, because
1160
- the derivation counts padding but not the 1px border on each edge.
1161
- Measured at every size: no glyph clips, because an input centres its
1162
- line and paints into the padding. Correcting it would move a field
1163
- off its button, so it stays a recorded fact rather than a fix. */
1235
+ The derivation counts padding but not the 1px border on each edge,
1236
+ and the box is border-box, so these heights leave the line box 2px
1237
+ taller than the content box. An input hides that -- it centres its
1238
+ line and paints into the padding -- but a select clips at the
1239
+ content box, and at md its descenders lost their bottoms.
1240
+ Correcting the height would move a field off its button, so the
1241
+ border comes out of the block padding instead: see the note after
1242
+ the size rules in shared/form-field.css.js. */
1164
1243
  --form-input-small-height: calc(
1165
1244
  var(--spacing-8) * 2 + var(--typography-fontSize-sm) * var(--typography-lineHeight-tight)
1166
1245
  );
@@ -1207,16 +1286,13 @@
1207
1286
 
1208
1287
  --form-input-error-backgroundColor: var(--status-error-surface);
1209
1288
  --form-input-error-borderColor: var(--status-error-accent);
1210
- --form-input-error-placeholderColor: var(--color-red-600);
1211
1289
 
1212
1290
  --form-input-success-backgroundColor: var(--status-success-surface);
1213
1291
  --form-input-success-borderColor: var(--color-green-600);
1214
- --form-input-success-placeholderColor: var(--color-green-700);
1215
1292
 
1216
1293
  --form-input-disabled-backgroundColor: var(--color-surface-disabled);
1217
1294
  --form-input-disabled-borderColor: var(--color-border-disabled);
1218
1295
  --form-input-disabled-color: var(--color-text-subtle);
1219
- --form-input-disabled-placeholderColor: var(--color-neutral-400);
1220
1296
 
1221
1297
  /* Form Help Text Tokens */
1222
1298
  --form-help-text-default-fontSize: var(--typography-fontSize-xs);
@@ -1254,9 +1330,6 @@
1254
1330
  32, which is what a form actually wants and what the value is set to
1255
1331
  here. */
1256
1332
  --form-fieldSpacing: var(--spacing-24);
1257
- --form-sectionSpacing: var(--spacing-32);
1258
- --form-labelSpacing: var(--spacing-4);
1259
- --form-helpTextSpacing: var(--spacing-4);
1260
1333
 
1261
1334
  /* ================================
1262
1335
  COMPONENT TOKENS - BUTTON
@@ -1286,15 +1359,14 @@
1286
1359
  --button-large-gap: var(--spacing-8);
1287
1360
  --button-large-borderRadius: var(--radius-lg);
1288
1361
 
1289
- /* Button Default State */
1290
- --button-default-backgroundColor: var(--color-neutral-0);
1291
- --button-default-borderColor: var(--color-neutral-400);
1292
- --button-default-borderWidth: var(--border-width-1);
1293
- --button-default-color: var(--color-neutral-900);
1294
- --button-default-fontFamily: var(--typography-fontFamily-sans);
1295
- --button-default-fontWeight: var(--typography-fontWeight-medium);
1296
- --button-default-lineHeight: var(--typography-lineHeight-normal);
1297
-
1362
+ /* Removed 2026-10-15, because nothing read them: the seven
1363
+ --button-default-* (a state no variant draws), and
1364
+ --button-shared-focus-boxShadow, -disabled-opacity and
1365
+ -disabled-cursor (the button draws focus with the outline below and
1366
+ disabled through its own rules). Likewise the three
1367
+ --form-input-*-placeholderColor tokens, the --form-section-,
1368
+ -label- and -helpTextSpacing trio, and two --layout-awards- widths.
1369
+ None was mirrored in Figma, which carries no component tokens. */
1298
1370
  /* Button Shared Tokens */
1299
1371
  --button-shared-fontFamily: var(--typography-fontFamily-sans);
1300
1372
  --button-shared-fontWeight: var(--typography-fontWeight-medium);
@@ -1307,9 +1379,6 @@
1307
1379
  --button-shared-transition-easing: var(--transition-easing-smooth);
1308
1380
  --button-shared-focus-outline: var(--focus-outline-traditional);
1309
1381
  --button-shared-focus-outlineOffset: var(--focus-outline-offset);
1310
- --button-shared-focus-boxShadow: var(--focus-outline-primary);
1311
- --button-shared-disabled-opacity: 0.6;
1312
- --button-shared-disabled-cursor: not-allowed;
1313
1382
 
1314
1383
  /* ---- variant colours -------------------------------------------
1315
1384
  Named for the kind attribute they serve, because that is the public
@@ -1330,10 +1399,12 @@
1330
1399
  wiring them up unchanged would have moved pixels.
1331
1400
 
1332
1401
  The per-variant -focus and -disabled sets are gone. The component
1333
- draws one focus ring for every variant, from --focus-outline-primary,
1334
- and one shared disabled treatment; thirty tokens described per-variant
1335
- versions of both that nothing rendered. --button-empty-* went with
1336
- them: there is no empty kind. */
1402
+ draws its focus ring as an offset outline -- the blue one through
1403
+ --button-shared-focus-outline by default, the white one from
1404
+ --focus-outline-traditional-inverse under surface="dark" and on
1405
+ white and outline-white -- and one shared disabled treatment;
1406
+ thirty tokens described per-variant versions of both that nothing
1407
+ rendered. --button-empty-* went with them: there is no empty kind. */
1337
1408
 
1338
1409
  /* primary: blue fill */
1339
1410
  --button-primary-background-default: var(--color-action-primary);
@@ -1548,8 +1619,11 @@
1548
1619
  /* Accessibility Spacing Tokens
1549
1620
  -----------------------------------------------*/
1550
1621
  /* Touch Target Sizes - WCAG 2.1 Success Criterion 2.5.5 (AAA) and 2.5.8 (AA) */
1551
- --touch-target-size: 44px; /* Minimum touch target size (44px × 44px) */
1552
- --touch-target-spacing: 8px; /* Minimum space between touch targets */
1622
+ /* The dimension steps that carry these values, rather than px
1623
+ literals beside them: a target is matched to a finger, not to the
1624
+ reader's text size, so it is px, which --dimension-* is. */
1625
+ --touch-target-size: var(--dimension-44); /* Minimum touch target size (44px × 44px) */
1626
+ --touch-target-spacing: var(--dimension-8); /* Minimum space between touch targets */
1553
1627
 
1554
1628
  /* Readable Line Lengths - For optimal readability */
1555
1629
  --content-width-readable: 70ch; /* Approximately 70 characters per line */
@@ -1557,18 +1631,21 @@
1557
1631
 
1558
1632
  /** GRID AND BREAKPOINT TOKENS
1559
1633
 
1560
- These have no consumer in this package and are kept deliberately.
1561
- A media condition cannot read a custom property — @media
1634
+ The breakpoint tokens have no consumer in this package and are kept
1635
+ deliberately. A media condition cannot read a custom property — @media
1562
1636
  (max-width: var(--breakpoint-sm)) is not valid CSS — so a breakpoint
1563
1637
  token can never be referenced the way a colour is. It exists so the
1564
1638
  six values have one place to be read from, by the lint that checks
1565
1639
  media queries against them and by anything generating CSS. The grid
1566
- tokens are the same case: a layout that wants them reads them, and
1567
- nothing in the atom layer does.
1568
-
1569
- They are the exception. Everything else here that nothing references
1570
- is dead weight, and the OLD VALUES and FONT TOKENS blocks that used
1571
- to sit below were removed for exactly that reason.
1640
+ tokens below are read: --grid-container-max-* and --grid-padding-*
1641
+ are the page column, through shared/ensemble.css.js and layout.css,
1642
+ and the header and compare read them too. --grid-gutter-* has no
1643
+ reader outside the blog's own token copy, and carries the same
1644
+ values as --grid-padding-*.
1645
+
1646
+ The breakpoints are the exception. Everything else here that nothing
1647
+ references is dead weight, and the OLD VALUES and FONT TOKENS blocks
1648
+ that used to sit below were removed for exactly that reason.
1572
1649
  */
1573
1650
  /* Grid container max widths */
1574
1651
  --grid-container-max-xs: 100%; /* mobile full width */
@@ -1617,18 +1694,18 @@
1617
1694
 
1618
1695
  /* Awards section — Orbit Frame 14 (node 1882:9342) */
1619
1696
  --layout-awards-section-background: var(--color-blue-50);
1620
- --layout-awards-banner-max-width: 37.5rem; /* legacy narrow cap; prefer cluster */
1621
1697
  --layout-awards-cluster-max-width: 49.5625rem; /* 793px — trust banner column */
1622
1698
  --layout-awards-intro-max-width: 39.4375rem; /* 631px — headline stack */
1623
- /* Legacy: narrow lower block from Orbit; prefer --layout-ensemble-content-max for compare-aligned grids */
1624
- --layout-awards-content-max-width: 53.0625rem; /* 849px */
1625
- /* There is no page-width token. The page column is an implementation --
1699
+ /* The page column has no width token of its own. --content-width-max,
1700
+ above, is a 1200px cap that no component reads; only the blog's own
1701
+ token copy aliases it. The page column is an implementation --
1626
1702
  src/components/shared/ensemble.css.js -- on the grid container scale
1627
1703
  above (--grid-container-max-* with --grid-padding-*), which is what
1628
1704
  Foundations/Grid System documented and nothing had built. A width token
1629
1705
  here is how six ensembles came to hold one literal each and seven other
1630
- modules a different one. This padding step stays only because the blog
1631
- still reads it. */
1706
+ modules a different one. This padding step stays because bd-features
1707
+ reads it for its inline padding; the blog declares its own copy and
1708
+ does not read this one. */
1632
1709
  --layout-ensemble-inline-padding: var(--spacing-24);
1633
1710
 
1634
1711