@felloinnovations/brand-kit 0.4.0 → 0.5.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 (363) hide show
  1. package/AGENTS.md +198 -24
  2. package/CHANGELOG.md +197 -0
  3. package/README.md +34 -7
  4. package/design-system/01-how-claude-decides.md +26 -17
  5. package/design-system/02-principles.md +11 -6
  6. package/design-system/03-colour.md +134 -47
  7. package/design-system/04-type.md +45 -23
  8. package/design-system/05-space-and-layout.md +175 -52
  9. package/design-system/06-sizing-profiles.md +4 -4
  10. package/design-system/07-scrolling.md +66 -20
  11. package/design-system/08-choosing-components.md +50 -22
  12. package/design-system/09-charts.md +71 -28
  13. package/design-system/10-patterns.md +33 -10
  14. package/design-system/11-page-recipes.md +110 -23
  15. package/design-system/12-content.md +2 -1
  16. package/design-system/13-motion.md +330 -47
  17. package/design-system/14-accessibility.md +47 -24
  18. package/design-system/15-ai-experiences.md +11 -6
  19. package/design-system/16-creativity.md +1 -1
  20. package/design-system/17-decisions.md +357 -1
  21. package/design-system/18-checklist.md +79 -16
  22. package/design-system/19-public-pages.md +6 -4
  23. package/design-system/20-palettes.md +275 -0
  24. package/design-system/README.md +30 -17
  25. package/design-system/components/ActionList/README.md +96 -10
  26. package/design-system/components/ActionList/preview.html +52 -7
  27. package/design-system/components/ActionList/style.css +64 -0
  28. package/design-system/components/ActivityGrid/README.md +38 -2
  29. package/design-system/components/ActivityGrid/preview.html +1 -1
  30. package/design-system/components/ActivityGrid/style.css +35 -0
  31. package/design-system/components/AppShell/README.md +205 -75
  32. package/design-system/components/AppShell/preview.html +339 -58
  33. package/design-system/components/AppShell/style.css +154 -0
  34. package/design-system/components/Avatar/README.md +37 -10
  35. package/design-system/components/Avatar/preview.html +13 -4
  36. package/design-system/components/Avatar/style.css +14 -0
  37. package/design-system/components/Badge/README.md +41 -19
  38. package/design-system/components/Badge/preview.html +13 -10
  39. package/design-system/components/Badge/style.css +23 -0
  40. package/design-system/components/Banner/README.md +30 -9
  41. package/design-system/components/Banner/preview.html +1 -1
  42. package/design-system/components/Banner/style.css +19 -0
  43. package/design-system/components/Breadcrumb/README.md +58 -46
  44. package/design-system/components/Breadcrumb/preview.html +16 -16
  45. package/design-system/components/Breadcrumb/style.css +17 -0
  46. package/design-system/components/Button/README.md +113 -55
  47. package/design-system/components/Button/preview.html +98 -25
  48. package/design-system/components/Button/style.css +86 -0
  49. package/design-system/components/Card/README.md +158 -49
  50. package/design-system/components/Card/preview.html +141 -19
  51. package/design-system/components/Card/style.css +115 -0
  52. package/design-system/components/CardBoard/README.md +58 -37
  53. package/design-system/components/CardBoard/preview.html +26 -29
  54. package/design-system/components/ChatCard/README.md +115 -29
  55. package/design-system/components/ChatCard/preview.html +149 -32
  56. package/design-system/components/ChatCard/style.css +49 -0
  57. package/design-system/components/ChatShell/README.md +116 -0
  58. package/design-system/components/ChatShell/preview.html +201 -0
  59. package/design-system/components/ChatShell/style.css +86 -0
  60. package/design-system/components/ChatTurn/README.md +78 -35
  61. package/design-system/components/ChatTurn/preview.html +60 -28
  62. package/design-system/components/ChatTurn/style.css +50 -0
  63. package/design-system/components/CheckRow/README.md +141 -0
  64. package/design-system/components/CheckRow/preview.html +140 -0
  65. package/design-system/components/CheckRow/style.css +88 -0
  66. package/design-system/components/Checkbox/README.md +58 -22
  67. package/design-system/components/Checkbox/preview.html +112 -50
  68. package/design-system/components/Checkbox/style.css +45 -0
  69. package/design-system/components/Chip/README.md +78 -47
  70. package/design-system/components/Chip/preview.html +29 -4
  71. package/design-system/components/Chip/style.css +17 -0
  72. package/design-system/components/Combobox/README.md +44 -11
  73. package/design-system/components/Combobox/preview.html +35 -12
  74. package/design-system/components/Combobox/style.css +54 -0
  75. package/design-system/components/Composer/README.md +137 -35
  76. package/design-system/components/Composer/preview.html +115 -40
  77. package/design-system/components/Composer/style.css +81 -0
  78. package/design-system/components/ConfirmDialog/README.md +73 -52
  79. package/design-system/components/ConfirmDialog/preview.html +70 -26
  80. package/design-system/components/ConfirmDialog/style.css +5 -0
  81. package/design-system/components/Cover/preview.html +3 -3
  82. package/design-system/components/Cover/style.css +19 -0
  83. package/design-system/components/DateInput/README.md +77 -12
  84. package/design-system/components/DateInput/preview.html +27 -12
  85. package/design-system/components/DateInput/style.css +38 -0
  86. package/design-system/components/Dialog/README.md +112 -44
  87. package/design-system/components/Dialog/preview.html +141 -18
  88. package/design-system/components/Dialog/style.css +74 -0
  89. package/design-system/components/EmptyState/README.md +42 -12
  90. package/design-system/components/EmptyState/preview.html +11 -11
  91. package/design-system/components/EmptyState/style.css +9 -0
  92. package/design-system/components/EntryShell/README.md +73 -48
  93. package/design-system/components/EntryShell/preview.html +60 -27
  94. package/design-system/components/EntryShell/style.css +19 -0
  95. package/design-system/components/FeatureGrid/README.md +61 -39
  96. package/design-system/components/FeatureGrid/preview.html +2 -2
  97. package/design-system/components/FeatureGrid/style.css +20 -0
  98. package/design-system/components/FileUpload/README.md +33 -3
  99. package/design-system/components/FileUpload/preview.html +18 -4
  100. package/design-system/components/FileUpload/style.css +23 -0
  101. package/design-system/components/FilterBar/README.md +114 -0
  102. package/design-system/components/FilterBar/preview.html +82 -0
  103. package/design-system/components/FilterBar/style.css +22 -0
  104. package/design-system/components/Fold/README.md +84 -26
  105. package/design-system/components/Fold/preview.html +77 -34
  106. package/design-system/components/Fold/style.css +48 -0
  107. package/design-system/components/Footer/README.md +62 -39
  108. package/design-system/components/Footer/preview.html +5 -5
  109. package/design-system/components/Footer/style.css +30 -0
  110. package/design-system/components/FunnelBars/README.md +24 -3
  111. package/design-system/components/FunnelBars/preview.html +5 -5
  112. package/design-system/components/FunnelBars/style.css +13 -0
  113. package/design-system/components/GoalBars/README.md +54 -10
  114. package/design-system/components/GoalBars/preview.html +69 -28
  115. package/design-system/components/GoalBars/style.css +51 -0
  116. package/design-system/components/GoalTicks/README.md +74 -58
  117. package/design-system/components/GoalTicks/preview.html +41 -118
  118. package/design-system/components/GoalTicks/style.css +37 -0
  119. package/design-system/components/GoalTubes/README.md +29 -3
  120. package/design-system/components/GoalTubes/preview.html +6 -6
  121. package/design-system/components/GoalTubes/style.css +23 -0
  122. package/design-system/components/Heatmap/README.md +133 -0
  123. package/design-system/components/Heatmap/preview.html +168 -0
  124. package/design-system/components/Heatmap/style.css +119 -0
  125. package/design-system/components/Hero/README.md +58 -40
  126. package/design-system/components/Hero/preview.html +1 -1
  127. package/design-system/components/Hero/style.css +19 -0
  128. package/design-system/components/HoverCard/README.md +114 -0
  129. package/design-system/components/HoverCard/preview.html +107 -0
  130. package/design-system/components/HoverCard/style.css +59 -0
  131. package/design-system/components/IconButton/README.md +69 -38
  132. package/design-system/components/IconButton/preview.html +77 -43
  133. package/design-system/components/IconButton/style.css +45 -0
  134. package/design-system/components/Input/README.md +36 -11
  135. package/design-system/components/Input/preview.html +1 -1
  136. package/design-system/components/Input/style.css +23 -0
  137. package/design-system/components/KanbanBoard/README.md +93 -45
  138. package/design-system/components/KanbanBoard/preview.html +159 -43
  139. package/design-system/components/KanbanBoard/style.css +53 -0
  140. package/design-system/components/Kbd/README.md +25 -9
  141. package/design-system/components/Kbd/preview.html +6 -2
  142. package/design-system/components/Kbd/style.css +9 -0
  143. package/design-system/components/KitButton/README.md +81 -47
  144. package/design-system/components/KitButton/preview.html +35 -13
  145. package/design-system/components/KitButton/style.css +46 -0
  146. package/design-system/components/KitCard/README.md +75 -44
  147. package/design-system/components/KitCard/preview.html +18 -10
  148. package/design-system/components/KitCard/style.css +15 -0
  149. package/design-system/components/KitInput/README.md +54 -39
  150. package/design-system/components/KitInput/preview.html +7 -7
  151. package/design-system/components/KitInput/style.css +23 -0
  152. package/design-system/components/Leaderboard/README.md +76 -49
  153. package/design-system/components/Leaderboard/preview.html +61 -26
  154. package/design-system/components/Leaderboard/style.css +44 -0
  155. package/design-system/components/ListDetail/README.md +222 -0
  156. package/design-system/components/ListDetail/preview.html +213 -0
  157. package/design-system/components/ListDetail/style.css +148 -0
  158. package/design-system/components/LoadBar/README.md +79 -0
  159. package/design-system/components/LoadBar/preview.html +40 -0
  160. package/design-system/components/LoadBar/style.css +17 -0
  161. package/design-system/components/MarketingNav/README.md +76 -42
  162. package/design-system/components/MarketingNav/preview.html +37 -8
  163. package/design-system/components/MarketingNav/style.css +45 -0
  164. package/design-system/components/Matrix/README.md +129 -0
  165. package/design-system/components/Matrix/preview.html +99 -0
  166. package/design-system/components/Matrix/style.css +84 -0
  167. package/design-system/components/Menu/README.md +117 -41
  168. package/design-system/components/Menu/preview.html +85 -23
  169. package/design-system/components/Menu/style.css +61 -0
  170. package/design-system/components/Meter/README.md +39 -4
  171. package/design-system/components/Meter/preview.html +18 -1
  172. package/design-system/components/Meter/style.css +23 -0
  173. package/design-system/components/MetricTile/README.md +237 -0
  174. package/design-system/components/MetricTile/preview.html +241 -0
  175. package/design-system/components/MetricTile/style.css +129 -0
  176. package/design-system/components/Morph/README.md +106 -0
  177. package/design-system/components/Morph/preview.html +103 -0
  178. package/design-system/components/Morph/style.css +31 -0
  179. package/design-system/components/Motion/README.md +164 -0
  180. package/design-system/components/Motion/preview.html +2537 -0
  181. package/design-system/components/NumberInput/README.md +27 -8
  182. package/design-system/components/NumberInput/preview.html +21 -5
  183. package/design-system/components/NumberInput/style.css +34 -0
  184. package/design-system/components/PaceBar/README.md +75 -0
  185. package/design-system/components/PaceBar/preview.html +67 -0
  186. package/design-system/components/PaceBar/style.css +25 -0
  187. package/design-system/components/Page/README.md +57 -18
  188. package/design-system/components/Page/preview.html +15 -17
  189. package/design-system/components/Page/style.css +7 -0
  190. package/design-system/components/PageBar/README.md +90 -34
  191. package/design-system/components/PageBar/preview.html +60 -19
  192. package/design-system/components/PageBar/style.css +35 -0
  193. package/design-system/components/PageHero/README.md +87 -51
  194. package/design-system/components/PageHero/preview.html +35 -6
  195. package/design-system/components/PageHero/style.css +31 -0
  196. package/design-system/components/Pagination/README.md +70 -49
  197. package/design-system/components/Pagination/preview.html +24 -15
  198. package/design-system/components/Pagination/style.css +12 -0
  199. package/design-system/components/Panel/README.md +109 -51
  200. package/design-system/components/Panel/preview.html +118 -20
  201. package/design-system/components/Panel/style.css +51 -0
  202. package/design-system/components/PasswordInput/README.md +50 -18
  203. package/design-system/components/PasswordInput/preview.html +71 -21
  204. package/design-system/components/PasswordInput/style.css +31 -0
  205. package/design-system/components/Plate/README.md +75 -17
  206. package/design-system/components/Plate/preview.html +40 -7
  207. package/design-system/components/Plate/style.css +37 -0
  208. package/design-system/components/Popover/README.md +70 -49
  209. package/design-system/components/Popover/preview.html +44 -22
  210. package/design-system/components/Popover/style.css +41 -0
  211. package/design-system/components/PricingTable/README.md +69 -49
  212. package/design-system/components/PricingTable/preview.html +21 -21
  213. package/design-system/components/PricingTable/style.css +21 -0
  214. package/design-system/components/ProgressPetals/README.md +31 -3
  215. package/design-system/components/ProgressPetals/preview.html +14 -15
  216. package/design-system/components/ProgressPetals/style.css +27 -0
  217. package/design-system/components/README.md +151 -0
  218. package/design-system/components/Radio/README.md +40 -17
  219. package/design-system/components/Radio/preview.html +16 -1
  220. package/design-system/components/Radio/style.css +21 -0
  221. package/design-system/components/RankBar/README.md +29 -2
  222. package/design-system/components/RankBar/preview.html +14 -12
  223. package/design-system/components/RankBar/style.css +18 -0
  224. package/design-system/components/Ring/README.md +61 -11
  225. package/design-system/components/Ring/preview.html +55 -10
  226. package/design-system/components/Ring/style.css +49 -0
  227. package/design-system/components/ScoreHero/README.md +91 -0
  228. package/design-system/components/ScoreHero/preview.html +104 -0
  229. package/design-system/components/ScoreHero/style.css +32 -0
  230. package/design-system/components/Section/README.md +72 -33
  231. package/design-system/components/Section/preview.html +46 -16
  232. package/design-system/components/Section/style.css +18 -0
  233. package/design-system/components/Segmented/README.md +100 -55
  234. package/design-system/components/Segmented/preview.html +107 -26
  235. package/design-system/components/Segmented/style.css +94 -0
  236. package/design-system/components/SegmentedProgress/README.md +64 -0
  237. package/design-system/components/SegmentedProgress/preview.html +69 -0
  238. package/design-system/components/SegmentedProgress/style.css +11 -0
  239. package/design-system/components/Select/README.md +47 -12
  240. package/design-system/components/Select/preview.html +28 -2
  241. package/design-system/components/Select/style.css +22 -0
  242. package/design-system/components/ShareBar/README.md +69 -0
  243. package/design-system/components/ShareBar/preview.html +72 -0
  244. package/design-system/components/ShareBar/style.css +25 -0
  245. package/design-system/components/SideList/README.md +147 -0
  246. package/design-system/components/SideList/preview.html +139 -0
  247. package/design-system/components/SideList/style.css +94 -0
  248. package/design-system/components/Skeleton/README.md +52 -16
  249. package/design-system/components/Skeleton/preview.html +35 -23
  250. package/design-system/components/Skeleton/style.css +22 -0
  251. package/design-system/components/Slider/README.md +95 -0
  252. package/design-system/components/Slider/preview.html +49 -0
  253. package/design-system/components/Slider/style.css +13 -0
  254. package/design-system/components/Split/README.md +112 -0
  255. package/design-system/components/Split/preview.html +105 -0
  256. package/design-system/components/Split/style.css +30 -0
  257. package/design-system/components/Starter/README.md +21 -9
  258. package/design-system/components/Starter/preview.html +5 -5
  259. package/design-system/components/Stat/README.md +64 -43
  260. package/design-system/components/Stat/preview.html +3 -3
  261. package/design-system/components/Stat/style.css +15 -0
  262. package/design-system/components/StatTiles/README.md +88 -44
  263. package/design-system/components/StatTiles/preview.html +142 -71
  264. package/design-system/components/StatTiles/style.css +64 -0
  265. package/design-system/components/StatusLine/README.md +85 -0
  266. package/design-system/components/StatusLine/preview.html +49 -0
  267. package/design-system/components/StatusLine/style.css +14 -0
  268. package/design-system/components/StatusScreen/README.md +49 -35
  269. package/design-system/components/StatusScreen/preview.html +20 -5
  270. package/design-system/components/StatusScreen/style.css +9 -0
  271. package/design-system/components/StepLine/README.md +97 -0
  272. package/design-system/components/StepLine/preview.html +108 -0
  273. package/design-system/components/StepLine/style.css +62 -0
  274. package/design-system/components/Stepper/README.md +35 -13
  275. package/design-system/components/Stepper/style.css +13 -0
  276. package/design-system/components/StreakCalendar/README.md +22 -1
  277. package/design-system/components/StreakCalendar/preview.html +10 -10
  278. package/design-system/components/StreakCalendar/style.css +12 -0
  279. package/design-system/components/SuggestionChip/README.md +87 -0
  280. package/design-system/components/SuggestionChip/preview.html +42 -0
  281. package/design-system/components/SuggestionChip/style.css +20 -0
  282. package/design-system/components/Switch/README.md +44 -24
  283. package/design-system/components/Switch/preview.html +23 -8
  284. package/design-system/components/Switch/style.css +31 -0
  285. package/design-system/components/Table/README.md +129 -58
  286. package/design-system/components/Table/preview.html +106 -72
  287. package/design-system/components/Table/style.css +104 -0
  288. package/design-system/components/Tabs/README.md +71 -46
  289. package/design-system/components/Tabs/preview.html +56 -24
  290. package/design-system/components/Tabs/style.css +44 -0
  291. package/design-system/components/Testimonial/README.md +48 -32
  292. package/design-system/components/Testimonial/preview.html +14 -14
  293. package/design-system/components/Testimonial/style.css +12 -0
  294. package/design-system/components/TextArea/README.md +27 -11
  295. package/design-system/components/TextArea/preview.html +8 -2
  296. package/design-system/components/TextArea/style.css +12 -0
  297. package/design-system/components/ThemeSwitch/README.md +116 -0
  298. package/design-system/components/ThemeSwitch/preview.html +57 -0
  299. package/design-system/components/ThemeSwitch/style.css +6 -0
  300. package/design-system/components/TickRow/README.md +52 -36
  301. package/design-system/components/TickRow/preview.html +64 -41
  302. package/design-system/components/TickRow/style.css +23 -0
  303. package/design-system/components/TickStrip/README.md +95 -0
  304. package/design-system/components/TickStrip/preview.html +88 -0
  305. package/design-system/components/TickStrip/style.css +42 -0
  306. package/design-system/components/Tile/README.md +79 -18
  307. package/design-system/components/Tile/preview.html +91 -40
  308. package/design-system/components/Tile/style.css +36 -0
  309. package/design-system/components/Timeline/README.md +68 -48
  310. package/design-system/components/Timeline/preview.html +27 -15
  311. package/design-system/components/Timeline/style.css +25 -0
  312. package/design-system/components/Toast/README.md +70 -38
  313. package/design-system/components/Toast/preview.html +43 -8
  314. package/design-system/components/Toast/style.css +25 -0
  315. package/design-system/components/Tooltip/README.md +93 -35
  316. package/design-system/components/Tooltip/preview.html +69 -15
  317. package/design-system/components/Tooltip/style.css +78 -0
  318. package/design-system/components/TopBar/README.md +67 -53
  319. package/design-system/components/TopBar/preview.html +14 -27
  320. package/design-system/components/TopBar/style.css +35 -0
  321. package/design-system/components/TopicRail/README.md +108 -0
  322. package/design-system/components/TopicRail/preview.html +58 -0
  323. package/design-system/components/TopicRail/style.css +48 -0
  324. package/design-system/components/TrendBars/README.md +52 -14
  325. package/design-system/components/TrendBars/preview.html +65 -32
  326. package/design-system/components/TrendBars/style.css +25 -0
  327. package/design-system/components/TrendLine/README.md +164 -0
  328. package/design-system/components/TrendLine/preview.html +373 -0
  329. package/design-system/components/TrendLine/style.css +155 -0
  330. package/design-system/components/Well/README.md +64 -22
  331. package/design-system/components/Well/preview.html +14 -14
  332. package/design-system/components/Well/style.css +22 -0
  333. package/design-system/components/_house.css +324 -0
  334. package/design-system/components/bundle.css +4091 -744
  335. package/design-system/tokens.json +1314 -124
  336. package/dist/fello-core.css +2 -2
  337. package/dist/fello.css +6 -1369
  338. package/dist/fello.scoped.css +7 -0
  339. package/dist/index.d.ts +110 -11
  340. package/dist/index.js +781 -96
  341. package/dist/palettes.d.ts +464 -0
  342. package/dist/palettes.js +497 -0
  343. package/dist/scoped.d.ts +3 -0
  344. package/dist/scoped.js +16 -0
  345. package/dist/toast.d.ts +14 -0
  346. package/dist/toast.js +33 -29
  347. package/dist/tokens.d.ts +1686 -62
  348. package/dist/tokens.js +1668 -61
  349. package/package.json +20 -4
  350. package/scripts/check-palette.mjs +295 -0
  351. package/scripts/token-model.mjs +552 -0
  352. package/tokens/_dark.css +174 -0
  353. package/tokens/_palettes.css +46 -0
  354. package/tokens/_product.css +266 -53
  355. package/tokens/_source.hubl.css +39 -19
  356. package/tokens/design-tokens.json +319 -0
  357. package/tokens/palettes.ts +504 -0
  358. package/tokens/shadcn-compat.css +19 -19
  359. package/tokens/shadcn-compat.hsl.css +76 -0
  360. package/tokens/tokens.css +1292 -62
  361. package/tokens/tokens.md +588 -61
  362. package/tokens/tokens.root.css +1298 -62
  363. package/tokens/tokens.ts +1677 -64
@@ -14,11 +14,12 @@ A number field with its figures right-aligned and tabular, an optional unit insi
14
14
 
15
15
  ## Anatomy
16
16
 
17
- - Field: `Input`'s exact shell (32 px, `--ws-radius-control`, white `--ws-field`, `--ws-shadow-hairline`, mid-blue focus
18
- edge, 12 px label above, error below).
17
+ - Field: `Input`'s exact shell (32 px, `--ws-radius-control`, white `--ws-field`, the inside edge, the kit's focus
18
+ ring, 12 px label above, error below).
19
19
  - Numerals: `.ws-tnum` (tabular numerals), right-aligned.
20
20
  - Unit: a muted (`--color-text-muted`) suffix inside the field, after the number, before the steppers if both are
21
- shown; the field's own right padding grows to make room, the same technique `Select`'s chevron uses.
21
+ shown; the field's own right padding grows to make room, the same technique `Select`'s chevron uses. It is hidden
22
+ from reading on its own and named through the field's `aria-describedby`, so "6" is heard as "6, %".
22
23
  - Steppers: two 24 px `xs` ghost icon buttons (`.ws-icon-btn.ws-icon-btn--xs`), minus and plus, side by side at the
23
24
  field's right edge. Side by side, not stacked, because a 32 px field has no room for two stacked 24 px buttons without
24
25
  growing taller, which would break the field's fixed height.
@@ -38,8 +39,8 @@ There is one size; it grows to 40 px on a touch screen.
38
39
  - **Plain:** right-aligned tabular numerals, no unit, no steppers.
39
40
  - **With unit:** the muted suffix sits after the number.
40
41
  - **With steppers:** minus and plus buttons step the value; ArrowUp/ArrowDown do the same from the keyboard.
41
- - **Focus:** the edge turns mid blue with the focus halo, exactly as `Input`.
42
- - **Error:** a min/max violation turns the edge salmon and rises in a message below, exactly as `Input`'s error state
42
+ - **Focus:** the kit's focus ring, 2 px navy, 2 px out, as `Input`'s (a field's edge darkens under the pointer).
43
+ - **Error:** a min/max violation takes the salmon's AA step as its edge and rises in a message below, exactly as `Input`'s error state
43
44
  ("Enter a number between 1 and 100").
44
45
  - **Disabled:** the field and steppers are inert, shown at reduced emphasis.
45
46
 
@@ -48,9 +49,9 @@ There is one size; it grows to 40 px on a touch screen.
48
49
  - Keyboard: a real `<input type="number">` under the hood, so ArrowUp/ArrowDown step by the field's `step` and native
49
50
  validation works for free; the native spinner is hidden in favour of the two stepper buttons, which do the same job
50
51
  visibly.
51
- - Pointer / touch: clicking minus or plus steps the value by one press; the touch floor is 40 px.
52
- - Motion: border colour, background and shadow transition over `--ws-duration-instant` on `--ws-ease-soft`, exactly as
53
- `Input`; an error message rises in over `--ws-duration-gentle`.
52
+ - Pointer / touch: clicking minus or plus steps the value by one press; the touch floor is 40 px. On touch the two
53
+ marks sit 16 apart and 8 from the edge, so each 40 px hit area is whole and a tap on minus never lands on plus.
54
+ - Motion: as `Input`'s: the edge over the hover beat; an error message rises in.
54
55
  - Reduced motion: nothing animates.
55
56
 
56
57
  ## Content
@@ -80,3 +81,21 @@ There is one size; it grows to 40 px on a touch screen.
80
81
 
81
82
  Intentional addition, decided from the system (26 Oct 2026): the system had `Input` for free text but nothing for a
82
83
  value meant to be stepped and read as a number. Built on `Input`'s field chrome and `IconButton`'s `xs` size.
84
+
85
+ ## Markup
86
+
87
+ ```html
88
+ <span class="ws-number-input ws-number-input--steppers ws-number-input--unit">
89
+ <input class="ws-input ws-tnum" id="call-length" type="number" value="30" aria-describedby="call-length-unit">
90
+ <span class="ws-number-input__unit" id="call-length-unit" aria-hidden="true">min</span>
91
+ <span class="ws-number-input__steppers">
92
+ <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Decrease by one minute"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M4 8h8"/></svg></button>
93
+ <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Increase by one minute"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M8 4v8M4 8h8"/></svg></button>
94
+ </span>
95
+ </span>
96
+ ```
97
+
98
+ ## Styles
99
+
100
+ `design-system/components/NumberInput/style.css`: `ws-number-input` with `--unit`, `--steppers`; `__unit`,
101
+ `__steppers`. The field is `Input`'s `ws-input`.
@@ -9,7 +9,7 @@
9
9
  </head>
10
10
  <body>
11
11
  <div class="ws-stage">
12
- <div style="display: grid; grid-template-columns: repeat(4, minmax(140px, 1fr)); gap: var(--ws-gap-component); width: 100%;">
12
+ <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 160px), 1fr)); gap: var(--ws-gap-component); width: 100%;">
13
13
 
14
14
  <div class="ws-field">
15
15
  <span class="ws-muted">Plain</span>
@@ -23,8 +23,8 @@
23
23
  <span class="ws-muted">With unit</span>
24
24
  <label class="ws-label" for="ni-unit">Commission</label>
25
25
  <span class="ws-number-input ws-number-input--unit">
26
- <input class="ws-input ws-tnum" id="ni-unit" type="number" value="6">
27
- <span class="ws-number-input__unit" aria-hidden="true">%</span>
26
+ <input class="ws-input ws-tnum" id="ni-unit" type="number" value="6" aria-describedby="ni-unit-u">
27
+ <span class="ws-number-input__unit" id="ni-unit-u" aria-hidden="true">%</span>
28
28
  </span>
29
29
  </div>
30
30
 
@@ -32,8 +32,8 @@
32
32
  <span class="ws-muted">With steppers and a unit</span>
33
33
  <label class="ws-label" for="ni-step">Call length</label>
34
34
  <span class="ws-number-input ws-number-input--steppers ws-number-input--unit">
35
- <input class="ws-input ws-tnum" id="ni-step" type="number" value="30">
36
- <span class="ws-number-input__unit" aria-hidden="true">min</span>
35
+ <input class="ws-input ws-tnum" id="ni-step" type="number" value="30" aria-describedby="ni-step-u">
36
+ <span class="ws-number-input__unit" id="ni-step-u" aria-hidden="true">min</span>
37
37
  <span class="ws-number-input__steppers">
38
38
  <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Decrease by one minute">
39
39
  <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M4 8h8"/></svg>
@@ -57,6 +57,22 @@
57
57
  </p>
58
58
  </div>
59
59
 
60
+ <div class="ws-field">
61
+ <span class="ws-muted">Disabled, with steppers</span>
62
+ <label class="ws-label" for="ni-off">Seats</label>
63
+ <span class="ws-number-input ws-number-input--steppers">
64
+ <input class="ws-input ws-tnum" id="ni-off" type="number" value="12" disabled>
65
+ <span class="ws-number-input__steppers">
66
+ <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Remove a seat" disabled>
67
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M4 8h8"/></svg>
68
+ </button>
69
+ <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Add a seat" disabled>
70
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M8 4v8M4 8h8"/></svg>
71
+ </button>
72
+ </span>
73
+ </span>
74
+ </div>
75
+
60
76
  </div>
61
77
  </div>
62
78
  </body>
@@ -0,0 +1,34 @@
1
+ /* ---- NumberInput: the house field, numerals at the right, a unit inside it (named to a screen reader through the
2
+ field's aria-describedby) and two steppers ---- */
3
+ .ws-number-input { position: relative; display: flex; }
4
+ .ws-number-input .ws-input { text-align: right; }
5
+ .ws-number-input__unit { position: absolute; top: 50%; transform: translateY(-50%); right: var(--space-sm); color: var(--color-text-muted); font-size: var(--ws-text-body); pointer-events: none; }
6
+ .ws-number-input__steppers { position: absolute; top: 50%; right: calc(var(--space-xxs) / 2); transform: translateY(-50%); display: flex; gap: calc(var(--space-xxs) / 2); }
7
+ /* The steppers are field marks (--ws-field-mark, Input/style.css): navy, and the field's ink on the navy ground. */
8
+ .ws-number-input__steppers .ws-icon-btn { color: var(--ws-field-mark, var(--color-text-heading)); }
9
+ /* They sit on the field, not the ground, so their ring and wash take the mark's colour too (on the navy ground the
10
+ white ring and wash vanished on the white field). */
11
+ .ws-number-input__steppers .ws-icon-btn:focus-visible { outline-color: var(--ws-field-mark, var(--ws-focus-color)); }
12
+ @media (hover: hover) { .ws-number-input__steppers .ws-icon-btn:not(:disabled):hover { background-color: color-mix(in srgb, var(--ws-field-mark, var(--color-text-heading)) 6%, transparent); } }
13
+ /* A disabled field's marks are muted, as Select's chevron (its sunk ground is dark on the navy ground). */
14
+ .ws-number-input:has(> .ws-input:disabled) .ws-number-input__steppers .ws-icon-btn { color: var(--color-text-muted); }
15
+ /* The unit's room: 36 past its right inset (a three-letter unit and 11 before the number; the browser's spinner, now
16
+ hidden, used to hold this room). */
17
+ .ws-number-input--unit .ws-input { padding-right: var(--space-3xl); }
18
+ /* Steppers alone: the numbers end 12 before the minus (on the scale; 56 was not). */
19
+ .ws-number-input--steppers .ws-input { padding-right: var(--space-4xl); }
20
+ .ws-number-input--steppers.ws-number-input--unit .ws-input { padding-right: var(--space-6xl); }
21
+ .ws-number-input--steppers .ws-number-input__unit { right: calc(var(--space-4xl) - var(--space-xxs)); }
22
+
23
+ /* The browser's own spinner is hidden: the kit's steppers do its job, and on hover it sat over the unit. The arrow keys
24
+ still step the value. */
25
+ .ws-number-input .ws-input { appearance: textfield; }
26
+ .ws-number-input .ws-input::-webkit-inner-spin-button, .ws-number-input .ws-input::-webkit-outer-spin-button { margin: 0; appearance: none; }
27
+ /* Touch: each stepper's 40 px hit area (the house's touch block) sits whole, side by side, inside the field, so a tap on
28
+ the minus never lands on the plus: 8 from the edge, 16 between the two 24 px marks. */
29
+ @media (pointer: coarse) {
30
+ .ws-number-input__steppers { right: var(--space-xs); gap: var(--space-md); }
31
+ .ws-number-input--steppers .ws-input { padding-right: var(--space-5xl); }
32
+ .ws-number-input--steppers .ws-number-input__unit { right: var(--space-5xl); }
33
+ .ws-number-input--steppers.ws-number-input--unit .ws-input { padding-right: var(--space-7xl); }
34
+ }
@@ -0,0 +1,75 @@
1
+ Progress toward a goal on a 14 px track, with a dot where it should be by now. North's bar, used in tiles, lanes and lists.
2
+
3
+ **Use it when**
4
+
5
+ - A number runs against a goal over a period and the question is "are we on pace?" (revenue this month, calls this week).
6
+ - The same bar repeats down a list or across tiles, so each one reads at a glance against its own pace.
7
+
8
+ **Not for**
9
+
10
+ - A share with no time in it: use `TickStrip` or `Meter`.
11
+ - A running job's progress: use `Meter` or `LoadBar`.
12
+ - Comparing many rows by length: use `GoalBars`.
13
+
14
+ **Anatomy**
15
+
16
+ - Slot 24 tall, the track centred in it: 14 tall (`--space-sm-plus`), 2 px corners, `--ws-track`.
17
+ - Fill from the left to `--value`, in `--tone`, square at its end (2 px at its start).
18
+ - Cuts: 1 px lines in the ground's colour at quarters or targets (`__cut`, `style="--at: 25%"`).
19
+ - Gap (`__gap`, behind pace only): the shortfall as an open box in the ground's colour with a 0.5 px edge in the tone, no
20
+ left edge, from the fill to the dot.
21
+ - Dot (`__dot`): 14 px, in the tone, a 1.5 px ring in the ground's colour, centred on `--pace`.
22
+ - Data on the bar: `style="--value: 48%; --pace: 70%; --tone: var(--ws-chart-past-half)"`.
23
+
24
+ | Modifier | What changes |
25
+ | --- | --- |
26
+ | `--done` | the fill reaches the end and takes the track's corners on both sides |
27
+ | `--thin` | 5 px, no slot, 1 px corners, no dot: the bar under a heatmap lane's name |
28
+ | `--draw` | the fill grows in over 700 ms on `--ws-ease-settle`, the gap after it, then the dot pops |
29
+
30
+ **Tones (North's pace bands, on kit tokens)**
31
+
32
+ | Band | Tone |
33
+ | --- | --- |
34
+ | on or ahead of pace | `--ws-chart-finished` (teal) |
35
+ | behind | `--ws-chart-past-half` (purple) |
36
+ | off pace | `--ws-chart-needs-work` (pink) |
37
+ | no tone yet | `--color-text-heading` (navy) |
38
+
39
+ **States**
40
+
41
+ - Ahead: the fill runs past the dot; no gap.
42
+ - Behind: the gap shows how far.
43
+ - Zero: leave out `__fill`; the gap runs from 0 to the dot as a closed box with the track's start corners.
44
+ - Done: `--done`.
45
+ - Draw: as above; reduced motion shows the final state.
46
+ - Hover, focus: the bar is a picture; the row or tile around it takes the pointer.
47
+
48
+ **Behaviour**
49
+
50
+ - Give the bar `role="img"` and an `aria-label` with both numbers ("48% of the goal, pace is 70%"), or `aria-hidden` when
51
+ the words beside it already say them.
52
+
53
+ **Rules**
54
+
55
+ - One goal a bar. The words next to it say the number; the bar never carries a figure inside it.
56
+ - Marks keep the chart tones; any word in a tone takes its AA step.
57
+
58
+ **Source**
59
+
60
+ **Derived from**: North's five bars (`.pbar`, `.mc-bar`, `.ho-bar`, `.talk-bar`, `.mp-bar`), built from the base values
61
+ (14 track, 14 dot, 24 slot) rather than the tile's 1.09 scaled ones; the fill and dot timing from North's motion config.
62
+ North's own pace colours (#257985 teal, #744ccb purple, #9b1b5a plum) are mapped to the kit's chart tokens.
63
+
64
+ **Markup**
65
+
66
+ ```html
67
+ <div class="ws-pace-bar" style="--value: 48%; --pace: 70%; --tone: var(--ws-chart-past-half);" role="img" aria-label="48% of the goal, pace is 70%">
68
+ <span class="ws-pace-bar__fill"></span>
69
+ <span class="ws-pace-bar__gap"></span>
70
+ <span class="ws-pace-bar__cut" style="--at: 50%;"></span>
71
+ <span class="ws-pace-bar__dot"></span>
72
+ </div>
73
+ ```
74
+
75
+ **Styles**: `PaceBar/style.css`, in `bundle.css` and `fello.css` as `.ws-pace-bar`. Every value is a token.
@@ -0,0 +1,67 @@
1
+ <!-- @dsCard group="Progress" height=560 -->
2
+ <!doctype html>
3
+ <html>
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <title>PaceBar</title>
7
+ <link rel="stylesheet" href="../../tokens.css">
8
+ <link rel="stylesheet" href="../bundle.css">
9
+ </head>
10
+ <body>
11
+ <div class="ws-stage ws-stage--column">
12
+
13
+ <div class="ws-stack" style="max-width: 560px;">
14
+ <span class="ws-muted">Ahead of pace: the fill past the dot, quarter cuts, drawn in once</span>
15
+ <div class="ws-pace-bar ws-pace-bar--draw" style="--value: 72%; --pace: 64%; --tone: var(--ws-chart-finished);" role="img" aria-label="72% of the goal, pace is 64%">
16
+ <span class="ws-pace-bar__fill"></span>
17
+ <span class="ws-pace-bar__cut" style="--at: 25%;"></span><span class="ws-pace-bar__cut" style="--at: 50%;"></span><span class="ws-pace-bar__cut" style="--at: 75%;"></span>
18
+ <span class="ws-pace-bar__dot"></span>
19
+ </div>
20
+ </div>
21
+
22
+ <div class="ws-stack" style="max-width: 560px;">
23
+ <span class="ws-muted">Behind pace: the shortfall as an open box in the tone, from the fill to the dot</span>
24
+ <div class="ws-pace-bar ws-pace-bar--draw" style="--value: 48%; --pace: 70%; --tone: var(--ws-chart-past-half);" role="img" aria-label="48% of the goal, pace is 70%">
25
+ <span class="ws-pace-bar__fill"></span>
26
+ <span class="ws-pace-bar__gap"></span>
27
+ <span class="ws-pace-bar__cut" style="--at: 25%;"></span><span class="ws-pace-bar__cut" style="--at: 50%;"></span><span class="ws-pace-bar__cut" style="--at: 75%;"></span>
28
+ <span class="ws-pace-bar__dot"></span>
29
+ </div>
30
+ </div>
31
+
32
+ <div class="ws-stack" style="max-width: 560px;">
33
+ <span class="ws-muted">Far behind: the needs work tone</span>
34
+ <div class="ws-pace-bar" style="--value: 22%; --pace: 70%; --tone: var(--ws-chart-needs-work);" role="img" aria-label="22% of the goal, pace is 70%">
35
+ <span class="ws-pace-bar__fill"></span>
36
+ <span class="ws-pace-bar__gap"></span>
37
+ <span class="ws-pace-bar__dot"></span>
38
+ </div>
39
+ </div>
40
+
41
+ <div class="ws-stack" style="max-width: 560px;">
42
+ <span class="ws-muted">Done: the goal met before the month is out</span>
43
+ <div class="ws-pace-bar ws-pace-bar--done" style="--value: 100%; --pace: 90%; --tone: var(--ws-chart-finished);" role="img" aria-label="100% of the goal, pace is 90%">
44
+ <span class="ws-pace-bar__fill"></span>
45
+ <span class="ws-pace-bar__dot"></span>
46
+ </div>
47
+ </div>
48
+
49
+ <div class="ws-stack" style="max-width: 560px;">
50
+ <span class="ws-muted">Nothing yet: an empty track, the dot says where it should be by now</span>
51
+ <div class="ws-pace-bar" style="--value: 0%; --pace: 30%; --tone: var(--color-text-heading);" role="img" aria-label="0% of the goal, pace is 30%">
52
+ <span class="ws-pace-bar__gap"></span>
53
+ <span class="ws-pace-bar__dot"></span>
54
+ </div>
55
+ </div>
56
+
57
+ <div class="ws-stack" style="max-width: 200px;">
58
+ <span class="ws-muted">Thin (5 px): under a heatmap lane's name</span>
59
+ <div class="ws-pace-bar ws-pace-bar--thin" style="--value: 64%; --tone: var(--ws-chart-finished);" role="img" aria-label="64% of pace">
60
+ <span class="ws-pace-bar__fill"></span>
61
+ <span class="ws-pace-bar__cut" style="--at: 25%;"></span><span class="ws-pace-bar__cut" style="--at: 50%;"></span><span class="ws-pace-bar__cut" style="--at: 75%;"></span>
62
+ </div>
63
+ </div>
64
+
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,25 @@
1
+ /* ---- PaceBar: progress toward a goal on a 14 px track, with where it should be by now as a dot ---- */
2
+ /* Data on the bar: style="--value: 62%; --pace: 70%; --tone: ...". The fill runs from the left to --value; the dot sits
3
+ on --pace with a 1.5 px ring in the ground's colour; 1 px cuts in the ground's colour mark quarters or targets
4
+ (style="--at: 25%"); behind pace, the shortfall is an open box in the tone (__gap) from the fill to the dot.
5
+ The bar sits in a 24 px slot, the track centred in it. */
6
+ .ws-pace-bar { --value: 0%; --pace: 0%; --tone: var(--color-text-heading); --h: var(--space-sm-plus); position: relative; height: var(--space-lg); }
7
+ .ws-pace-bar::before, .ws-pace-bar__fill, .ws-pace-bar__gap { position: absolute; top: calc((100% - var(--h)) / 2); height: var(--h); }
8
+ .ws-pace-bar::before { content: ""; left: 0; right: 0; border-radius: var(--ws-radius-chip); background: var(--ws-track); }
9
+ .ws-pace-bar__fill { left: 0; width: var(--value); border-radius: var(--ws-radius-chip) 0 0 var(--ws-radius-chip); background: var(--tone); transform-origin: left; }
10
+ .ws-pace-bar__gap { left: var(--value); width: max(0%, calc(var(--pace) - var(--value))); border: var(--ws-hairline) solid var(--tone); border-left: 0; background: var(--color-bg-page); }
11
+ /* Nothing yet (no __fill): the shortfall starts the track, so it closes its box and takes the track's start corners. */
12
+ .ws-pace-bar:not(:has(> .ws-pace-bar__fill)) > .ws-pace-bar__gap { border-left: var(--ws-hairline) solid var(--tone); border-radius: var(--ws-radius-chip) 0 0 var(--ws-radius-chip); }
13
+ .ws-pace-bar__cut { position: absolute; top: calc((100% - var(--h)) / 2); left: var(--at); height: var(--h); border-left: var(--ws-line) solid var(--color-bg-page); }
14
+ .ws-pace-bar__dot { position: absolute; top: calc((100% - var(--h)) / 2); left: var(--pace); width: var(--h); height: var(--h); margin-left: calc(var(--h) / -2); border: calc(var(--ws-hairline) * 3) solid var(--color-bg-page); border-radius: var(--radius-full); background: var(--tone); }
15
+ /* Done: the fill reaches the end, so it takes the track's corners on both sides. */
16
+ .ws-pace-bar--done .ws-pace-bar__fill { width: 100%; border-radius: var(--ws-radius-chip); }
17
+ /* Thin: the 5 px bar under a heatmap lane's name, no slot of its own and no dot. */
18
+ .ws-pace-bar--thin { --h: calc(var(--space-xxs) + var(--ws-line)); height: var(--h); }
19
+ .ws-pace-bar--thin::before, .ws-pace-bar--thin .ws-pace-bar__fill { border-radius: var(--ws-radius-bar); }
20
+ @media (prefers-reduced-motion: no-preference) {
21
+ /* The fill (North): 700 ms on the settle curve; the dot pops once the fill has landed. */
22
+ .ws-pace-bar--draw .ws-pace-bar__fill, .ws-pace-bar--draw .ws-pace-bar__gap { animation: ws-grow var(--ws-duration-fill) var(--ws-ease-settle) backwards; animation-delay: var(--ws-build-at, 0s); }
23
+ .ws-pace-bar--draw .ws-pace-bar__gap { transform-origin: left; animation-delay: calc(var(--ws-build-at, 0s) + var(--ws-duration-settle)); }
24
+ .ws-pace-bar--draw .ws-pace-bar__dot { animation: ws-bloom var(--ws-duration-settle) var(--ws-ease-pop) backwards; animation-delay: calc(var(--ws-build-at, 0s) + var(--ws-duration-fill)); }
25
+ }
@@ -8,29 +8,47 @@ and a cluster. All in fello.css; with these a page needs no layout CSS of its ow
8
8
 
9
9
  ## Not for
10
10
 
11
- - A product area with a sidebar and a top bar: wrap the page in `AppShell` (its stage then holds the `.ws-page`).
11
+ - A product area with a nav and a bar: use `AppShell`. Its body is the page (it brings the same gutter, gap and size
12
+ container), so put the page's parts straight in it, with no `.ws-page` inside.
12
13
  - A public, marketing page: its sections (`Hero`, `FeatureGrid`, `Footer`) size from the kit's `layout-content-max`
13
14
  and `layout-margin`, full bleed (Public pages).
15
+ - A main column and its aside: `Split`.
14
16
  - Laying out the inside of one component: the component's own classes do that.
15
17
 
16
18
  ## Anatomy
17
19
 
18
20
  | Class | What it does | Values |
19
21
  | --- | --- | --- |
20
- | `.ws-page` | The page: a column of its parts, centred, at most two board columns wide | max `2 x --ws-chart-card-w + --ws-gap-component` (1128) plus the gutters; padding `--ws-gutter` (24), `--space-md` (16) on a phone (under 40rem); parts `--ws-gap-component` (16) apart; a size container |
21
- | `.ws-page--column` | The one column: a form, a reading page, a chat-like page | max `--ws-column-width` (656) plus the gutters |
22
- | `.ws-area` | Any other region that tiles or small cards should size from (a card, a pane) | `container-type: inline-size` |
23
- | `.ws-board` | A board of chart cards (`CardBoard`): two side by side once both fit at 480, each up to 556; below that one column at full width, in DOM order | grid by width, `--ws-chart-card-min`, `--ws-chart-card-w`, gap 16 |
22
+ | `.ws-page` | The page: a column of its parts, centred, at most two board columns wide | max `2 x --ws-chart-card-w + --ws-gap-component` (1128) plus the gutters; Seth's 32 gutter (`--space-xl`, D4), 16 on a phone (under 40rem); parts 16 apart; a size container |
23
+ | `.ws-page--column` | The one column: a form, a reading page | max `--ws-column-width` (656) plus the gutters |
24
+ | `.ws-area` | Any other region a component without its own container should size from | `container-type: inline-size` |
25
+ | `.ws-board` | A board of chart cards (`CardBoard`): two side by side once both fit at 480, each up to 556; below that one column at full width, in DOM order; on the content's start edge, never centred | grid by width, `--ws-chart-card-min`, `--ws-chart-card-w`, gap 16 |
24
26
  | `.ws-board__column` | A column of cards inside the board, each card its own height | gap 16 |
25
- | `.ws-board--4` | Small cards in a grid: one across, two from 40rem, four from 60rem of the page or area | container queries at area-sm and area-lg |
27
+ | `.ws-board--4` | Small cards: one across, two from 40rem, four from 60rem **of the board's own width** (K3) | a size container named `ws-board`, four tracks, each card spans 4, 2 or 1 |
26
28
  | `.ws-stack` | Things top to bottom | gap `--ws-gap` (8) |
27
29
  | `.ws-cluster` | Things side by side, centred, wrapping | gap `--ws-gap` (8); `--start` aligns them to the top |
28
30
  | `--tight`, `--loose`, `--component`, `--group` | The other named gaps, on a stack or a cluster | 4, 12, 16, 24 |
31
+ | `.ws-stack--block` | Seth's report blocks, top to bottom (a stack only) | `--ws-gap-block` (32) |
32
+ | `.ws-stack--section` | Page sections, top to bottom (a stack only) | `--ws-gap-section` (56) |
29
33
 
30
- - The page's width comes from the board: no page width token exists, so it is two 556 columns and the gap, which makes a
31
- board of two columns fill the page exactly and line up with the tiles above it.
32
- - The 40rem and 60rem steps are the guide's area-sm and area-lg (Space and layout). They are container queries, so they
33
- measure the page or the nearest `.ws-area`, never the window; outside both, `.ws-board--4` stays one across.
34
+ Which stack each Fia page (Seth's frames, `11-page-recipes.md`) uses, so a page never writes its own gap:
35
+
36
+ | Page | Its column | Inside each block |
37
+ | --- | --- | --- |
38
+ | Grow audit report (recipe 23) | `.ws-stack--block`: the tabs, the `ScoreHero`, the checks, 32 apart | `.ws-stack--component` (16): a heading and its card |
39
+ | Fixes checklist | `.ws-stack--block`: the areas, 32 apart (Seth's 28 snaps to it, D4) | the area heading 10 over its card (`Section`) |
40
+ | Tally report | `.ws-stack--section`: the hero, the bill row, the vendor board, 56 apart | `.ws-stack--loose` (12): a board's head, body and source |
41
+ | Review inbox (recipe 24) | no stack: one three-column grid, 8 apart (`ListDetail`) | the card's own parts |
42
+ | First open (recipe 22) | the thread's column (`ChatShell`) | the card's own parts |
43
+
44
+ The four app pages (Grow, Fixes, Tally, Inbox) sit in `ws-app-shell__body--wide` (Seth's 1350), under the thread header (`PageBar`).
45
+
46
+ - The page's width comes from the board: two 556 columns and the gap, so a board of two columns fills the page and
47
+ lines up with the bar and tiles above it.
48
+ - `.ws-board--4` measures itself, so the same markup is four across on a wide page, two in a 700 px pane and one in a
49
+ card, with no `.ws-area` round it. Give it four, two or one cards; never three or five (a 4 + 1 orphan).
50
+ - A column that can be height-bound (`.ws-page`, `.ws-stack`, `.ws-board__column`) never squashes its children (K1);
51
+ a child that should scroll inside says so (`flex: 1; min-height: 0; overflow: auto`).
34
52
 
35
53
  ## Variants and sizes
36
54
 
@@ -41,15 +59,15 @@ and a cluster. All in fello.css; with these a page needs no layout CSS of its ow
41
59
 
42
60
  ## States
43
61
 
44
- - **Wide** (content of 976 and up): two board columns; four small cards across from 960 of content.
45
- - **Middle**: one board column at the page's full width, lined up with the page bar; small cards two across.
62
+ - **Wide** (content of 976 and up): two board columns; small cards four across from 960 of board width.
63
+ - **Middle**: one board column at the page's full width; small cards two across.
46
64
  - **Phone**: a 16 gutter, one column, the same DOM order.
47
65
 
48
66
  ## Behaviour
49
67
 
50
68
  - The page scrolls as a whole: nothing in it sets a fixed height or hides overflow, so no part traps its content.
51
69
  - Order is DOM order at every width, so keyboard and screen-reader order never changes with the layout.
52
- - No motion of its own; cards rise in (`ws-rise`, staggered, at most six).
70
+ - No motion of its own; parts settle in (`ws-settle`, `--ws-i` for the 22 ms stagger).
53
71
 
54
72
  ## Content
55
73
 
@@ -59,12 +77,33 @@ and a cluster. All in fello.css; with these a page needs no layout CSS of its ow
59
77
  ## Rules
60
78
 
61
79
  - **The gutter is the page's**: a card never adds a margin; the board's and the page's gaps separate things.
62
- - **Size from the region, not the window**: a board or tiles inside a pane follow the pane (`.ws-area`).
80
+ - **Size from the region, not the window**: adaptive pieces measure themselves (`.ws-board--4`, `PageHero`, `Split`).
63
81
  - **Write no layout CSS**: a page made from these classes and the catalog's components needs only fello.css.
64
82
 
65
83
  ## Source
66
84
 
67
- **Derived from**: Space and layout (the gaps, the gutter, the board's 556 and 480, area-sm to area-xl at 40, 48, 60
68
- and 76 rem) and the first product's Grow board (`Board`: the page bar, the tiles and the cards one gap apart, sized
69
- from the board's own container). The page's maximum width is derived from the board here, 27 Oct 2026, since the
70
- system had none.
85
+ **Derived from**: Space and layout (the gaps, the board's 556 and 480, area-sm to area-xl at 40, 48, 60 and 76 rem),
86
+ the first product's Grow board, Seth's 32 gutter (D4, the Tally frame) and Revenue OS faults K1, K3 and K12 (4 Nov
87
+ 2026). The page's maximum width is derived from the board, 27 Oct 2026, since the system had none.
88
+
89
+ ## Markup
90
+
91
+ ```html
92
+ <main class="ws-page">
93
+ <header class="ws-page-bar">
94
+ <div class="ws-page-bar__words"><h1 class="ws-page-bar__title">Team this month</h1><span class="ws-page-bar__context">Since Oct 1</span></div>
95
+ </header>
96
+ <ul class="ws-board ws-board--4" aria-label="This month">
97
+ <li class="ws-card ws-card--inset ws-stack ws-stack--tight"><span class="ws-muted">Calls</span><span class="ws-figure ws-figure--tile">142</span></li>
98
+ <!-- four, two or one -->
99
+ </ul>
100
+ <div class="ws-board">
101
+ <!-- chart cards -->
102
+ </div>
103
+ </main>
104
+ ```
105
+
106
+ ## Styles
107
+
108
+ The page, the board, the stack and the cluster are in `_house.css`; `Page/style.css` holds the self-measuring
109
+ `.ws-board--4`. The 32 gutter is the global `--ws-gutter` (16 on a phone). Tokens: `--ws-gutter`, `--space-md`, `--ws-gap-component`, `--ws-chart-card-w`, `--ws-chart-card-min`, `--ws-column-width`.
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Layout" height=900 -->
1
+ <!-- @dsCard group="Layout" height=594 -->
2
2
  <!doctype html>
3
3
  <html>
4
4
  <head>
@@ -13,19 +13,19 @@
13
13
  <header class="ws-page-bar">
14
14
  <div class="ws-page-bar__words">
15
15
  <h1 class="ws-page-bar__title">Team this month</h1>
16
- <p class="ws-body">A page: two board columns wide at most, the 24 gutter (16 on a phone), its parts 16 apart.</p>
16
+ <span class="ws-page-bar__context">Since Oct 1</span>
17
17
  </div>
18
18
  <div class="ws-page-bar__acts">
19
- <button class="ws-btn ws-btn--primary">Export</button>
19
+ <button type="button" class="ws-btn ws-btn--primary">Export</button>
20
20
  </div>
21
21
  </header>
22
22
 
23
- <span class="ws-muted">.ws-board--4: small cards, one across, two from 40rem, four from 60rem of the page</span>
23
+ <span class="ws-muted">.ws-board--4 measures itself: one across, two from 40rem of its own width, four from 60rem</span>
24
24
  <ul class="ws-board ws-board--4" aria-label="This month">
25
- <li class="ws-card ws-card--inset ws-stack ws-stack--tight"><span class="ws-muted">Calls</span><span class="ws-figure">142</span></li>
26
- <li class="ws-card ws-card--inset ws-stack ws-stack--tight"><span class="ws-muted">Shows</span><span class="ws-figure">31</span></li>
27
- <li class="ws-card ws-card--inset ws-stack ws-stack--tight"><span class="ws-muted">Follow-ups</span><span class="ws-figure">58</span></li>
28
- <li class="ws-card ws-card--inset ws-stack ws-stack--tight"><span class="ws-muted">New leads</span><span class="ws-figure">14</span></li>
25
+ <li class="ws-card ws-card--inset ws-stack ws-stack--tight"><span class="ws-muted">Calls</span><span class="ws-figure ws-figure--tile">142</span></li>
26
+ <li class="ws-card ws-card--inset ws-stack ws-stack--tight"><span class="ws-muted">Shows</span><span class="ws-figure ws-figure--tile">31</span></li>
27
+ <li class="ws-card ws-card--inset ws-stack ws-stack--tight"><span class="ws-muted">Follow-ups</span><span class="ws-figure ws-figure--tile">58</span></li>
28
+ <li class="ws-card ws-card--inset ws-stack ws-stack--tight"><span class="ws-muted">New leads</span><span class="ws-figure ws-figure--tile">14</span></li>
29
29
  </ul>
30
30
 
31
31
  <span class="ws-muted">.ws-board: chart cards, two across once both fit at 480 (each up to 556), else one at full width</span>
@@ -39,18 +39,16 @@
39
39
  <span class="ws-chip">Follow-up</span>
40
40
  </div>
41
41
  <div class="ws-cluster ws-cluster--loose">
42
- <button class="ws-btn ws-btn--secondary">Share</button>
43
- <button class="ws-btn ws-btn--ghost">Not now</button>
42
+ <button type="button" class="ws-btn ws-btn--secondary">Share</button>
43
+ <button type="button" class="ws-btn ws-btn--ghost">Not now</button>
44
44
  </div>
45
45
  </section>
46
46
  <section class="ws-card ws-card--inset ws-stack ws-stack--loose" aria-labelledby="page-area">
47
- <h2 class="ws-title" id="page-area">An area</h2>
48
- <p class="ws-body">Small cards and tiles size from the page. Inside a card or a pane, mark the region .ws-area and they size from it instead.</p>
49
- <div class="ws-area">
50
- <div class="ws-board ws-board--4">
51
- <div class="ws-plate ws-stack ws-stack--tight"><span class="ws-muted">Goal</span><span class="ws-section">40</span></div>
52
- <div class="ws-plate ws-stack ws-stack--tight"><span class="ws-muted">Done</span><span class="ws-section">26</span></div>
53
- </div>
47
+ <h2 class="ws-title" id="page-area">A board in a card</h2>
48
+ <p class="ws-body">The small-card board sizes from its own width, not the page's: in this card it is one across, with no .ws-area round it.</p>
49
+ <div class="ws-board ws-board--4">
50
+ <div class="ws-plate ws-stack ws-stack--tight"><span class="ws-muted">Goal</span><span class="ws-section">40</span></div>
51
+ <div class="ws-plate ws-stack ws-stack--tight"><span class="ws-muted">Done</span><span class="ws-section">26</span></div>
54
52
  </div>
55
53
  </section>
56
54
  </div>
@@ -0,0 +1,7 @@
1
+ /* ---- Page: the page's own values in 0.5.0 (the page, the board and the stack live in _house.css). Seth's 32 gutter (D4) is the
2
+ global --ws-gutter now, 16 on a phone as before. A board of small cards measures itself (K3): one across, two from 40rem of the board's own
3
+ width, four from 60rem, so it is right in a pane, a column or the shell's body, with no .ws-area round it. ---- */
4
+ .ws-board--4 { container: ws-board / inline-size; grid-template-columns: repeat(4, minmax(0, 1fr)); }
5
+ .ws-board--4 > * { grid-column: span 4; }
6
+ @container ws-board (min-width: 40rem) { .ws-board--4 > * { grid-column: span 2; } }
7
+ @container ws-board (min-width: 60rem) { .ws-board--4 > * { grid-column: span 1; } }