@godxjp/ui 28.8.0 → 28.10.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 (271) hide show
  1. package/agent/START-HERE.md +193 -0
  2. package/agent/anti-ai-tells.json +158 -0
  3. package/agent/components/Accordion.json +60 -0
  4. package/agent/components/AccountChip.json +59 -0
  5. package/agent/components/Actions.json +78 -0
  6. package/agent/components/Activity.json +80 -0
  7. package/agent/components/Affix.json +78 -0
  8. package/agent/components/Alert.json +65 -0
  9. package/agent/components/AlertDialog.json +109 -0
  10. package/agent/components/AlertDialogRoot.json +52 -0
  11. package/agent/components/Anchor.json +119 -0
  12. package/agent/components/AppLauncher.json +95 -0
  13. package/agent/components/AppProvider.json +105 -0
  14. package/agent/components/AppSettingPicker.json +88 -0
  15. package/agent/components/AppSettingToggle.json +70 -0
  16. package/agent/components/AppShell.json +159 -0
  17. package/agent/components/AreaChart.json +105 -0
  18. package/agent/components/AspectRatio.json +38 -0
  19. package/agent/components/Attachments.json +76 -0
  20. package/agent/components/AuthAccountSummary.json +64 -0
  21. package/agent/components/AuthDivider.json +35 -0
  22. package/agent/components/AuthFooter.json +48 -0
  23. package/agent/components/AuthIdentity.json +42 -0
  24. package/agent/components/AuthShell.json +108 -0
  25. package/agent/components/AuthStack.json +21 -0
  26. package/agent/components/Avatar.json +89 -0
  27. package/agent/components/Badge.json +96 -0
  28. package/agent/components/Banner.json +48 -0
  29. package/agent/components/BarChart.json +108 -0
  30. package/agent/components/BranchScopePicker.json +89 -0
  31. package/agent/components/Breadcrumb.json +54 -0
  32. package/agent/components/Button.json +133 -0
  33. package/agent/components/Calendar.json +259 -0
  34. package/agent/components/Callout.json +46 -0
  35. package/agent/components/Card.json +112 -0
  36. package/agent/components/CardBar.json +49 -0
  37. package/agent/components/CardContent.json +51 -0
  38. package/agent/components/Carousel.json +50 -0
  39. package/agent/components/Cascader.json +209 -0
  40. package/agent/components/CenteredShell.json +66 -0
  41. package/agent/components/ChatBubble.json +100 -0
  42. package/agent/components/ChatBubbleList.json +64 -0
  43. package/agent/components/ChatComposer.json +160 -0
  44. package/agent/components/ChatSuggestion.json +86 -0
  45. package/agent/components/Checkbox.json +68 -0
  46. package/agent/components/CheckboxGroup.json +96 -0
  47. package/agent/components/CodeBlock.json +64 -0
  48. package/agent/components/Collapsible.json +74 -0
  49. package/agent/components/ColorPicker.json +87 -0
  50. package/agent/components/Command.json +168 -0
  51. package/agent/components/CommandPalette.json +84 -0
  52. package/agent/components/CompactBarTrend.json +101 -0
  53. package/agent/components/Conversations.json +82 -0
  54. package/agent/components/CredentialReveal.json +93 -0
  55. package/agent/components/DataState.json +79 -0
  56. package/agent/components/DataTable.json +268 -0
  57. package/agent/components/DatePicker.json +275 -0
  58. package/agent/components/Descriptions.json +67 -0
  59. package/agent/components/Dialog.json +78 -0
  60. package/agent/components/DraggablePanel.json +106 -0
  61. package/agent/components/DropdownMenu.json +102 -0
  62. package/agent/components/EmptyState.json +83 -0
  63. package/agent/components/ErrorSurface.json +128 -0
  64. package/agent/components/FeatureList.json +43 -0
  65. package/agent/components/Field.json +64 -0
  66. package/agent/components/FilterBar.json +99 -0
  67. package/agent/components/Flex.json +153 -0
  68. package/agent/components/FloatButton.json +91 -0
  69. package/agent/components/Form.json +87 -0
  70. package/agent/components/FormErrors.json +51 -0
  71. package/agent/components/FormField.json +137 -0
  72. package/agent/components/FormFieldArray.json +39 -0
  73. package/agent/components/FormFieldControl.json +129 -0
  74. package/agent/components/FormRoot.json +122 -0
  75. package/agent/components/Heading.json +61 -0
  76. package/agent/components/HoverCard.json +55 -0
  77. package/agent/components/Icon.json +60 -0
  78. package/agent/components/InfiniteQueryState.json +58 -0
  79. package/agent/components/Input.json +122 -0
  80. package/agent/components/InputOTP.json +106 -0
  81. package/agent/components/Label.json +43 -0
  82. package/agent/components/LegalDocumentShell.json +102 -0
  83. package/agent/components/Legend.json +42 -0
  84. package/agent/components/LineChart.json +103 -0
  85. package/agent/components/Link.json +41 -0
  86. package/agent/components/ListRow.json +92 -0
  87. package/agent/components/Logo.json +85 -0
  88. package/agent/components/Marquee.json +91 -0
  89. package/agent/components/Masonry.json +82 -0
  90. package/agent/components/MasterDetail.json +95 -0
  91. package/agent/components/MegaMenu.json +120 -0
  92. package/agent/components/MobileShell.json +73 -0
  93. package/agent/components/NavList.json +63 -0
  94. package/agent/components/NumberInput.json +158 -0
  95. package/agent/components/OrgSwitcher.json +89 -0
  96. package/agent/components/OverlayPortalProvider.json +42 -0
  97. package/agent/components/PageContainer.json +181 -0
  98. package/agent/components/Pagination.json +132 -0
  99. package/agent/components/Paragraph.json +40 -0
  100. package/agent/components/PasswordInput.json +79 -0
  101. package/agent/components/PasswordStrength.json +51 -0
  102. package/agent/components/PermissionMatrix.json +81 -0
  103. package/agent/components/PieChart.json +99 -0
  104. package/agent/components/Popover.json +110 -0
  105. package/agent/components/PrefetchLink.json +65 -0
  106. package/agent/components/Progress.json +79 -0
  107. package/agent/components/Prose.json +57 -0
  108. package/agent/components/QrCode.json +62 -0
  109. package/agent/components/Radio.json +98 -0
  110. package/agent/components/RadioGroup.json +91 -0
  111. package/agent/components/RangeTimeline.json +80 -0
  112. package/agent/components/Rating.json +92 -0
  113. package/agent/components/ResizablePanel.json +69 -0
  114. package/agent/components/ResponsiveGrid.json +77 -0
  115. package/agent/components/Reveal.json +70 -0
  116. package/agent/components/ScrollArea.json +104 -0
  117. package/agent/components/SearchInput.json +98 -0
  118. package/agent/components/Segmented.json +96 -0
  119. package/agent/components/Select.json +397 -0
  120. package/agent/components/Separator.json +86 -0
  121. package/agent/components/ServiceCatalogCta.json +46 -0
  122. package/agent/components/ServiceLauncherCard.json +86 -0
  123. package/agent/components/ServiceRolePanel.json +83 -0
  124. package/agent/components/Sheet.json +85 -0
  125. package/agent/components/Sidebar.json +118 -0
  126. package/agent/components/Skeleton.json +57 -0
  127. package/agent/components/SkeletonArticle.json +71 -0
  128. package/agent/components/SkeletonAvatar.json +50 -0
  129. package/agent/components/SkeletonButton.json +57 -0
  130. package/agent/components/SkeletonForm.json +52 -0
  131. package/agent/components/SkeletonImage.json +37 -0
  132. package/agent/components/SkeletonInput.json +51 -0
  133. package/agent/components/SkeletonNode.json +42 -0
  134. package/agent/components/SkeletonRows.json +49 -0
  135. package/agent/components/SkeletonTable.json +45 -0
  136. package/agent/components/Slider.json +160 -0
  137. package/agent/components/SplitPane.json +66 -0
  138. package/agent/components/StatCard.json +83 -0
  139. package/agent/components/Steps.json +95 -0
  140. package/agent/components/Swatch.json +41 -0
  141. package/agent/components/Switch.json +81 -0
  142. package/agent/components/Table.json +112 -0
  143. package/agent/components/Tabs.json +158 -0
  144. package/agent/components/TagInput.json +105 -0
  145. package/agent/components/Text.json +201 -0
  146. package/agent/components/Textarea.json +126 -0
  147. package/agent/components/ThoughtChain.json +76 -0
  148. package/agent/components/Thumbnail.json +70 -0
  149. package/agent/components/TimePicker.json +200 -0
  150. package/agent/components/TimeRangePicker.json +90 -0
  151. package/agent/components/Timeline.json +47 -0
  152. package/agent/components/TimelineGrid.json +92 -0
  153. package/agent/components/Title.json +67 -0
  154. package/agent/components/Toaster.json +42 -0
  155. package/agent/components/Toggle.json +90 -0
  156. package/agent/components/ToggleGroup.json +102 -0
  157. package/agent/components/Toolbar.json +120 -0
  158. package/agent/components/Tooltip.json +110 -0
  159. package/agent/components/Topbar.json +83 -0
  160. package/agent/components/TopbarItem.json +79 -0
  161. package/agent/components/Transfer.json +141 -0
  162. package/agent/components/Tree.json +185 -0
  163. package/agent/components/TreeSelect.json +232 -0
  164. package/agent/components/TwoFactorSetup.json +79 -0
  165. package/agent/components/Typography.json +42 -0
  166. package/agent/components/Upload.json +221 -0
  167. package/agent/components/UploadCropDialog.json +60 -0
  168. package/agent/components/VisuallyHidden.json +20 -0
  169. package/agent/components/Welcome.json +65 -0
  170. package/agent/components/formatDate.json +46 -0
  171. package/agent/components/inertiaUpload.json +32 -0
  172. package/agent/components/useZodForm.json +39 -0
  173. package/agent/components-index.json +884 -0
  174. package/agent/components.json +15507 -0
  175. package/agent/index.json +56 -0
  176. package/agent/llms.txt +32 -0
  177. package/agent/patterns/account-recovery-settings.json +19 -0
  178. package/agent/patterns/async-data-state.json +20 -0
  179. package/agent/patterns/auth-recovery-panels.json +29 -0
  180. package/agent/patterns/badge-coloring.json +14 -0
  181. package/agent/patterns/common-fixes.json +16 -0
  182. package/agent/patterns/confirm-destructive.json +11 -0
  183. package/agent/patterns/data-table-page.json +18 -0
  184. package/agent/patterns/deferred-loading.json +12 -0
  185. package/agent/patterns/error-pages.json +28 -0
  186. package/agent/patterns/inertia-detail-page.json +13 -0
  187. package/agent/patterns/inertia-list-page.json +15 -0
  188. package/agent/patterns/inertia-persistent-layout.json +14 -0
  189. package/agent/patterns/organization-memberships.json +19 -0
  190. package/agent/patterns/page-sections.json +18 -0
  191. package/agent/patterns/settings-page-responsive.json +18 -0
  192. package/agent/patterns/settings-section-rows.json +23 -0
  193. package/agent/patterns/signup-form.json +13 -0
  194. package/agent/patterns/topbar-account-chip.json +18 -0
  195. package/agent/patterns/transactional-email.json +22 -0
  196. package/agent/patterns-index.json +323 -0
  197. package/agent/patterns.json +342 -0
  198. package/agent/rules.json +237 -0
  199. package/agent/tokens.json +8422 -0
  200. package/agent/vocabulary.json +198 -0
  201. package/dist/components/data-entry/input.js +8 -1
  202. package/dist/components/layout/flex.d.ts +2 -2
  203. package/dist/components/layout/flex.js +2 -0
  204. package/dist/components/ui/tag-input.d.ts +10 -0
  205. package/dist/components/ui/tag-input.js +35 -2
  206. package/dist/contracts/measurement.json +1 -1
  207. package/dist/i18n/messages/en.json +23 -1
  208. package/dist/i18n/messages/ja.json +21 -1
  209. package/dist/i18n/messages/vi.json +21 -1
  210. package/dist/lib/variants.js +4 -1
  211. package/dist/props/components/data-entry.prop.d.ts +21 -2
  212. package/dist/props/components/layout.prop.d.ts +42 -0
  213. package/dist/props/registry.d.ts +9 -0
  214. package/dist/props/registry.js +6 -0
  215. package/dist/props/vocabulary/layout.prop.d.ts +1 -1
  216. package/dist/styles/base.css +47 -14
  217. package/dist/styles/card-layout.css +6 -6
  218. package/dist/styles/chart-layout.css +6 -6
  219. package/dist/styles/control.css +41 -6
  220. package/dist/styles/data-display-layout.css +21 -6
  221. package/dist/styles/density.css +2 -0
  222. package/dist/styles/dialog-layout.css +4 -1
  223. package/dist/styles/focus-ring.css +4 -1
  224. package/dist/styles/layout.css +30 -3
  225. package/dist/styles/navigation-layout.css +3 -1
  226. package/dist/styles/shell-layout.css +27 -21
  227. package/dist/styles/table-layout.css +50 -9
  228. package/dist/styles/text-layout.css +94 -23
  229. package/dist/tokens/components/activity.css +13 -4
  230. package/dist/tokens/components/attachments.css +1 -1
  231. package/dist/tokens/components/badge.css +1 -1
  232. package/dist/tokens/components/card.css +28 -7
  233. package/dist/tokens/components/chart.css +4 -1
  234. package/dist/tokens/components/chat-composer.css +4 -1
  235. package/dist/tokens/components/control.css +69 -30
  236. package/dist/tokens/components/conversations.css +4 -1
  237. package/dist/tokens/components/data-display.css +42 -15
  238. package/dist/tokens/components/data-entry.css +8 -2
  239. package/dist/tokens/components/descriptions.css +1 -1
  240. package/dist/tokens/components/feedback.css +8 -5
  241. package/dist/tokens/components/float-button.css +8 -2
  242. package/dist/tokens/components/legal-document.css +12 -3
  243. package/dist/tokens/components/logo.css +15 -6
  244. package/dist/tokens/components/mega-menu.css +14 -5
  245. package/dist/tokens/components/navigation.css +37 -13
  246. package/dist/tokens/components/segmented.css +9 -2
  247. package/dist/tokens/components/separator.css +4 -1
  248. package/dist/tokens/components/shell.css +96 -31
  249. package/dist/tokens/components/table.css +13 -6
  250. package/dist/tokens/components/thought-chain.css +4 -1
  251. package/dist/tokens/components/toggle.css +4 -1
  252. package/dist/tokens/components/tree.css +1 -1
  253. package/dist/tokens/components/upload.css +21 -9
  254. package/dist/tokens/foundation.css +24 -30
  255. package/dist/tokens/semantic/layout.css +19 -5
  256. package/docs/COMPOSITION-VS-COMPONENT.md +41 -0
  257. package/docs/DESIGN-AUTHORITY.md +14 -0
  258. package/docs/DEVELOPMENT.md +81 -6
  259. package/docs/TOKENS.md +16 -1
  260. package/docs/data-entry/tag-input.tsx +37 -0
  261. package/docs/layout/flex.tsx +40 -0
  262. package/docs/roadmap/website-components.md +34 -0
  263. package/docs/showcase/case4-login.tsx +10 -2
  264. package/docs/showcase/case5-shift-calendar.tsx +1 -1
  265. package/docs/showcase/case6-agency-handy.tsx +6 -6
  266. package/docs/showcase/futurelastic-web.tsx +7 -9
  267. package/docs/showcase/marketing-page.tsx +61 -52
  268. package/docs/showcase/table-expandable-rows.tsx +4 -1
  269. package/docs/showcase/table-pagination.tsx +88 -18
  270. package/docs/showcase/theme-customization.tsx +25 -2
  271. package/package.json +8 -5
@@ -6,7 +6,8 @@
6
6
  --table-row-height-comfortable: var(--band-height-xl);
7
7
  --table-row-height: calc(var(--table-row-height-default) * var(--scaling));
8
8
  --table-cell-padding-y: var(--space-2);
9
- --table-cell-space-x: var(--control-padding-x);
9
+
10
+ --table-cell-space-x: initial;
10
11
 
11
12
  --table-cell-indent-space-step: var(--space-4);
12
13
 
@@ -15,7 +16,7 @@
15
16
  --table-pagination-padding-x: initial;
16
17
 
17
18
  --table-surface-min-inline-size: 640px;
18
- --table-head-font-size: var(--font-size-xs);
19
+ --table-head-font-size: var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)));
19
20
 
20
21
  --table-head-font-weight: var(--font-weight-medium);
21
22
 
@@ -59,7 +60,10 @@
59
60
  --table-action-collection-meta-width-floor: 5rem;
60
61
 
61
62
  --table-action-collection-flex-width-floor: 5rem;
62
- --table-action-collection-font-size-compact: var(--font-size-xs);
63
+ --table-action-collection-font-size-compact: var(
64
+ --font-size-xs,
65
+ calc(var(--font-size-base) / var(--font-size-ratio))
66
+ );
63
67
  --table-action-collection-cell-space-x-compact: var(--space-2);
64
68
  --table-action-collection-cell-padding-y-compact: var(--space-2);
65
69
  --table-action-collection-row-height-compact: var(--table-row-height-compact);
@@ -72,13 +76,16 @@
72
76
  --table-stacked-collection-card-padding-x: var(--space-inline-md);
73
77
  --table-stacked-collection-card-gap: var(--space-stack-sm);
74
78
  --table-stacked-collection-cell-padding-y: var(--space-stack-xs);
75
- --table-stacked-collection-label-font-size: var(--font-size-xs);
79
+ --table-stacked-collection-label-font-size: var(
80
+ --font-size-xs,
81
+ calc(var(--font-size-base) / var(--font-size-ratio))
82
+ );
76
83
 
77
84
  --table-select-column-width: 2.5rem;
78
85
  --table-sort-icon-size: var(--icon-size-xs);
79
86
  --table-toolbar-icon-size: var(--icon-size-md);
80
87
  --table-pagination-icon-size: var(--icon-size-md);
81
- --table-pagination-font-size: var(--font-size-sm);
88
+ --table-pagination-font-size: var(--font-size-sm, var(--font-size-base));
82
89
 
83
90
  --table-skeleton-check-size: 1rem;
84
91
 
@@ -86,7 +93,7 @@
86
93
  --table-skeleton-line-height: var(--table-skeleton-line-block-size);
87
94
  --table-skeleton-radius: var(--radius-sm);
88
95
 
89
- --table-font-size: var(--font-size-sm);
96
+ --table-font-size: var(--font-size-sm, var(--font-size-base));
90
97
 
91
98
  --table-line-height: calc(1.25 / 0.875);
92
99
 
@@ -7,7 +7,10 @@
7
7
  --thought-chain-body-gap: var(--space-1);
8
8
 
9
9
  --thought-chain-icon-size: var(--band-height-sm);
10
- --thought-chain-icon-font-size: var(--font-size-xs);
10
+ --thought-chain-icon-font-size: var(
11
+ --font-size-xs,
12
+ calc(var(--font-size-base) / var(--font-size-ratio))
13
+ );
11
14
  --thought-chain-icon-radius: var(--radius-pill);
12
15
 
13
16
  --thought-chain-icon-background: initial;
@@ -3,7 +3,10 @@
3
3
 
4
4
  --toggle-count-min-width: var(--space-4);
5
5
  --toggle-count-space-inline: var(--space-1);
6
- --toggle-count-font-size: var(--font-size-xs);
6
+ --toggle-count-font-size: var(
7
+ --font-size-xs,
8
+ calc(var(--font-size-base) / var(--font-size-ratio))
9
+ );
7
10
  --toggle-count-radius: var(--radius-pill);
8
11
 
9
12
  --toggle-count-gap: 0;
@@ -9,7 +9,7 @@
9
9
  --tree-node-padding-inline: var(--space-2);
10
10
  --tree-node-gap: var(--space-2);
11
11
  --tree-node-radius: var(--radius-sm);
12
- --tree-node-font-size: var(--font-size-sm);
12
+ --tree-node-font-size: var(--font-size-sm, var(--font-size-base));
13
13
 
14
14
  --tree-switcher-size: 1.25rem;
15
15
 
@@ -7,17 +7,26 @@
7
7
  --upload-dropzone-border-width: var(--stroke-md);
8
8
  --upload-dropzone-icon-size: var(--icon-size-3xl);
9
9
  --upload-dropzone-hint-space-block-start: var(--space-3);
10
- --upload-dropzone-hint-font-size: var(--font-size-sm);
10
+ --upload-dropzone-hint-font-size: var(--font-size-sm, var(--font-size-base));
11
11
  --upload-dropzone-meta-space-block-start: var(--space-1);
12
- --upload-dropzone-meta-font-size: var(--font-size-xs);
12
+ --upload-dropzone-meta-font-size: var(
13
+ --font-size-xs,
14
+ calc(var(--font-size-base) / var(--font-size-ratio))
15
+ );
13
16
 
14
17
  --upload-tile-size: 6rem;
15
18
  --upload-tile-radius: var(--radius-md);
16
19
  --upload-tile-space-gap: var(--space-3);
17
20
  --upload-tile-icon-size: var(--icon-size-xl);
18
21
  --upload-tile-label-space-block-start: var(--space-1);
19
- --upload-tile-label-font-size: var(--font-size-xs);
20
- --upload-tile-overlay-font-size: var(--font-size-xs);
22
+ --upload-tile-label-font-size: var(
23
+ --font-size-xs,
24
+ calc(var(--font-size-base) / var(--font-size-ratio))
25
+ );
26
+ --upload-tile-overlay-font-size: var(
27
+ --font-size-xs,
28
+ calc(var(--font-size-base) / var(--font-size-ratio))
29
+ );
21
30
 
22
31
  --upload-overlay-background: initial;
23
32
  --upload-overlay-alpha: 70%;
@@ -33,14 +42,17 @@
33
42
 
34
43
  --upload-picture-icon-size: var(--icon-size-2xl);
35
44
  --upload-picture-empty-label-space-block-start: var(--space-2);
36
- --upload-picture-empty-label-font-size: var(--font-size-sm);
37
- --upload-picture-overlay-font-size: var(--font-size-sm);
45
+ --upload-picture-empty-label-font-size: var(--font-size-sm, var(--font-size-base));
46
+ --upload-picture-overlay-font-size: var(--font-size-sm, var(--font-size-base));
38
47
 
39
48
  --upload-picture-badge-radius: var(--radius-md);
40
49
  --upload-picture-badge-offset: var(--space-2);
41
50
  --upload-picture-badge-space-inline: var(--space-2);
42
51
  --upload-picture-badge-space-block: 0.125rem;
43
- --upload-picture-badge-font-size: var(--font-size-xs);
52
+ --upload-picture-badge-font-size: var(
53
+ --font-size-xs,
54
+ calc(var(--font-size-base) / var(--font-size-ratio))
55
+ );
44
56
 
45
57
  --upload-avatar-size: 6rem;
46
58
 
@@ -57,14 +69,14 @@
57
69
  --upload-draft-space-block: var(--space-2);
58
70
  --upload-draft-space-gap: var(--space-2);
59
71
  --upload-draft-radius: var(--radius-md);
60
- --upload-draft-font-size: var(--font-size-sm);
72
+ --upload-draft-font-size: var(--font-size-sm, var(--font-size-base));
61
73
  --upload-draft-icon-size: var(--icon-size-sm);
62
74
 
63
75
  --upload-row-space-inline: var(--space-3);
64
76
  --upload-row-space-block: var(--space-2);
65
77
  --upload-row-space-gap: var(--space-3);
66
78
  --upload-row-radius: var(--radius-md);
67
- --upload-row-font-size: var(--font-size-sm);
79
+ --upload-row-font-size: var(--font-size-sm, var(--font-size-base));
68
80
  --upload-row-icon-size: var(--icon-size-md);
69
81
 
70
82
  --upload-crop-dialog-max-width: 24rem;
@@ -146,37 +146,27 @@
146
146
 
147
147
  --font-size-base: 0.875rem;
148
148
  --font-size-ratio: 1.1227;
149
- --font-size-2xs: calc(
150
- var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)
151
- );
152
- --font-size-xs: calc(var(--font-size-base) / var(--font-size-ratio));
153
- --font-size-sm: var(--font-size-base);
154
- --font-size-lg: calc(
155
- var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio)
156
- );
157
- --font-size-xl: calc(var(--font-size-lg) * var(--font-size-ratio));
158
- --font-size-2xl: calc(var(--font-size-xl) * var(--font-size-ratio));
159
-
160
- --font-size-display: 3.375rem;
149
+
150
+ --font-size-2xs: initial;
151
+ --font-size-xs: initial;
152
+ --font-size-sm: initial;
153
+ --font-size-lg: initial;
154
+ --font-size-xl: initial;
155
+ --font-size-2xl: initial;
156
+
157
+ --font-size-display: clamp(2rem, 1.5rem + 2.5vw, 3.375rem);
161
158
  --font-size-display-ratio: 1.28;
162
- --font-size-3xl: calc(
163
- var(--font-size-display) / var(--font-size-display-ratio) / var(--font-size-display-ratio)
164
- );
165
- --font-size-4xl: calc(
166
- var(--font-size-display) / var(--font-size-display-ratio)
167
- );
168
- --font-size-5xl: var(--font-size-display);
169
-
170
- --heading-h1: calc(
171
- var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio) * var(--font-size-ratio)
172
- );
173
- --heading-h2: calc(
174
- var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio)
175
- );
176
- --heading-h3: var(--font-size-base);
177
- --heading-h4: var(--font-size-xs);
178
-
179
- --heading-h5: var(--font-size-2xs);
159
+
160
+ --font-size-3xl: initial;
161
+ --font-size-4xl: initial;
162
+ --font-size-5xl: initial;
163
+
164
+ --heading-h1: initial;
165
+ --heading-h2: initial;
166
+ --heading-h3: initial;
167
+ --heading-h4: initial;
168
+
169
+ --heading-h5: initial;
180
170
 
181
171
  --font-weight-normal: 400;
182
172
  --font-weight-medium: 500;
@@ -225,6 +215,10 @@
225
215
  --stroke-xl: 4px;
226
216
  --stroke-2xl: 6px;
227
217
 
218
+ --blur-sm: 4px;
219
+ --blur-md: 8px;
220
+ --blur-lg: 16px;
221
+
228
222
  --band-height-xs: 1.5rem;
229
223
  --band-height-sm: 1.75rem;
230
224
  --band-height-md: 2rem;
@@ -18,6 +18,8 @@
18
18
  --space-inline-md: var(--space-3);
19
19
  --space-inline-lg: var(--space-4);
20
20
 
21
+ --space-inline-xl: var(--space-6);
22
+
21
23
  --overlay-z-index: 50;
22
24
 
23
25
  --sticky-z-index: 20;
@@ -71,14 +73,26 @@
71
73
 
72
74
  --page-measure-wide: 72rem;
73
75
 
74
- --page-title-font-size: var(--heading-h1);
75
- --page-title-font-size-compact: var(--heading-h2);
76
+ --page-title-font-size: var(
77
+ --heading-h1,
78
+ calc(
79
+ var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio) *
80
+ var(--font-size-ratio)
81
+ )
82
+ );
83
+ --page-title-font-size-compact: var(
84
+ --heading-h2,
85
+ calc(var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio))
86
+ );
76
87
  --page-subtitle-font-size: var(--font-size-base);
77
- --page-subtitle-font-size-compact: var(--font-size-sm);
88
+ --page-subtitle-font-size-compact: var(--font-size-sm, var(--font-size-base));
78
89
 
79
- --page-title-font-size-chrome: var(--heading-h3);
90
+ --page-title-font-size-chrome: var(--heading-h3, var(--font-size-base));
80
91
 
81
- --page-subtitle-font-size-chrome: var(--font-size-2xs);
92
+ --page-subtitle-font-size-chrome: var(
93
+ --font-size-2xs,
94
+ calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio))
95
+ );
82
96
 
83
97
  --page-pad-block-start-chrome: 0px;
84
98
 
@@ -84,6 +84,7 @@ new UI need
84
84
  | **PricingTable** / feature grid | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **Composition** — `ResponsiveGrid` + `Card` |
85
85
  | Dashboard **page layout** | ❌ | ❌ | ❌ | ❌ | ➖ | ❌ | ❌ | **Composition** — `AppShell` + `PageContainer` + `ResponsiveGrid` |
86
86
  | "Icon medallion" | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | **Composition** — `Avatar` (square) + a Lucide glyph |
87
+ | **Section** / **Band** (full-bleed + measured column) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | **Composition** — `<section>` + `Flex measure` + `pad`; see §3.1 |
87
88
 
88
89
  `✅ pass · ❌ fail · ➖ borderline`. **StatCard** is the instructive borderline: C2 is weak (it owns little behavior), but it is a universal KPI tile with a controlled API, fully tokenized, broadly reused — so it earns its place. A **Hero** fails six of seven; it is unambiguously a composition.
89
90
 
@@ -106,6 +107,46 @@ C2 rather than C7.
106
107
 
107
108
  **ServiceLauncherCard is the ONE recorded exception, and it is recorded so that it stays one.** It shipped before the test was run against it, and when the test was run it came back with two hard FAILs: **C2** — no state, no keyboard handling, no focus management, its only ARIA three static attributes — and **C3** — its own imports are `Card` + `CardContent` + `Badge` + a Lucide glyph, so "could I build this right now from primitives?" is yes. By §2 that makes it a composition pattern. It is kept anyway because `src/components/layout/app-launcher.tsx` consumes it: it is an internal building block of a component that **does** pass, so the question was never "should it exist" but "should it be PUBLIC", and removing a public export is breaking. Keeping it public was the cheaper call and the ledger lives on gh#814 and at the top of `src/components/data-display/service-launcher-card.tsx`. **Consumers should compose `Card` + `Badge` for a service tile** — reach for `ServiceLauncherCard` only to match `AppLauncher`'s own tiles — and this row is not precedent for adding another static tile to `src/components/`.
108
109
 
110
+ ### 3.1 "Full-bleed outside, measured column inside" — the case that was answered with a PROP (gh#839)
111
+
112
+ This row exists because the question it settles was asked the other way round, and the right answer
113
+ turned out to be neither "add a component" nor "do nothing".
114
+
115
+ **A `Section` component is refused, and it is refused for Hero's reasons.** It owns no state, no
116
+ keyboard, no focus and no ARIA a `<section aria-labelledby>` does not already have (**C2**); it is
117
+ `<section>` + `Flex` + padding + a max-width, i.e. buildable today (**C3**); its API would be the
118
+ grab-bag `band` / `measure` / `glow` / `surface` / `bleed` that **C4** names by name; and a JP
119
+ business-software library would be shipping a marketing band to every consumer (**C7**). One
120
+ criterion of seven passes. Nothing about that is close.
121
+
122
+ **But "do nothing" was also refused, and that is the part worth remembering.** The doctrine's own
123
+ remedy for a composition is a TOKEN (§4.3), and `--page-measure-wide` shipped in 28.8.0 — so on
124
+ paper the gap was already closed. It was not. A token is only closed when something can READ it,
125
+ and three unrelated pages had each hand-written the identical four declarations to do so:
126
+ `docs/showcase/marketing-page.tsx` as an inline `style` constant, `acme-website.tsx` as `.tx-shell`,
127
+ `futurelastic-web.tsx` as `.fl-shell` — one shape, three spellings, two of them page-local CSS
128
+ classes on the pages whose entire claim is that they need none. `docs/TOKENS.md` calls a value that
129
+ appears in more than one place tier 1, and the same logic reads on a SHAPE.
130
+
131
+ **The third move is a prop on a primitive that already passes the test.** `Flex measure` (narrow |
132
+ medium | wide) centres the box and caps it at `var(--page-measure-*)`; it adds no gutter, because
133
+ `pad` owns that. A full-bleed band is now `<section>` — carrying the edge-to-edge paint — around one
134
+ `<Flex direction="col" measure="wide" pad={{ inline: 6, block: 20 }}>`. Measured on
135
+ `marketing-page.tsx`: seven bands, 7 inline `style` spreads and 3 `CSSProperties` constants gone,
136
+ the metric that page defends (0 bespoke classes, 0 raw px/rem literals) unchanged at 0/0, and the
137
+ geometry byte-identical (1440: section 1440px, column 1152px, band 96/80px, gutter 24px).
138
+
139
+ **`PageContainer measure="wide"` stays refused, and for the original reason.** A marketing page is
140
+ full-bleed `<section>`s; `PageContainer` owns page padding and a header/toolbar/footer scaffold, so
141
+ the two pages that are the prop's proof still cannot consume it. The prop went to the primitive
142
+ those pages CAN put inside a `<section>`, which is the distinction the earlier deferral was missing
143
+ rather than a reversal of it.
144
+
145
+ **The rule this leaves behind:** when a composition repeats a shape, ask whether an existing
146
+ primitive is missing ONE AXIS before you ask whether a new component is missing. A component that
147
+ fails C1–C7 and a prop that closes the same gap are not the same proposal, and the test above is
148
+ only asking about the first.
149
+
109
150
  ---
110
151
 
111
152
  ## 4. How to build a composition pattern correctly
@@ -449,6 +449,20 @@ expandable.expandedRowKeys` / `onExpandedRowsChange`. This library already mappe
449
449
  (`role="toolbar"`, `aria-pressed`); the prop there only keeps the last item selected.
450
450
  Divergence from Radix's markup is the point of the change, not a side effect of it.
451
451
 
452
+ - **`Input addonBefore` / `addonAfter` stay, although antd DEPRECATED them (gh#841).** Verified in
453
+ `ant-design@master` rather than on the docs page: `components/input/Input.tsx` carries
454
+ `@deprecated Use Space.Compact instead` on both props and fires a dev-time
455
+ `devUseWarning('Input').deprecated(…)` for each, while still rendering them; both locale tables
456
+ strike the rows through and the `addon` demo is flagged `debug`, so it no longer appears on the
457
+ published page. The deprecation is a REFACTOR onto `Space.Compact`, and this library has no
458
+ `Space` — so following it would delete the joined control and put nothing in its place, which is
459
+ a breaking change bought for nothing. `addonBefore` IS the joined control here: it renders
460
+ `.ui-input-group`, and gh#841 squared its seam. The steer that IS followed is the one antd's own
461
+ live surface gives: a GLYPH belongs in `prefix`, inside the field, where there is one box, one
462
+ border and no seam; an addon is for a label segment. Written on the prop
463
+ (`src/props/components/data-entry.prop.ts`) and in the MCP catalog. Revisit if a `Space`/compact
464
+ primitive is ever ported — then antd's steer is followable and this becomes a migration.
465
+
452
466
  **A knob that only a fork could reach is not parity either.** antd's `components`,
453
467
  `filterDropdown`, `classNames`/`styles` semantic maps and `prefixCls` all exist to let a consumer
454
468
  replace the rendered markup. This library answers that layer with tokens (cardinal rule #45), so
@@ -112,16 +112,91 @@ A change isn't done until its documentation reflects it:
112
112
 
113
113
  ---
114
114
 
115
- ## 5. Verify before finishing
115
+ ## 5. Verify before finishing — scope the checks to the DIFF
116
+
117
+ > **Read §5.0 before you run anything.** This section was rewritten after the owner watched a
118
+ > two-file change take six minutes of gates and asked, correctly, _"bản chất chỉ sửa rất ít, check
119
+ > diff đéo được hay sao? có phải release đâu mà run hết thế?"_ — it is not a release, so stop
120
+ > running a release's worth of checks.
121
+
122
+ ### 5.0 MEASURE FIRST, THEN COMPLAIN — the real cost table
123
+
124
+ Every number below was measured on this repo, on an M-series Mac, warm. **Measure again before you
125
+ believe them; a cost you assumed is how you end up optimising the wrong thing.**
126
+
127
+ | command | cost | scope |
128
+ | -------------------------- | --------------- | ------------------------------------------ |
129
+ | `check:token-tiers` | **0.2s** | whole repo |
130
+ | `audit` | **0.5s** | whole repo (~600 files) |
131
+ | `typecheck:docs` | **0.7s** | whole `docs/` program |
132
+ | `typecheck` | **1.3s** | whole `src/` program |
133
+ | `build` | **1.5s** | whole package |
134
+ | `preview:build` | **1.9s** | whole preview |
135
+ | `lint` | **12.9s** | whole repo |
136
+ | **`check:frame-overflow`** | **52s** (was 339s before it was parallelised, gh#851) | **199 frames x 2 viewports, in a browser** |
137
+
138
+ **The lesson is the opposite of the intuition.** "Typecheck the whole system" sounds wasteful and
139
+ costs **1.3 seconds** — typescript-7 is the native compiler, there is nothing to save there, and
140
+ scoping it to changed files would cost more in ceremony than it saves in wall clock. Meanwhile the
141
+ one command that _does_ cost real time is the browser sweep, and it is the one that looks innocent
142
+ in a shell script.
143
+
144
+ `check:frame-overflow` alone was **~96% of the wall clock** of a full local pass. It ran all 398
145
+ navigations down a SINGLE page, in series. It now runs a pool of one page per core (capped at 8):
146
+ **339s -> 52.3s, 6.5x**, byte-identical output, and a planted overflow is still caught at both
147
+ viewports by both. `FRAME_CONCURRENCY=1` restores the serial run for debugging.
148
+
149
+ > **Never argue about the cost of a gate you have not timed.** Time it:
150
+ > `st=$(date +%s); pnpm <gate> >/dev/null 2>&1; echo $(( $(date +%s) - st ))s`
151
+
152
+ ### 5.1 What to run, by what you touched
153
+
154
+ Find the row that matches your diff. Run that row. Do not run the rows below it.
155
+
156
+ | you changed | run | why |
157
+ | ---------------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------- |
158
+ | a `.css` file only | `audit` · `check:token-tiers` · the component's own tests · `check:frame-overflow --only <slug>` | no TS changed, so `typecheck` has nothing to say |
159
+ | a `.tsx`/`.ts` in `src/` | `typecheck` · `lint` · `audit` · that group's tests | 1.3s + 12.9s, both worth it |
160
+ | a file in `docs/` | `typecheck:docs` · `audit` · `check:example-imports` | `typecheck` covers `src/`, not `docs/` |
161
+ | a token in `src/tokens/` | + `check:token-tiers` · `src/tokens/__tests__` · `pnpm regen` twice (gh#847) | frozen tier tables go stale instantly |
162
+ | a public export / prop | + `pnpm ship:surface` | 8 stacked generators; the list is derived, not remembered |
163
+ | anything that moves LAYOUT | `check:frame-overflow --only <slug>` while you work; the FULL sweep once, before the PR | 17.5s vs 339s |
164
+ | opening the PR / cutting a release | the full sweep, `verify:ci:static`, the full suite in CI | the only place "run everything" is right |
165
+
166
+ ### 5.2 `--only` — the diff-scoped browser sweep
167
+
168
+ Added in gh#851 for exactly this. The sweep had no filter at all: 199 frames or nothing.
169
+
170
+ ```bash
171
+ pnpm check:frame-overflow --only table # 9 frames, 17.5s
172
+ pnpm check:frame-overflow --only '/^data-entry-(switch|segmented)/' # 3 frames
173
+ pnpm check:frame-overflow # all 199, 52s
174
+ ```
175
+
176
+ Measured: `--only table` is **17.5s against the full sweep's 52.3s**. Both matter — the pool cut
177
+ the full sweep 6.5x, and `--only` cuts what is left to the frames a diff can actually reach.
178
+
179
+ Two guards, both deliberate:
180
+
181
+ - **`--only` refuses `--update-baseline`.** A partial sweep does not know whether the frames it
182
+ skipped are still clean, and recording that as the whole truth is how a baseline stops meaning
183
+ anything. Rebaselining needs the full sweep.
184
+ - **Its success line says `PARTIAL, not a release gate`** and prints how many frames it skipped, so
185
+ a filtered green can never be pasted into a PR as if it were the real thing.
186
+
187
+ ### 5.3 The commands, for reference
116
188
 
117
189
  ```bash
118
- pnpm lint # eslint — self-contained flat config
119
- pnpm typecheck # tsc --noEmit
190
+ pnpm lint # eslint — self-contained flat config 12.9s
191
+ pnpm typecheck # tsc --noEmit over src/ 1.3s
192
+ pnpm typecheck:docs # tsc --noEmit over docs/ 0.7s
193
+ pnpm audit # godxjp-ui-audit — 0 errors for touched files 0.5s
194
+ pnpm check:mcp-sync # MCP registry <-> library export drift guard
120
195
  pnpm vitest run src/components/<group>/__tests__ --maxWorkers=2 # ONLY what you touched
196
+ pnpm check:frame-overflow --only <slug> # the frames your change can reach ~18s
197
+ pnpm check:frame-overflow # all 199 — pre-PR and CI only 52s
198
+ pnpm preview:build # integration test: examples + docs must build 1.9s
121
199
  pnpm test # FULL suite — CI only, never from an agent loop
122
- pnpm preview:build # integration test: examples + docs must build — at most once, pre-PR
123
- pnpm audit # godxjp-ui-audit — 0 errors for touched files
124
- pnpm check:mcp-sync # MCP registry ↔ library export drift guard
125
200
  pnpm check:frame-axe # WCAG 2.2 AA over every frame — LOCAL ONLY, never in CI (FRAME-A11Y-CI.md)
126
201
  ```
127
202
 
package/docs/TOKENS.md CHANGED
@@ -297,7 +297,22 @@ Instead, declare the knob `initial` (a real, catalogued, guaranteed-invalid decl
297
297
  }
298
298
  ```
299
299
 
300
- The same rule applies to `@theme inline` (utilities re-resolve scoped roles) and to any `:root`-declared **composite** that wraps a role (e.g. a focus-ring box-shadow): read the role **directly** at the call site, never through a frozen `:root` intermediate. Pure non-colour knobs (spacing, radius, font-size) don't need this — they aren't scope-retinted — but any colour/fill/ border/shadow knob whose default is a role token does.
300
+ The same rule applies to `@theme inline` (utilities re-resolve scoped roles) and to any `:root`-declared **composite** that wraps a role (e.g. a focus-ring box-shadow): read the role **directly** at the call site, never through a frozen `:root` intermediate. Pure non-colour knobs (spacing, radius, font-size) don't need this **as long as nothing re-scopes what they read** — see the two paragraphs below, which is where that qualifier cost a release.
301
+
302
+ **A DERIVED TIER FREEZES ON ITS OWN SEED — the `--font-size-*` ramp (gh#834).** The type scale is one base and one ratio, and every step used to be written `--font-size-5xl: var(--font-size-display)` / `--font-size-lg: calc(var(--font-size-base) * …)` on `:root`. Those substitute on `<html>`, so a `[data-tenant]` that re-seeds the base — the route level 3 of `docs/CUSTOMER-THEMING.md` documents, and which level 1 calls a seed — moved `text-base` and **nothing else**. Measured with `--font-size-base: 24px; --font-size-display: 80px` on a scope: 2xs/xs/sm/lg/xl/2xl/3xl/4xl/5xl all sat exactly where `:root` had left them, and a showcase whose comment read "80px hero via text-5xl" painted 54.
303
+
304
+ So every **derived** step is now an `initial` knob and the formula lives at the call site, spelled in terms of the un-derived knobs only (`--font-size-base`, `--font-size-ratio`, `--font-size-display`, `--font-size-display-ratio`) — an `initial` knob cannot be chained through, so `xl` reads `base × ratio³` rather than `lg × ratio`:
305
+
306
+ ```css
307
+ :root {
308
+ --font-size-5xl: initial;
309
+ } /* documented default = var(--font-size-display) */
310
+ [data-slot="text"][data-size="5xl"] {
311
+ font-size: var(--font-size-5xl, var(--font-size-display));
312
+ }
313
+ ```
314
+
315
+ **Every reader must carry the fallback**: a bare `var(--font-size-xs)` on an `initial` knob resolves to nothing, and the failure is silent and total. `check:frame-token-scope` is the gate that measures both halves — it fails on a step that stops following a scoped seed, and on a bare read of an empty knob.
301
316
 
302
317
  **The same freeze bites any knob whose default is a RE-SCOPED tier, colour or not.** `--control-height` is re-scoped by `.ui-auth-shell` (44px comfortable) and by `.ui-auth-shell[data-variant="canonical"]` (36px), so a knob that mirrors it must follow the same `initial` + call-site-fallback shape:
303
318
 
@@ -2,6 +2,7 @@ import { useState } from "react";
2
2
 
3
3
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
4
4
  import { FormField, TagInput } from "@godxjp/ui/data-entry";
5
+ import { useTranslation } from "@godxjp/ui/i18n";
5
6
  import { Flex, PageContainer } from "@godxjp/ui/layout";
6
7
 
7
8
  /**
@@ -11,9 +12,17 @@ import { Flex, PageContainer } from "@godxjp/ui/layout";
11
12
  * Composed only from real @godxjp/ui components.
12
13
  */
13
14
  export default function Demo() {
15
+ const { t } = useTranslation();
14
16
  const [invoiceTags, setInvoiceTags] = useState<string[]>(["営業部", "Q1"]);
15
17
  const [skillTags, setSkillTags] = useState<string[]>(["経理", "仕訳入力"]);
16
18
  const [recipientEmails, setRecipientEmails] = useState<string[]>([]);
19
+ /* The reporter's exact 71-character string, held FIRST so the truncated chip is one of the two
20
+ that render rather than one of the ones `+N` hides (gh#840). */
21
+ const [ledgerTags, setLedgerTags] = useState<string[]>([
22
+ "THEME_SEED_LEDGER_0007_CONTRAST_VERIFIED_AGAINST_CANVAS_AND_LABEL_00042",
23
+ "本番",
24
+ "ổn định",
25
+ ]);
17
26
 
18
27
  return (
19
28
  <PageContainer
@@ -87,6 +96,34 @@ export default function Demo() {
87
96
  </CardContent>
88
97
  </Card>
89
98
 
99
+ <Card>
100
+ <CardHeader>
101
+ <CardTitle level={2}>{t("showcase.tagInput.longIdTitle")}</CardTitle>
102
+ <CardDescription>
103
+ maxTagTextLength cuts the chip TEXT only — the whole value stays in the chip&apos;s
104
+ title and in the remove button&apos;s accessible name. maxTagCount collapses the rest
105
+ into a +N that names, in its own title and aria-label, exactly which tags it hides.
106
+ Neither may swallow a value silently (gh#840).
107
+ </CardDescription>
108
+ </CardHeader>
109
+ <CardContent>
110
+ <FormField
111
+ id="ledger-tags"
112
+ label={t("showcase.tagInput.ledgerLabel")}
113
+ helper={t("showcase.tagInput.ledgerHelper")}
114
+ >
115
+ <TagInput
116
+ id="ledger-tags"
117
+ value={ledgerTags}
118
+ onValueChange={setLedgerTags}
119
+ maxTagCount={2}
120
+ maxTagTextLength={16}
121
+ aria-label={t("showcase.tagInput.ledgerLabel")}
122
+ />
123
+ </FormField>
124
+ </CardContent>
125
+ </Card>
126
+
90
127
  <Card>
91
128
  <CardHeader>
92
129
  <CardTitle level={2}>無効状態</CardTitle>
@@ -8,6 +8,7 @@ import {
8
8
  ListRow,
9
9
  } from "@godxjp/ui/data-display";
10
10
  import { Button, Text } from "@godxjp/ui/general";
11
+ import { useTranslation } from "@godxjp/ui/i18n";
11
12
  import { Flex, PageContainer } from "@godxjp/ui/layout";
12
13
 
13
14
  /**
@@ -20,6 +21,7 @@ import { Flex, PageContainer } from "@godxjp/ui/layout";
20
21
  * @godxjp/ui components.
21
22
  */
22
23
  export default function Demo() {
24
+ const { t } = useTranslation();
23
25
  return (
24
26
  <PageContainer
25
27
  title="Flex"
@@ -398,6 +400,44 @@ export default function Demo() {
398
400
  </Flex>
399
401
  </CardContent>
400
402
  </Card>
403
+
404
+ <Card>
405
+ <CardHeader>
406
+ <CardTitle level={2}>{t("showcase.flexMeasure.title")}</CardTitle>
407
+ <CardDescription>{t("showcase.flexMeasure.lead")}</CardDescription>
408
+ </CardHeader>
409
+ <CardContent>
410
+ <Flex direction="col" gap="sm">
411
+ <Flex
412
+ id="measure-narrow"
413
+ measure="narrow"
414
+ surface="muted"
415
+ pad={{ block: 2, inline: 6 }}
416
+ justify="center"
417
+ >
418
+ <Text tone="muted">measure=&quot;narrow&quot; · 42rem</Text>
419
+ </Flex>
420
+ <Flex
421
+ id="measure-medium"
422
+ measure="medium"
423
+ surface="muted"
424
+ pad={{ block: 2, inline: 6 }}
425
+ justify="center"
426
+ >
427
+ <Text tone="muted">measure=&quot;medium&quot; · 48rem</Text>
428
+ </Flex>
429
+ <Flex
430
+ id="measure-wide"
431
+ measure="wide"
432
+ surface="muted"
433
+ pad={{ block: 2, inline: 6 }}
434
+ justify="center"
435
+ >
436
+ <Text tone="muted">measure=&quot;wide&quot; · 72rem</Text>
437
+ </Flex>
438
+ </Flex>
439
+ </CardContent>
440
+ </Card>
401
441
  </Flex>
402
442
  </PageContainer>
403
443
  );
@@ -649,6 +649,40 @@ with no call site in the two pages that are its proof, which is the tier-2 mista
649
649
  warns about. The token stands on its own as the vocabulary a composition caps its shell with, the
650
650
  way `--gradient-hero` does.
651
651
 
652
+ **CLOSED in gh#839, and the refusal above still stands.** Leaving the centred column to "the
653
+ composition writes it" was measured and found wanting: three unrelated pages hand-wrote the SAME
654
+ four declarations — `marketing-page.tsx` as an inline `style` constant, `acme-website.tsx` as
655
+ `.tx-shell`, `futurelastic-web.tsx` as `.fl-shell` — which `docs/TOKENS.md` calls tier 1, and two of
656
+ the three spelled it as a page-local CSS class. The answer was not a `Section` component (it fails
657
+ C1–C7 the way Hero does — `docs/COMPOSITION-VS-COMPONENT.md` §3.1 carries the ledger) and not
658
+ `PageContainer`, which still cannot be consumed by a full-bleed page. It is **`Flex measure`**
659
+ (`narrow | medium | wide`, reading `--page-measure-*`), on the primitive a `<section>` CAN put
660
+ inside itself. It centres and caps and nothing else: `pad` keeps the gutter, so a band is
661
+ `<section>` around one `<Flex direction="col" measure="wide" pad={{ inline: 6, block: 20 }}>`.
662
+
663
+ | step | reader |
664
+ | ---------------------------------- | -------------------------------------------------------------- |
665
+ | `--space-section-band` (80px) | `pad={{ block: 20 }}` — `GapStepProp` gained 20/24 |
666
+ | `--space-section-hero` (96px) | `pad={{ block: 24 }}` |
667
+ | `--page-measure-{narrow,med,wide}` | `Flex measure` — and `PageContainer measure` for the first two |
668
+
669
+ **No compact rung for the band steps, decided on measurement.** At 320×568 the hero band is 96px
670
+ at both edges = 33.8% of the first screen, and the `<h1>` still lands fully above the fold (top
671
+ 195px, bottom 315px). Three reasons not to add one: (1) 96px is already the NARROW rung of the
672
+ industry pair — Tailwind UI's marketing sections are `py-24 sm:py-32`, i.e. 96px on a phone and
673
+ 128px from `sm` up, so the missing step is at the wide end, not the narrow one; (2) a numeric `pad`
674
+ step is a VALUE by contract (`pad={3}` is 12px at every width — `GapStepProp`'s own docstring says
675
+ so), and making 20/24 responsive would make them the two steps whose number lies; (3) a
676
+ `--space-section-band-compact` token would have nowhere to be flipped: every `-active`/`-compact`
677
+ pair in this repo switches inside a COMPONENT's scope (`.ui-page-container`,
678
+ `.ui-centered-shell[data-preset="public-landing"]`), and a plain `<section>` has no such scope — so
679
+ it would ship as vocabulary with no caller, the exact defect gh#839 exists to stop.
680
+ `--centered-shell-landing-main-padding-block-compact` is not the counter-example it looks like: it
681
+ is 40px → 24px of a SHELL's `main` padding, not a marketing band, and it lives inside that shell's
682
+ own scope. **The real capability the band wants is a responsive object form for `pad`**, the one
683
+ `direction` and `ResponsiveGrid columns` already take (`pad={{ block: { base: 12, md: 20 } }}`) —
684
+ that is its own issue, and a much larger one than a token rung.
685
+
652
686
  ---
653
687
 
654
688
  ## 6. The animation and motion story