@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
@@ -0,0 +1,112 @@
1
+ A page's main column and its aside, side by side when both fit and stacked when they do not. It measures its own
2
+ width, so it is right in the shell's body, a page, a dialog or a pane.
3
+
4
+ ## Use it when
5
+
6
+ - A page shows a list or a report and, beside it, the detail of the one thing picked (Seth's checks list and its
7
+ check drawer).
8
+ - A page needs a column of facts or acts beside its main content (a deal and its next steps).
9
+ - The two parts have different jobs and the aside has a natural width; the main column takes the rest.
10
+
11
+ ## Not for
12
+
13
+ - A page of like cards: that is a board (`CardBoard`, `.ws-board`).
14
+ - Small cards one, two then four across: `.ws-board--4` (see `Page`).
15
+ - A drawer that covers the page: `Panel` or a `Dialog` drawer.
16
+ - A list and its detail joined into one surface: `ListDetail` (from WP-data).
17
+
18
+ ## Anatomy
19
+
20
+ - `<div class="ws-split">`: a size container named `ws-split`, its two parts 24 apart (`--ws-gap-group`, Seth's gap
21
+ between a report and its drawer), tops on one line (nothing stretches).
22
+ - Main (`__main`): takes the width the aside leaves, never under 0 (its content wraps or scrolls inside itself).
23
+ - Aside (`__aside`): 440 wide (`--ws-thing-width`, Seth's drawer). A page that needs another width sets
24
+ `--ws-split-aside` on the split from a token (North's side columns run 320 to 420).
25
+ - From 60rem of the split's own width the two sit side by side; under it the aside goes under the main column, both
26
+ the full width, in DOM order (the phone's order is the reading order).
27
+ - `--sticky`: side by side, the aside stays in view while the main column scrolls past it (`position: sticky`), 16
28
+ under the scroller's top (`--ws-gap-component`), the same gap it had under the bar before it stuck.
29
+ - `--fill`: the split is the rest of a height-bound column (the shell's body, a pane), Seth's report and its check
30
+ drawer (`301:2011`). Side by side, both parts take its height: the main column scrolls on its own (with 4 px of room
31
+ at its sides, so a ring on a row's edge is never cut) and the aside runs to the foot, its last part (a `Panel`'s
32
+ foot, a card's band) on the bottom. In the shell's body the page then ends 24 above the stage's foot, as Seth draws
33
+ it. Stacked, the split scrolls the two together. Its parent must be a flex column with a height.
34
+
35
+ ## Variants and sizes
36
+
37
+ | Width of the split | Shows |
38
+ | --- | --- |
39
+ | 60rem and up | Main (the rest) and aside (440) side by side, 24 apart |
40
+ | Under 60rem | Main, then the aside under it, each the full width, 24 apart |
41
+
42
+ | Class | Height | Use |
43
+ | --- | --- | --- |
44
+ | (default) | Each part its content's | A page that scrolls as a whole |
45
+ | `--sticky` | The aside its own, held in view | A long main column beside a short aside |
46
+ | `--fill` | Both the rest of the column, the main scrolling inside | Seth's report and its drawer, the drawer's acts on the stage foot |
47
+
48
+ ## States
49
+
50
+ - **Default**: side by side or stacked by width, as above.
51
+ - **Long content**: the main column grows the page; the aside keeps its own height. With `--sticky` it stays in view;
52
+ with `--fill` the main column scrolls inside its part and the aside's foot stays on the bottom; while rows are
53
+ hidden below, its last 24 px fade out (a scroll-driven fade, as `ListDetail`'s list), so a cut on a row's edge never
54
+ reads as the end. The fade lifts at the end, a column that fits shows none, and a keyboard focus inside drops it.
55
+ - **Long words**: they wrap inside their part, never widening it past its column.
56
+ - **No aside**: leave the split out; the main content goes straight in the page.
57
+ - **Loading**: each part shows its own ghosts (`.ws-shimmer`) at the size of what is coming.
58
+
59
+ ## Behaviour
60
+
61
+ - Order is DOM order at every width: put the part that matters first on a phone first in the markup.
62
+ - No motion of its own; the parts' content settles in. The `--fill` fade follows the scroll, not time, so it is the
63
+ same under reduced motion.
64
+ - It sizes from its own width, never the window's, so in a 720 px pane it stacks even on a wide screen.
65
+
66
+ ## Content
67
+
68
+ - The main column holds the page's answer; the aside holds the detail of one picked thing or the page's next acts.
69
+ - The aside's head names what it is the detail of, once.
70
+
71
+ ## Props
72
+
73
+ | Name | Type | Meaning |
74
+ | --- | --- | --- |
75
+ | `main` | `ReactNode` | The main column |
76
+ | `aside` | `ReactNode` | The aside |
77
+ | `asideWidth` | `string` | A token for `--ws-split-aside`; default `--ws-thing-width` |
78
+ | `sticky` | `boolean` | Keeps the aside in view while the main column scrolls |
79
+ | `fill` | `boolean` | The split is the rest of a height-bound column; the main column scrolls inside it |
80
+
81
+ ## Rules
82
+
83
+ - **Size from the split, not the window** (K3): it is its own container.
84
+ - **Tops on one line**: the two parts start on the same edge; neither adds a margin.
85
+ - **DOM order is the phone's order**: never reorder the parts for a narrow screen.
86
+
87
+ ## Source
88
+
89
+ **Derived from**: Seth's Grow report with its check drawer (Figma `301:1630`: report 886, gap 24, drawer 440 in a
90
+ 1350 content box), North's side columns (`style1.css` 311, 446, 963, 1036: a chart and a 320 to 420 column, 24 apart)
91
+ and Revenue OS's missing "main plus aside" pattern (Aryan's `.mock-split`, which switched by window and left the main
92
+ column too narrow at 1280). New in 0.5.0, 4 Nov 2026.
93
+
94
+ ## Markup
95
+
96
+ ```html
97
+ <div class="ws-split ws-split--sticky">
98
+ <div class="ws-split__main">
99
+ <!-- the report or the list -->
100
+ </div>
101
+ <aside class="ws-split__aside" aria-labelledby="split-aside-title">
102
+ <h2 class="ws-title" id="split-aside-title">Local search</h2>
103
+ <!-- the detail of the picked thing -->
104
+ </aside>
105
+ </div>
106
+ ```
107
+
108
+ ## Styles
109
+
110
+ `Split/style.css`. Tokens: `--ws-gap-group`, `--ws-gap-component`, `--ws-thing-width`, `--ws-focus-width`,
111
+ `--ws-focus-offset`, `--ws-ink`; the page may set `--ws-split-aside`. With the shell, Seth's frame is
112
+ `<main class="ws-app-shell__body ws-app-shell__body--wide"><div class="ws-split ws-split--fill">`.
@@ -0,0 +1,105 @@
1
+ <!-- @dsCard group="Layout" height=974 -->
2
+ <!doctype html>
3
+ <html>
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <title>Split</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">
14
+ <span class="ws-muted">Side by side from 60rem of its own width: the main column takes the rest, the aside 440, 24 apart, tops on one line; --sticky keeps the aside in view</span>
15
+ <div class="ws-split ws-split--sticky">
16
+ <div class="ws-split__main ws-stack ws-stack--component">
17
+ <section class="ws-section-group" aria-labelledby="split-checks">
18
+ <div class="ws-section-group__head">
19
+ <div class="ws-section-group__words">
20
+ <h2 id="split-checks" class="ws-section-group__title">Your AI visibility checks</h2>
21
+ </div>
22
+ </div>
23
+ <ul>
24
+ <li class="ws-section-group__row"><span class="ws-row-name">Local search</span><span class="ws-figure ws-figure--row">39</span></li>
25
+ <li class="ws-section-group__row"><span class="ws-row-name">Website</span><span class="ws-figure ws-figure--row">75</span></li>
26
+ <li class="ws-section-group__row"><span class="ws-row-name">Social</span><span class="ws-figure ws-figure--row">92</span></li>
27
+ <li class="ws-section-group__row"><span class="ws-row-name">Zillow</span><span class="ws-figure ws-figure--row">100</span></li>
28
+ </ul>
29
+ </section>
30
+ <section class="ws-card ws-card--inset ws-stack" aria-labelledby="split-more">
31
+ <h2 class="ws-title" id="split-more">Zillow is your strongest</h2>
32
+ <p class="ws-body">Start with Local search: buyers near you see you in five of nine spots, never in the top three.</p>
33
+ </section>
34
+ </div>
35
+ <aside class="ws-split__aside ws-card ws-card--inset ws-stack ws-stack--loose" aria-labelledby="split-aside">
36
+ <h2 class="ws-title" id="split-aside">Local search</h2>
37
+ <p class="ws-body">How often you show up on Google Maps when buyers search near you.</p>
38
+ <div class="ws-plate ws-stack ws-stack--tight">
39
+ <span class="ws-muted">Next fix, 1 of 2</span>
40
+ <span class="ws-section">Name the towns you serve in your Google Business Profile.</span>
41
+ </div>
42
+ <div class="ws-cluster">
43
+ <button type="button" class="ws-btn ws-btn--secondary">Send to my web person</button>
44
+ <button type="button" class="ws-btn ws-btn--primary">Review the rewrite</button>
45
+ </div>
46
+ </aside>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="ws-stack">
51
+ <span class="ws-muted">--fill in a height-bound column (here a 280 px frame standing in for the shell's body): both parts take its height, the main column scrolls on its own, the aside's foot sits on the bottom</span>
52
+ <div style="height: 280px; display: flex; flex-direction: column;">
53
+ <div class="ws-split ws-split--fill">
54
+ <div class="ws-split__main">
55
+ <section class="ws-section-group" aria-labelledby="split-fill-checks">
56
+ <div class="ws-section-group__head">
57
+ <div class="ws-section-group__words">
58
+ <h2 id="split-fill-checks" class="ws-section-group__title">Your AI visibility checks <span class="ws-section-group__count">6 checks</span></h2>
59
+ </div>
60
+ </div>
61
+ <ul>
62
+ <li class="ws-section-group__row"><span class="ws-row-name">Local search</span><span class="ws-figure ws-figure--row">39</span></li>
63
+ <li class="ws-section-group__row"><span class="ws-row-name">Website</span><span class="ws-figure ws-figure--row">75</span></li>
64
+ <li class="ws-section-group__row"><span class="ws-row-name">Social</span><span class="ws-figure ws-figure--row">92</span></li>
65
+ <li class="ws-section-group__row"><span class="ws-row-name">Zillow</span><span class="ws-figure ws-figure--row">100</span></li>
66
+ <li class="ws-section-group__row"><span class="ws-row-name">Google profile</span><span class="ws-muted">Could not check</span></li>
67
+ <li class="ws-section-group__row"><span class="ws-row-name">AI answers</span><span class="ws-muted">Could not check</span></li>
68
+ <li class="ws-section-group__row"><span class="ws-row-name">Reviews</span><span class="ws-figure ws-figure--row">88</span></li>
69
+ </ul>
70
+ </section>
71
+ </div>
72
+ <aside class="ws-split__aside ws-card ws-card--compound" aria-labelledby="split-fill-aside">
73
+ <header class="ws-head"><div>
74
+ <h2 class="ws-title" id="split-fill-aside">Local search</h2>
75
+ <p class="ws-body ws-card__line">How often you show up on Google Maps when buyers search near you.</p>
76
+ </div></header>
77
+ <footer class="ws-band">
78
+ <div class="ws-band__words">
79
+ <p class="ws-band__title">Next fix, 1 of 2</p>
80
+ <p class="ws-band__how">Name the towns you serve</p>
81
+ </div>
82
+ <button type="button" class="ws-btn ws-btn--primary ws-btn--lg">Review the rewrite</button>
83
+ </footer>
84
+ </aside>
85
+ </div>
86
+ </div>
87
+ </div>
88
+
89
+ <div class="ws-stack" style="width: 720px; max-width: 100%;">
90
+ <span class="ws-muted">Under 60rem (here a 720 px column): the aside goes under the main column, both the full width, in DOM order</span>
91
+ <div class="ws-split">
92
+ <section class="ws-split__main ws-card ws-card--inset ws-stack" aria-labelledby="split-narrow-main">
93
+ <h2 class="ws-title" id="split-narrow-main">Three offers wait on you</h2>
94
+ <p class="ws-body">The oldest has waited two days. Call Dana Alvarez first, then Marco Diaz.</p>
95
+ </section>
96
+ <aside class="ws-split__aside ws-card ws-card--inset ws-stack" aria-labelledby="split-narrow-aside">
97
+ <h2 class="ws-section" id="split-narrow-aside">Dana Alvarez</h2>
98
+ <p class="ws-body">Offer out Monday on 14 Elm Street, a long label that wraps inside the aside rather than widening it past its column.</p>
99
+ </aside>
100
+ </div>
101
+ </div>
102
+
103
+ </div>
104
+ </body>
105
+ </html>
@@ -0,0 +1,30 @@
1
+ /* ---- Split: a page's main column and its aside (a check's drawer, a list's detail, a column of facts) side by side, 24
2
+ apart, tops on one line; the aside 440 wide (Seth's drawer, --ws-thing-width) unless the page sets --ws-split-aside.
3
+ It measures itself: under 60rem of its own width the two stack in DOM order, each the full width. --sticky keeps the
4
+ aside in view while the main column scrolls past it; --fill makes the split the rest of a height-bound column. ---- */
5
+ .ws-split { container: ws-split / inline-size; display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--ws-gap-group); }
6
+ .ws-split > * { flex: 1 1 100%; min-width: 0; }
7
+ /* Fill (Seth's report and its drawer, 301:2011): the split takes the rest of a height-bound column (the shell's body).
8
+ Side by side, both parts take its height: the main column scrolls on its own (4 px of room at its sides, so a ring on
9
+ a row's edge is never cut; its scroll edges stay on the aside's) and the aside runs to the foot, its last part (a
10
+ Panel's or a card's foot) on the bottom. Stacked, the split scrolls the two together. */
11
+ .ws-split--fill { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--ws-ink) 18%, transparent) transparent; }
12
+ @container ws-split (min-width: 60rem) {
13
+ .ws-split > .ws-split__main { flex: 1 1 0; }
14
+ .ws-split > .ws-split__aside { flex: 0 0 var(--ws-split-aside, var(--ws-thing-width)); }
15
+ .ws-split--sticky > .ws-split__aside { position: sticky; top: var(--ws-gap-component); }
16
+ .ws-split--fill > :is(.ws-split__main, .ws-split__aside) { align-self: stretch; max-height: 100%; min-height: 0; }
17
+ .ws-split--fill > .ws-split__main { --ws-split-room: calc(var(--ws-focus-width) + var(--ws-focus-offset)); margin-inline: calc(var(--ws-split-room) * -1); padding-inline: var(--ws-split-room); overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--ws-ink) 18%, transparent) transparent; }
18
+ .ws-split--fill > .ws-split__aside { overflow-y: auto; }
19
+ .ws-split--fill > .ws-split__aside > :last-child:not(:first-child) { margin-top: auto; }
20
+ }
21
+ /* The main column shows that it holds more (a cut on a row's edge reads as the list's end): while rows are hidden below,
22
+ its last 24 px fade out, and the fade lifts at the end. Scroll-driven, as ListDetail's list, so a column that fits
23
+ shows none and nothing moves under reduced motion. A keyboard focus inside drops it, so a ring is never faded. */
24
+ @supports (animation-timeline: scroll()) {
25
+ @container ws-split (min-width: 60rem) {
26
+ .ws-split--fill > .ws-split__main { mask-image: linear-gradient(to top, transparent, var(--ws-mask) var(--space-lg)); mask-size: 100% calc(100% + var(--space-lg)); mask-repeat: no-repeat; animation: ws-split-end linear both; animation-timeline: scroll(self block); animation-range: calc(100% - var(--space-lg)) 100%; }
27
+ .ws-split--fill > .ws-split__main:is(:focus-visible, :has(:focus-visible)) { mask-image: none; }
28
+ }
29
+ }
30
+ @keyframes ws-split-end { from { mask-position: 0 calc(var(--space-lg) * -1); } to { mask-position: 0 0; } }
@@ -5,8 +5,8 @@ paste the CSS into the `<style>`, then replace the sample content with the real
5
5
  ## Use it when
6
6
 
7
7
  - Starting any page on the system: a claude.ai artifact, a mockup, a one-off HTML page, a report or a dashboard.
8
- - Starting from markup only: every class in it is the kit's (`fello-core.css` plus the `Card` styles), so the page needs no
9
- CSS of its own.
8
+ - Starting from markup only: every class in it is the kit's (`fello-core.css` plus the `Page`, `PageBar`, `Card`,
9
+ `Button` and `Well` blocks), so the page needs no CSS of its own.
10
10
 
11
11
  ## Not for
12
12
 
@@ -20,11 +20,13 @@ paste the CSS into the `<style>`, then replace the sample content with the real
20
20
  - `<head>`: charset, viewport, a title, the Google Fonts link for Instrument Sans (fello.css also imports it; the link
21
21
  loads it sooner), and one `<style>` holding the kit's CSS.
22
22
  - In a claude.ai artifact the CSS must be inlined (an artifact may load no stylesheet but Google Fonts): paste
23
- `fello-core.css`, then the styles of each component the page uses (each component's card lists them; the whole
24
- `fello.css` is too big to paste). A plain page links the whole file instead, pinned:
25
- `https://brand-kit-site-production.up.railway.app/v/0.4.0/fello.css`.
26
- - `<main class="ws-page">`: the page (see `Page`).
27
- - `PageBar`: the page's one `h1`, one line, and its acts with the page's one navy primary last.
23
+ `fello-core.css`, then the styles of each component the page uses (each component's card lists them; this page needs
24
+ `Page`, `PageBar`, `Card`, `Button` and `Well`; the whole `fello.css` is too big to paste). The buttons and the well
25
+ rows need their own blocks: `fello-core.css` holds only their 0.4 look. A plain page links the whole file instead,
26
+ pinned: `https://brand-kit-site-production.up.railway.app/v/0.5.0/fello.css`.
27
+ - `<main class="ws-page">`: the page (see `Page`), Seth's 32 gutter.
28
+ - `PageBar`: the page's 56 px header, its one `h1` (16 / 22 semibold) and a word of context beside it, and its acts
29
+ with the page's one navy primary last.
28
30
  - `.ws-board` with two `Card`s, each `ws-card ws-card--compound`: a head (`.ws-head`, the 22 px title that answers the
29
31
  question and one line), a body (`.ws-card__body`), and a footer band (`.ws-band`) whose act is secondary, since the
30
32
  page's one primary is in the PageBar.
@@ -34,7 +36,7 @@ paste the CSS into the `<style>`, then replace the sample content with the real
34
36
 
35
37
  - **Wide**: the two cards side by side, each up to 556.
36
38
  - **Narrow** (under 976 of content): one column, the first card first.
37
- - **Arriving**: the cards rise in, 30 ms apart; still with reduced motion.
39
+ - **Arriving**: the cards settle in (`ws-settle`, `--ws-i` 0 and 1), 22 ms apart; still with reduced motion.
38
40
 
39
41
  ## Behaviour
40
42
 
@@ -57,4 +59,14 @@ paste the CSS into the `<style>`, then replace the sample content with the real
57
59
  ## Source
58
60
 
59
61
  **Derived from**: `Page`, `PageBar`, `CardBoard` and `Card` in this catalog, and the first product's dashboard
60
- arrangement (a page bar, then tiles, then cards). Added 27 Oct 2026 so a page is built from markup only.
62
+ arrangement (a page bar, then tiles, then cards). Added 27 Oct 2026 so a page is built from markup only; brought to
63
+ 0.5.0 (Seth's thread header and gutter) 4 Nov 2026.
64
+
65
+ ## Markup
66
+
67
+ The whole of `preview.html` is the markup to copy: the head, the one `<style>`, the page, its bar and the board.
68
+
69
+ ## Styles
70
+
71
+ Starter has no `style.css`: it is `fello-core.css` (tokens and the house) plus the `Page`, `PageBar`, `Card`,
72
+ `Button` and `Well` blocks. Write no other CSS. A component added to the page brings its own block (its card says which).
@@ -7,12 +7,12 @@
7
7
  <title>Starter</title>
8
8
  <!-- In a claude.ai artifact, paste fello-core.css into the <style> below, then the styles of each component you use
9
9
  (each component's card lists them): an artifact may load no stylesheet but Google Fonts. On a plain page, link the
10
- whole kit instead, pinned: https://brand-kit-site-production.up.railway.app/v/0.4.0/fello.css -->
10
+ whole kit instead, pinned: https://brand-kit-site-production.up.railway.app/v/0.5.0/fello.css -->
11
11
  <link rel="preconnect" href="https://fonts.googleapis.com">
12
12
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
13
13
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400..700&display=swap">
14
14
  <style>
15
- /* fello-core.css here, then each used component's styles (this page: PageBar, Card). Write no other CSS. */
15
+ /* fello-core.css here, then each used component's styles (this page: Page, PageBar, Card, Button, Well). Write no other CSS. */
16
16
  </style>
17
17
  </head>
18
18
  <body>
@@ -21,7 +21,7 @@
21
21
  <header class="ws-page-bar">
22
22
  <div class="ws-page-bar__words">
23
23
  <h1 class="ws-page-bar__title">Calls this month</h1>
24
- <p class="ws-body">Your team's calls and who to call next, since Oct 1.</p>
24
+ <span class="ws-page-bar__context">Your team's calls since Oct 1</span>
25
25
  </div>
26
26
  <div class="ws-page-bar__acts">
27
27
  <button type="button" class="ws-btn ws-btn--secondary">Share</button>
@@ -31,7 +31,7 @@
31
31
 
32
32
  <div class="ws-board">
33
33
 
34
- <section class="ws-card ws-card--compound ws-rise" aria-labelledby="starter-pace">
34
+ <section class="ws-card ws-card--compound ws-settle" style="--ws-i: 0;" aria-labelledby="starter-pace">
35
35
  <header class="ws-head">
36
36
  <div>
37
37
  <h2 class="ws-title" id="starter-pace">On pace for 40 calls by Oct 22</h2>
@@ -56,7 +56,7 @@
56
56
  </footer>
57
57
  </section>
58
58
 
59
- <section class="ws-card ws-card--compound ws-rise" style="animation-delay: 30ms;" aria-labelledby="starter-waiting">
59
+ <section class="ws-card ws-card--compound ws-settle" style="--ws-i: 1;" aria-labelledby="starter-waiting">
60
60
  <header class="ws-head">
61
61
  <div>
62
62
  <h2 class="ws-title" id="starter-waiting">Three leads are waiting</h2>
@@ -1,6 +1,6 @@
1
1
  The kit's marketing piece: for a public page, never a product screen.
2
2
 
3
- A single figure with its label, built to be a marketing proof point, three of them in a row.
3
+ A single figure with its label, built to be a marketing proof point, three of them in a strip.
4
4
 
5
5
  ## Use it when
6
6
 
@@ -11,87 +11,108 @@ A single figure with its label, built to be a marketing proof point, three of th
11
11
 
12
12
  ## Not for
13
13
 
14
- - Any product screen: use `StatTiles` or `GoalTicks`, which carry the product's 40px and 72px
15
- figure sizes and its "a card whose data does not exist is left out" rule instead of a dash.
16
- - A number that changes and should be compared to a past value: that is a `ChangeChip` beside a figure, a
17
- different idea than this component carries.
14
+ - Any product screen: use `StatTiles` or `GoalTicks`, which carry the product's figure sizes and its "a card whose
15
+ data does not exist is left out" rule instead of a dash.
16
+ - A number that should be compared to a past value: that is a change chip beside a figure.
18
17
  - Several related numbers that need their own chart: a bar or goal chart, not three `Stat`s side by side.
19
18
 
20
19
  ## Anatomy
21
20
 
22
- - Label: `--font-size-3xs` (10px), semibold, uppercase, `--letter-spacing-overline` (1.2px) tracking, `--color-text-muted`.
23
- - Value: 28px semibold, 1.05 line height, tabular numerals, `--color-text-heading` by default (see Rules for why
24
- 28px is not a token step).
25
- - Note: `--font-size-2xs` (12px), 16px line height, `--color-text-muted`, `--space-xxs` (4px) below the value.
26
- - Gap from label to value: `--space-xxs` (4px).
21
+ - Label (`__label`): 12/16 (`--font-size-2xs`), semibold, uppercase, `--letter-spacing-overline` (1.2px),
22
+ `--color-text-muted`.
23
+ - Value (`__value`): `--space-xxs` (4px) under the label, 28/32 (`--ws-text-figure-row`, `--ws-leading-figure-row`)
24
+ semibold, tabular numerals, `--color-text-heading` by default.
25
+ - Note (`__note`): `--space-xxs` under the value, 12/16 `--color-text-muted`.
26
+ - Strip (`.ws-stat-strip`): the stats `--space-2xl` (40px) apart in a row, wrapping with `--space-lg` (24px) between
27
+ rows when they do not fit.
27
28
 
28
29
  ## Variants and sizes
29
30
 
30
- One size. Four tones, set by the `tone` prop:
31
+ One size. Four tones:
31
32
 
32
33
  | Tone | Colour | Use |
33
34
  | --- | --- | --- |
34
35
  | `default` | `--color-text-heading` (navy) | the ordinary case |
35
36
  | `positive` | `--color-stat-positive` (teal) | a number that is good news |
36
- | `brand` | `--color-brand-salmon` | a number that should draw the eye |
37
+ | `brand` | `--color-text-brand-strong` (salmon's word step) | a number that should draw the eye |
37
38
  | `muted` | `--color-text-muted` | a secondary or softer number beside a stronger one |
38
39
 
40
+ Classes: the default is the bare `ws-stat__value`; the tones are `ws-stat__value--positive`, `--brand` and `--muted`.
41
+ `ws-stat__value--none` is the no-data state (muted, an en dash), not a tone.
42
+
39
43
  ## States
40
44
 
41
- - **Value (default):** the number, in its tone, as above.
42
- - **Pending:** a shimmering block takes the value's place, sized to roughly match a number (29px tall, 80px
43
- wide, `--color-gray-2`), never a zero. A screen reader hears "Loading" from an `sr-only` span. This is the
44
- state to use while a real source is still answering.
45
- - **No data (`value: null`):** an en dash in `--color-gray-5`, with "No data" read to a screen reader. The kit's
46
- own doc comment draws the line sharply: "A zero is a claim about the business that may be false; an X reads as
47
- 'this broke'; a dash reads as 'nothing here yet', which is the only true one." This is not the pending state:
48
- it means nothing is wired up at all.
49
- - **Hover / focus / selected / pressed:** not applicable; `Stat` renders no interactive element.
50
- - **Disabled / error:** not applicable.
45
+ - **Value (default):** the number, in its tone.
46
+ - **Pending:** a ghost the size of a number (80 by 32, `--ws-radius-row`) under the house shimmer (`ws-shimmer`), never a
47
+ zero. It is the figure's own height, so nothing shifts when the number lands. A screen reader hears "Loading".
48
+ Under reduced motion it is the still ghost.
49
+ - **No data (`value: null`):** an en dash in `--color-text-muted`, with "No data" read to a screen reader. "A zero is a
50
+ claim about the business that may be false; an X reads as 'this broke'; a dash reads as 'nothing here yet', which is
51
+ the only true one." This is not pending: it means nothing is wired up at all.
52
+ - **Hover / focus / selected / pressed / disabled / error:** not applicable; `Stat` renders nothing interactive.
51
53
  - **Long label:** the label wraps; the value's size does not change to fit.
52
- - **Narrow:** `min-w-0` on the outer element lets the value truncate its container's width rather than overflow a
53
- tight column.
54
+ - **Narrow:** the strip wraps, so each stat keeps its words on its own lines instead of crushing into a third of a phone.
54
55
 
55
56
  ## Behaviour
56
57
 
57
58
  - Keyboard: nothing to focus; this is read-only content.
58
59
  - Pointer / touch: no interaction.
59
- - Motion: the pending block pulses on `animate-pulse`, dropped under `prefers-reduced-motion: reduce` in favour of
60
- a still block (`motion-reduce:animate-none`).
60
+ - Motion: the pending shimmer sweeps over 1.8s (`--ws-loop-shimmer`), only under `prefers-reduced-motion: no-preference`.
61
61
 
62
62
  ## Content
63
63
 
64
- - Label: short, uppercase by the component itself, so write it in sentence case in code ("Appointments booked").
64
+ - Label: short, written in sentence case ("Appointments booked"); the component shows it uppercase.
65
65
  - Value: the real number, pre-formatted (with its "%", "$" or comma) by the caller; `Stat` does not format it.
66
66
  - Note: one short line of context ("Last 30 days, across the team"), optional.
67
- - No em dashes; the "no data" mark is an en dash, drawn by the component, not typed.
67
+ - No em dashes; the "no data" mark is an en dash, drawn by the component.
68
68
 
69
69
  ## Props
70
70
 
71
+ The React `Stat` (`@felloinnovations/brand-kit`) renders this with Tailwind utilities on the same tokens.
72
+
71
73
  | Name | Type | Meaning |
72
74
  | --- | --- | --- |
73
75
  | `label` | `string` | the small uppercase caption |
74
76
  | `value` | `string \| null` | the figure; `null` means no source is connected, not zero |
75
77
  | `note` | `string \| null` | optional context line under the value |
76
78
  | `tone` | `'default' \| 'positive' \| 'brand' \| 'muted'` | the value's colour, default `default` |
77
- | `pending` | `boolean` | shows the shimmering placeholder instead of `value` |
79
+ | `pending` | `boolean` | shows the shimmer ghost instead of `value` |
78
80
 
79
81
  ## Rules
80
82
 
81
- - "A zero is a claim about the business that may be false; an X reads as 'this broke'; a dash reads as 'nothing
82
- here yet', which is the only true one." (`dist/index.d.ts`, doc comment on `StatProps`.)
83
- - "null means no source is connected. It does not mean zero." (same doc comment, on the `value` field.)
84
- - **Contradiction found, reported rather than resolved:** the kit's own `AGENTS.md` states the house rule "Never
85
- write a raw px font-size. There is a token for every step," yet `Stat`'s own source writes the value at a literal
86
- `text-[28px]` and sizes its pending placeholder at literal `h-[29px] w-20`, none of which match a step in
87
- `tokens/tokens.md` (the nearest are `--font-size-2xl` at 26px and `--font-size-3xl` at 40px). fello.css keeps the
88
- kit's actual 28px value rather than rounding it to a step, since the brief asks for the kit's values exactly and code
89
- is truth, but writes it as a calc on the 4px grid (`.ws-stat__value`: `calc(var(--space-lg) + var(--space-xxs))`;
90
- the pending block 29 by 80, `.ws-stat__pending`); the mismatch is reported here, not silently fixed.
91
- - `--color-feedback-*` and `--color-stat-positive` are themselves flagged provisional in `AGENTS.md`: "inherited
92
- from the HubSpot boilerplate, awaiting design." `positive` carries this caveat along with it.
83
+ - "null means no source is connected. It does not mean zero." (`dist/index.d.ts`, doc comment on `value`.)
84
+ - **The figure is a type step now** (D6, 4 Nov 2026): 28/32, the kit's row figure. It was a 28px calc with a 1.05
85
+ line height, and the React export drew 26px; both are 28/32 now.
86
+ - **Brand takes salmon's word step** (D2): salmon itself is 2.7:1 on white, under the 3:1 a 28px figure needs.
87
+ - **Labels are 12px** (`06-sizing-profiles.md`, public web: "meta, labels 12 to 14"); they were 10px.
88
+ - **Pending is the shimmer** (D7, North): it was a grey block on the house pulse.
89
+ - The strip wraps (4 Nov 2026): at 320px the three stats were 74px each and their labels and values ran past their boxes.
90
+ - `--color-stat-positive` is still flagged provisional in `AGENTS.md`.
93
91
 
94
92
  ## Source
95
93
 
96
- **Derived from**: the kit's own `Stat` component, its doc comments on null-versus-zero data and pending states, and
97
- the house rule that every size is a token. **Precedent**: marketing pages only; no product screen uses it.
94
+ **Derived from**: the kit's own `Stat`, its doc comments on null versus zero and pending, the type steps (D6), North's
95
+ loading shimmer (D7), the public web profile and the geometry check at 320. **Precedent**: marketing pages only.
96
+
97
+ ## Markup
98
+
99
+ ```html
100
+ <div class="ws-stat-strip">
101
+ <div class="ws-stat">
102
+ <div class="ws-stat__label">Appointments booked</div>
103
+ <div class="ws-stat__value ws-stat__value--positive">214</div>
104
+ <div class="ws-stat__note">Last 30 days, across the team</div>
105
+ </div>
106
+ <div class="ws-stat">
107
+ <div class="ws-stat__label">Calls this week</div>
108
+ <div class="ws-stat__value" aria-busy="true"><span class="ws-stat__pending ws-shimmer"><span class="ws-sr">Loading</span></span></div>
109
+ </div>
110
+ <div class="ws-stat">
111
+ <div class="ws-stat__label">Profile views</div>
112
+ <div class="ws-stat__value ws-stat__value--none"><span aria-hidden="true">&ndash;</span><span class="ws-sr">No data</span></div>
113
+ <div class="ws-stat__note">No source connected yet</div>
114
+ </div>
115
+ </div>
116
+ ```
117
+
118
+ Styles: the `Stat` block (`components/Stat/style.css`); `ws-shimmer` and `ws-sr` are in `fello-core.css`.
@@ -1,6 +1,6 @@
1
1
  <!-- @dsCard group="Marketing" height=247 -->
2
2
  <!doctype html>
3
- <html>
3
+ <html lang="en">
4
4
  <head>
5
5
  <meta charset="utf-8">
6
6
  <title>Stat</title>
@@ -20,8 +20,8 @@
20
20
  </div>
21
21
  <div class="ws-stat">
22
22
  <div class="ws-stat__label">Calls this week</div>
23
- <div class="ws-stat__value ws-working" aria-busy="true">
24
- <span class="ws-stat__pending"><span class="ws-sr">Loading</span></span>
23
+ <div class="ws-stat__value" aria-busy="true">
24
+ <span class="ws-stat__pending ws-shimmer"><span class="ws-sr">Loading</span></span>
25
25
  </div>
26
26
  <div class="ws-stat__note">Still counting Monday's calls</div>
27
27
  </div>
@@ -0,0 +1,15 @@
1
+ /* ---- Stat: the kit's marketing figure, its label above and a note under, three to a strip that wraps on a phone ---- */
2
+ .ws-stat-strip { display: flex; flex-wrap: wrap; gap: var(--space-lg) var(--space-2xl); }
3
+ .ws-stat { min-width: 0; }
4
+ .ws-stat__label { font-size: var(--font-size-2xs); line-height: var(--space-md); font-weight: 600; text-transform: uppercase; letter-spacing: var(--letter-spacing-overline); color: var(--color-text-muted); }
5
+ /* The figure is the kit's 28 / 32 row step (D6), semibold because it is a marketing heading. */
6
+ .ws-stat__value { margin-top: var(--space-xxs); font-size: var(--ws-text-figure-row); line-height: var(--ws-leading-figure-row); font-weight: 600; font-variant-numeric: tabular-nums; color: var(--color-text-heading); }
7
+ .ws-stat__value--positive { color: var(--color-stat-positive); }
8
+ /* Salmon itself is 2.7:1 on white, under the 3:1 a 28 px figure needs; its word step carries the tone. */
9
+ .ws-stat__value--brand { color: var(--color-text-brand-strong); }
10
+ .ws-stat__value--muted, .ws-stat__value--none { color: var(--color-text-muted); }
11
+ /* Pending: the North shimmer over a ghost the size of a number, never a zero. Same height as the figure, so nothing shifts. */
12
+ .ws-stat__pending { display: block; height: var(--ws-leading-figure-row); width: var(--space-5xl); border-radius: var(--ws-radius-row); }
13
+ /* Markup from before 0.5.0 (no ws-shimmer) still shows its ghost. */
14
+ .ws-stat__pending:not(.ws-shimmer) { background: var(--ws-track); }
15
+ .ws-stat__note { margin-top: var(--space-xxs); font-size: var(--font-size-2xs); line-height: var(--space-md); color: var(--color-text-muted); }