@felloinnovations/brand-kit 0.4.0 → 0.5.1

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 +221 -0
  3. package/README.md +38 -9
  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 +135 -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 +367 -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 +53 -16
  249. package/design-system/components/Skeleton/preview.html +35 -23
  250. package/design-system/components/Skeleton/style.css +17 -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 +4086 -744
  335. package/design-system/tokens.json +1310 -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 +109 -10
  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 +173 -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 +1287 -62
  361. package/tokens/tokens.md +587 -61
  362. package/tokens/tokens.root.css +1293 -62
  363. package/tokens/tokens.ts +1677 -64
@@ -1,58 +1,341 @@
1
1
  # Motion
2
2
 
3
- One motion language: things arrive on one soft curve, leave faster on the exit curve, and nothing loops but the one working
4
- beat. Everything is still under reduced motion.
3
+ Seth's motion, taken from his North app and named by role (D7). Things grow out of where they were and go back the same
4
+ way, quicker. The frame moves first; its details settle after. Hover is a colour, never a lift. Under reduced motion
5
+ everything is still.
5
6
 
6
- ## Tokens
7
+ ## The rule
7
8
 
8
- | Token | Value | For |
9
+ **Motion comes from the kit.** Build with the component's markup and classes and it already moves: the press, the
10
+ sliding indicators, the folds, the enters and exits are in `fello.css`, on Seth's springs. Never type a duration, a
11
+ curve, a `cubic-bezier()`, a spring or a `@keyframes` by hand, and never restyle a kit element's transition.
12
+
13
+ When a part is genuinely your own (nothing in the catalog has it), it still moves on the kit's role tokens, inside
14
+ `@media (prefers-reduced-motion: no-preference)`:
15
+
16
+ - **A spring for what the person drives** (a press, the pointer, a choice, a panel): `--ws-spring-<name>` over
17
+ `--ws-spring-<name>-duration`, always the pair. Each is Seth's spring written out as a CSS `linear()` curve, its own
18
+ small overshoot kept, and the time it takes to settle. A spring can be interrupted and picks up from where it is.
19
+ - **A duration and a curve for what the system plays** (a draw, a build, a loop): `--ws-duration-*` and
20
+ `--ws-ease-*` (Role tokens, below).
21
+
22
+ ```css
23
+ @media (prefers-reduced-motion: no-preference) {
24
+ .my-thumb { transition: translate var(--ws-spring-indicator-duration) var(--ws-spring-indicator); }
25
+ .my-note { animation: ws-settle var(--ws-duration-settle) var(--ws-ease-soft) backwards; }
26
+ }
27
+ ```
28
+
29
+ In React with the motion library, the same springs are presets: `import { springs, eases } from
30
+ '@felloinnovations/brand-kit/tokens'` (`transition={springs.press}`), and every motion tree sits in
31
+ `<MotionConfig reducedMotion="user">`.
32
+
33
+ ## By situation
34
+
35
+ ### Hover
36
+
37
+ A colour, never a lift: no shadow, rise or grow on hover. Kit controls and rows carry their own wash; anything of yours
38
+ takes `.ws-hover-tint` (`--faint` for a list row, the default for a nav or menu row, `--strong` for an icon button or a
39
+ quiet act). It turns over `--ws-duration-hover` (200 ms) on `--ws-ease-soft`, only where a pointer hovers
40
+ (`@media (hover: hover)`), so a tap never leaves it on. Why: a colour answers the pointer without moving the layout; a
41
+ lift says "this floats", and a control does not. What hover reveals (a close, an arrow, a row's acts) also shows on
42
+ `:focus-visible` and on a tap; an arrow may step forward by `--ws-nudge`.
43
+
44
+ ```html
45
+ <li class="lead-row ws-hover-tint ws-hover-tint--faint">...</li>
46
+ ```
47
+
48
+ ### Press
49
+
50
+ `.ws-btn`, `.ws-icon-btn`, `.ws-suggestion-chip` and a chip that acts (`button.ws-chip`, `a.ws-chip`) give under a
51
+ press and spring back, on `--ws-spring-press` (Seth's "Button press (mic, add)"): to `--ws-press-scale` (0.97), a round
52
+ act (`ws-icon-btn--round`, `.ws-press--round`) to 0.94, the send act (`.ws-press--send`) to 0.92. Their colours turn at
53
+ once going in and over `--ws-duration-hover` coming out. Words that act (`--link`, `--text`), a disabled control and a
54
+ busy one do not move. Rows, list rows, menu rows and cards never scale: a press tints them a step darker
55
+ (`--ws-surface-press`). Why: the spring's small give says "pressed" without changing the layout, and it rides `scale`,
56
+ so the control's own transform is untouched. Your own pressable thing adds `.ws-press`.
57
+
58
+ ```html
59
+ <button type="button" class="report-tile ws-press">Open the report</button>
60
+ ```
61
+
62
+ ### A choice moving: sliding indicators
63
+
64
+ When the choice changes, its mark slides from the old item to the new one instead of jumping. No script and no extra
65
+ markup: the chosen item is a CSS anchor and the track's own pseudo-element slides to it. Mark the choice the way the
66
+ component's README says and it moves.
67
+
68
+ | Component | What slides | Spring (Seth's label) |
9
69
  | --- | --- | --- |
10
- | `ws-ease-soft` | decelerate | everything arriving; every pop (no overshoot) |
11
- | `ws-ease-exit` | accelerate | everything leaving |
12
- | `ws-ease-glide` + `ws-duration-glide` | balanced, 400 ms | a side panel's width |
13
- | `ws-ease-steady` | linear | a live ring keeping pace with a clock |
14
- | `ws-duration-instant` | 120 ms | hover, press, focus, a chip flipping, a dialog's exit |
15
- | `ws-duration-gentle` | 200 ms | the default: a row or card arriving, a menu, a drawer leaving |
16
- | `ws-duration-settle` | 320 ms | a pane, dialog or drawer in, a screen changing, a pop, a tile rising |
17
- | `ws-duration-calm` | 420 ms | content replacing a skeleton, a chart drawing, a figure counting |
18
- | `ws-stagger` | 30 ms (40 slow), at most 6 items | a list's first paint only |
19
- | `ws-sweep` | 220 ms | a chart's parts filling first to last |
20
- | `ws-rise` | 6 px | how far things rise as they arrive (the person's message 12) |
21
- | `ws-press-scale` | 0.97 | a control under a press; 1 with reduced motion |
22
- | `ws-loop` / `ws-loop-slow` | 1.2 s / 2.4 s | the working beat; a big quiet area's |
70
+ | `Segmented` | the thumb | `--ws-spring-indicator` ("Toggle pill slide") |
71
+ | `Tabs` | the underline | `--ws-spring-tab` ("Department card underline") |
72
+ | `AppShell` | the sidebar's current-row pill | `--ws-spring-nav` ("Sidebar active row slide") |
73
+ | `SideList`, `ListDetail` | the selected row's fill | `--ws-spring-highlight` ("List highlight slide") |
23
74
 
24
- ## Rules
75
+ Only a real choice moves it: at rest the chosen item paints its own ground, and the slide takes over while the track is
76
+ pointed at or holds focus, so a resize or a late font lands at once. Why a spring: the person drives it, and a second
77
+ click mid-slide turns it from where it is.
78
+
79
+ ```html
80
+ <div class="ws-segmented" role="group" aria-label="View">
81
+ <button type="button" class="ws-segmented__item" aria-pressed="true">Bars</button>
82
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Line</button>
83
+ </div>
84
+ ```
85
+
86
+ ### Something opening in place: folds
87
+
88
+ What opens in place grows from nothing to its height and fades in, then closes back the same way, on `--ws-spring-fold`
89
+ (Seth's "Sidebar sections open / close", no bounce); a chevron turns on the same spring. Every kit `<details>` does it
90
+ on its own (`Fold`, or any `<details>` inside a kit element). A body your script shows and hides with the `hidden`
91
+ attribute wears `.ws-unfold` (as `CheckRow`'s detail does), and its padding and margins grow with it, so nothing
92
+ jumps. Why: what sits below is pushed down smoothly instead of leaping, and the person sees where the new part came
93
+ from.
94
+
95
+ ```html
96
+ <button type="button" aria-expanded="false" aria-controls="why">Why this move</button>
97
+ <div class="ws-unfold" id="why" hidden>...</div>
98
+ ```
99
+
100
+ ### Something appearing over the page: enters and exits
101
+
102
+ It grows out of what opened it and goes back there, **quicker**: every exit is shorter than its entrance. Why: the eye
103
+ follows cause to effect on the way in; on the way out the person has already moved on.
104
+
105
+ | Component | Enters | Leaves | How the exit gets to play |
106
+ | --- | --- | --- | --- |
107
+ | `Menu`, `Popover` | out of the corner it hangs from, 4 px toward its control, from `--ws-open-scale` (0.97), on `--ws-spring-settle` ("Messages and steps settle") | back into that corner over `--ws-duration-exit` (120 ms) on `--ws-ease-exit` | a native `popover`: `@starting-style` and `allow-discrete` keep its box while it leaves, and a close mid-entrance turns back. Mounted by the app: `data-leaving`, then remove it |
108
+ | `Dialog` | the scrim fades; the window rises 14 px out of `--ws-open-scale-pane` (0.98) on `--ws-spring-settle`, its parts settling in after it | 8 px down over `--ws-duration-exit` | a native `<dialog>` (`showModal()`, `close()`), the same way. A drawer slides in from its edge over `--ws-duration-grow` on `--ws-ease-grow` and back over `--ws-duration-shrink` |
109
+ | `Toast` | up out of `--ws-open-scale-toast` (0.96) on `--ws-spring-settle` | 4 px down over `--ws-duration-exit` | `data-leaving`, then remove it |
110
+ | `Tooltip` | pops from 0.9, 4 px toward its control, on `--ws-spring-pop` ("Tooltip pop-in"), after the 40 ms hover intent; at once on keyboard focus | fades off over 180 ms | CSS alone: hover, focus or `ws-tooltip--open` |
111
+ | `HoverCard` | pops from 0.9 on `--ws-spring-pop`, its rows settling 45 ms apart; `--follow` glides after the pointer on `--ws-spring-follow`, which never bounces | to `--ws-pop-scale` over `--ws-duration-exit` | `data-leaving`, then remove it |
112
+ | `Panel`, `ChatShell` | out of 0.97 from the edge it docks to, out of an 8 px blur, on `--ws-spring-panel` ("Opens / moves / docks") | back over 160 ms | `data-leaving` (or `ws-panel--leaving`), then remove it |
113
+
114
+ An element the app mounts and unmounts keeps its node until its exit has played. Wait on its own animations, never a
115
+ number of your own (under reduced motion there are none, so it goes at once):
116
+
117
+ ```js
118
+ toast.dataset.leaving = '';
119
+ Promise.allSettled(toast.getAnimations().map((a) => a.finished)).then(() => toast.remove());
120
+ ```
121
+
122
+ ### A card going full screen, or the chat changing mode: `morph()`
123
+
124
+ A thing that changes its place or size goes there as itself, never as a copy sliding in. `morph(update, { as, el })`
125
+ runs your class or state change as a view transition on Seth's curve for `as`: `full` (a chat card to full screen and
126
+ back, `--ws-duration-morph` on `--ws-ease-morph`), `grow` and `shrink` (a tile opening across its row over
127
+ `--ws-duration-grow`, closing back over the quicker `--ws-duration-shrink`, both on `--ws-ease-grow`), `shift` (the chat
128
+ between bar, docked and full, `--ws-duration-shift` on `--ws-ease-shift`). Words never scale: they ride in the frame's
129
+ corner, fade off and fade back. `full` also lifts the element into the top layer, so it covers the whole window from
130
+ inside any ancestor, moves focus in, and Escape (or its own Back button) brings it home. Why: the person sees the card
131
+ they tapped become the full screen, and finds it again in its place when it closes.
132
+
133
+ ```ts
134
+ import { morph } from '@felloinnovations/brand-kit';
135
+ morph(() => card.classList.toggle('ws-chat-card--full'), { as: 'full', el: card });
136
+ morph(() => flushSync(() => setMode('docked')), { as: 'shift', el: shellRef.current }); // React: flush inside
137
+ ```
138
+
139
+ ### A list reordering: `reorder()`
25
140
 
26
- - Only `transform`, `opacity`, colour and shadow move; height only through a layout animation, `interpolate-size` or a
27
- fixed track. No UI motion over 400 ms; `calm` only for content and charts. Exits are shorter than entrances.
28
- - Everything is interruptible: a transition picks up from where it is; no keyframe blocks input; animation never moves
29
- focus.
30
- - A stagger runs only on first paint, never on a re-filter.
31
- - Things arrive from where they belong: a panel from its edge, a menu from its corner, a chart from its middle, words
32
- rising 6 px into place. Nothing slides across the screen.
33
- - Nothing loops on its own except the working signal (typing dots, a pressed button's dot, a live face's ring, an
34
- indeterminate bar), all on `ws-loop`.
35
- - Reduced motion: keyframes do not run, presses do not scale, dialogs cross-fade, folds snap, scrolling is instant, figures
36
- show their value, a chart shows its final figure drawn.
141
+ Rows that change places glide to their new places instead of jumping: a sort, a filter, a card dropped in another
142
+ column. `reorder(update, within)` snapshots the rows before and after your update and moves each as one piece on
143
+ `--ws-spring-reorder` (Seth's "List rows reorder", no bounce); a row that arrives or leaves fades, and a card that
144
+ changes column flies above the ones it passes. It knows the kit's rows (`KanbanBoard` cards, `ListDetail` rows,
145
+ `SideList` picks); pass a selector as the third argument for others. Give each row an `id` or `data-key` so it is
146
+ followed across a re-render. Why: the person keeps their place in the list and sees where each row went. A stagger
147
+ never replays on a re-filter: rows that stay reorder in place.
37
148
 
38
- ## What moves, beyond the components
149
+ ```ts
150
+ import { reorder } from '@felloinnovations/brand-kit';
151
+ reorder(() => flushSync(() => setRows(sorted)), listRef.current);
152
+ ```
39
153
 
40
- Each component's README says how it moves. What sits between components:
154
+ ### Build-in (a dashboard on arrival)
41
155
 
42
- | What | What moves | How |
156
+ Amit, 5 Nov 2026: North's Home intro is the kit's default for every dashboard, not North's alone. A page or a section
157
+ of cards wears `.ws-build`; each card in it wears `.ws-build__card` with `--ws-i` (0, 1, 2 ... in reading order).
158
+
159
+ - **The cards** rise in (`ws-rise`: 6 px and a fade, 320 ms on `settle`), each 70 ms after the one before
160
+ (`ws-stagger-part`; North's cards are 71 ms apart, a .21 share of its 1.7 s rail). A card's start is
161
+ `--ws-build-at` (`--ws-i` x 70 ms).
162
+ - **The charts in a card** that carry their draw (`--draw` on a `MetricTile`, `SideList`, `PaceBar`, `GoalBars`,
163
+ `TickStrip`, `TickRow`, `ShareBar`, `StepLine`; `.ws-ring__value--draw`; `--build` on a `Heatmap`; `ws-grow-up`
164
+ on `TrendBars` and `GoalTubes`) add `--ws-build-at` to their own delays, so each draws as its card lands. A tile's
165
+ columns grow from the baseline one after another, its line draws left to right and its dots pop, then its foot's
166
+ figure rises in; a goal list's bars fill in order. Those two run over the card's share of `ws-duration-fill-page`
167
+ (1343 ms, North's "Metric + goal bars fill"); every other chart keeps its own draw (900 ms in a card).
168
+ - **When**: on arrival, once. Where the browser has scroll-triggered animation (a `timeline-trigger` on the card's own
169
+ `view()` timeline, `animation-trigger: play-once`), a card waits, hidden, until a tenth of it has come into view and
170
+ then plays; scrolling back never replays it. Elsewhere it all plays on first paint, so a card below the fold has
171
+ finished, its final state, by the time it is reached. It is a scroll trigger, not a scroll-driven timeline: the
172
+ build plays in time and is never scrubbed by the scroll.
173
+ - **Budget**: the first screen's build, cards and draws, stays under `ws-duration-build` (2400 ms). Number the cards
174
+ that arrive together from 0: a card below the fold plays when it is reached, so its `--ws-i` orders it only among the
175
+ cards that come into view with it (a row of tiles 0 to 3, the next row 0 to 3 again).
176
+ - **What stays still**: hover is still a tint (a tile's frame darkens, its arrow steps); a headline figure shows its
177
+ value at once (it never counts); a re-filter or a resize replays nothing. A fresh element builds in again, so an
178
+ app keeps its cards' elements (stable keys) when only their numbers change.
179
+ - **Reduced motion**: no build. Every card and chart is in its final state from the first frame.
180
+ - North's cards also arrive at 1.15 and shrink to their place; the kit leaves the scale out (a card larger than its
181
+ column pushes a phone's page sideways while it lands) and keeps North's curve, stagger and draws.
182
+
183
+ ```html
184
+ <section class="ws-build">
185
+ <div class="ws-metric-tiles"><div class="ws-metric-tiles__grid">
186
+ <button type="button" class="ws-metric-tile ws-metric-tile--draw ws-build__card" style="--ws-i: 0;" aria-label="...">...</button>
187
+ <button type="button" class="ws-metric-tile ws-metric-tile--draw ws-build__card" style="--ws-i: 1;" aria-label="...">...</button>
188
+ </div></div>
189
+ <div class="ws-side-list ws-side-list--draw ws-build__card" style="--ws-i: 2;">...</div>
190
+ <section class="ws-card ws-build__card" style="--ws-i: 3;">... <div class="ws-pace-bar ws-pace-bar--draw">...</div></section>
191
+ </section>
192
+ ```
193
+
194
+ ### Loading
195
+
196
+ Content on its way is a ghost the size of what it stands for with the shimmer passing over it: one quiet tone, the
197
+ ghost grey and a lighter pass of the same grey, never a chart hue (`Skeleton`, or `.ws-shimmer` on a block of your own:
198
+ every `--ws-loop-shimmer`, 1.8 s, on `--ws-ease-shimmer`), never a spinner. When the content lands, its details settle in top to bottom (`.ws-settle` with `--ws-i` on each, 22 ms
199
+ apart). An answer at work shows a `StatusLine`; a long load with no figure a `LoadBar`; a pressed button waiting keeps
200
+ its width and shows its working dot on `--ws-loop`. Why: the layout is already in place, so nothing jumps when the real
201
+ thing arrives. Under reduced motion the shimmer stops on its ghost and the words say what is loading.
202
+
203
+ ```html
204
+ <div class="ws-skeleton ws-skeleton--line" aria-hidden="true"></div>
205
+ <p class="ws-settle" style="--ws-i: 0;">Your calls this week</p>
206
+ ```
207
+
208
+ ### Charts drawing
209
+
210
+ A chart builds in when it arrives: its `--draw` variant (the list under Build-in) or, for `TrendLine`, on its own. A
211
+ draw is one progress: marks start at their share (mark `i` of `n` at `i / (n - 1) x 0.55` of the draw) and ease on
212
+ `--ws-ease-settle`; values written in the chart follow it. A chart draws over `--ws-duration-draw` (900 ms) in a card,
213
+ `--ws-duration-draw-chat` in the chat, and over its card's share of `--ws-duration-fill-page` in a `.ws-build`. Why: one
214
+ sweep reads as the data arriving; marks sliding in from an edge read as noise.
215
+
216
+ - **On hover** the hovered column's band slides over `--ws-duration-settle`; the rest dims to `--ws-dim`; a hovered
217
+ tick or wedge grows to `--ws-grow-scale` from its base.
218
+ - **Bars to a line** (`TrendLine`): the columns collapse into their tops on `--ws-spring-morph-chart` ("Bars to line
219
+ morph") while the line draws left to right; back, they grow down from the dots. Switch the class; the CSS does the
220
+ rest.
221
+ - **A headline figure never counts up**: it shows its value.
222
+ - **Nothing that carries data loops.**
223
+
224
+ ```html
225
+ <div class="ws-goal-bars ws-goal-bars--draw">...</div>
226
+ ```
227
+
228
+ ## Which spring, when
229
+
230
+ From `motion.springs` in `tokens/design-tokens.json`: Seth's tuned springs, each as `--ws-spring-<name>` and
231
+ `--ws-spring-<name>-duration` in CSS and `springs.<name>` in JS. Reach for the one whose label matches the move; the
232
+ components already use theirs.
233
+
234
+ | Spring | Seth's label | For |
43
235
  | --- | --- | --- |
44
- | Rows, menu rows, sidebar rows | a tint; a step darker under a press (rows never scale) | instant |
45
- | Sidebar's current row | the wash slides from the row it left | a shared layout, 200 ms |
46
- | A clicked link card or row | its navy edge pulses until the page answers | `ws-working` |
47
- | A field's error, a form's outcome | rises in with a mark before the words | `ws-arrive` |
48
- | Typing dots | breathe | `ws-loop` |
49
- | Search results, a filter's results | cross-fade | gentle |
50
- | Cards on a board | rise in, staggered | settle |
51
- | Route change inside the frame | the canvas cross-fades (fixed panels stay) | settle |
52
- | A pane closing | slides back and fades, gives its room back before the next page answers | gentle, exit curve |
53
- | A row set aside, Undo | folds away; rises back | gentle |
54
- | Bars, tubes | grow from their start; ease to a new length when the value changes | calm, staggered; settle |
55
- | Ticks, days | fill in first to last | gentle each, over `ws-sweep` |
56
- | Petals, marks | bloom from the middle | settle |
57
- | Rings | draw to their figure once; a live one follows at an even pace | calm; steady |
58
- | A figure | counts up from nought; counts on when it changes while shown | calm |
236
+ | `press` | Button press (mic, add) | a button or chip under a press (house press) |
237
+ | `follow` | Tooltip follows cursor | something trailing the pointer; never bounces (`HoverCard --follow`) |
238
+ | `pop` | Tooltip pop-in | a tip or a hover card popping in (`Tooltip`, `HoverCard`) |
239
+ | `settle` | Messages and steps settle | menus, popovers, dialogs, toasts, a message settling |
240
+ | `fold` | Sidebar sections open / close | a height opening or closing, and its chevron (`<details>`, `.ws-unfold`) |
241
+ | `indicator` | Toggle pill slide | a segmented thumb (`Segmented`) |
242
+ | `tab` | Department card underline | a tab's underline (`Tabs`) |
243
+ | `nav` | Sidebar active row slide | the sidebar's current pill (`AppShell`) |
244
+ | `highlight` | List highlight slide | a list's selected fill (`SideList`, `ListDetail`) |
245
+ | `reorder` | List rows reorder | rows moving to new places (`reorder()`) |
246
+ | `tile` | Tile grows open / closes | a heatmap square opening (`Heatmap`) |
247
+ | `mark` | Pace dot on an opened square | a small mark popping in (`Heatmap`) |
248
+ | `panel` | Opens / moves / docks (spring) | a panel or the chat opening, moving, docking (`Panel`, `ChatShell`) |
249
+ | `card` | Chart card arrives | a chart card arriving in the thread (`ChatCard`) |
250
+ | `glow`, `roll` | Focus glow; Placeholder roll | the composer's focus glow and rolling placeholder (`Composer`) |
251
+ | `morphChart` | Bars to line morph | a chart changing form (`TrendLine`) |
252
+ | `lane` | Department: lane detail opens / closes | a lane's detail opening (token only) |
253
+ | `lens` | Lens switch (chart swap) | one chart swapping for another inside an open tile (token only) |
254
+ | `swap` | Old chart out / new chart in | a board chart replaced by another (token only) |
255
+ | `flag` | Trend flag follows the pointer (spring) | a read-out following the pointer along a chart (token only) |
256
+ | `text` | Metric card text swap | a card's words swapping (token only) |
257
+ | `badge` | Nav count badge pop | a count badge popping when it changes (token only) |
258
+ | `chip` | Attention chip to card | a chip opening into its card (token only) |
259
+ | `orb` | Agent orb arriving | an agent's orb arriving (token only) |
260
+ | `default` | Anything not tuned | anything the person drives that no spring above fits |
261
+
262
+ "Token only": no kit component moves this way yet; build it on the token and report it as new.
263
+
264
+ ## Role tokens
265
+
266
+ For your own part, by role. Values are in `tokens.md`.
267
+
268
+ | Duration | For |
269
+ | --- | --- |
270
+ | `--ws-duration-instant`, `--ws-duration-exit` (120 ms) | a press going in; every exit |
271
+ | `--ws-duration-hover` (200 ms) | hover colour, tint, edge and opacity; a scrim |
272
+ | `--ws-duration-text` (250 ms) | words changing colour, small fades |
273
+ | `--ws-duration-settle` (320 ms) | details settling in, a chart's hover band |
274
+ | `--ws-duration-reveal` (350 ms) | an underline growing, a bar's ground |
275
+ | `--ws-duration-shrink` (400 ms), `--ws-duration-grow` (550 ms) | a tile closing back; a tile or drawer growing open |
276
+ | `--ws-duration-morph` (450 ms), `--ws-duration-shift` (550 ms) | a shared element in flight; layout moving (docking, columns, the sidebar folding) |
277
+ | `--ws-duration-fill` (700 ms), `--ws-duration-draw` (900 ms) | a bar filling; a chart drawing in a card, a ring filling |
278
+ | `--ws-duration-draw-chat`, `--ws-duration-fill-page`, `--ws-duration-build` | a chart in the chat; a dashboard's charts; a page's whole build, at most |
279
+
280
+ | Curve | For |
281
+ | --- | --- |
282
+ | `--ws-ease-soft` | the default: content arriving, a hover, a fold |
283
+ | `--ws-ease-settle` | things that land and rest: a mark, a bar filling, a card building in |
284
+ | `--ws-ease-grow`, `--ws-ease-shift`, `--ws-ease-morph` | a shape changing size; layout moving; one element in flight |
285
+ | `--ws-ease-exit` | everything leaving |
286
+ | `--ws-ease-steady` | linear: a draw's overall progress, a live ring keeping pace |
287
+ | `--ws-ease-sweep`, `--ws-ease-commit` | a chart sweeping in the chat; a decisive one-shot (sending, a check mark) |
288
+ | `--ws-ease-shimmer`, `--ws-ease-loop`, `--ws-ease-ambient` | a loading sweep; every loop; the one slow brand sheen |
289
+ | `--ws-ease-pop`, `--ws-ease-lift` | overshoot, for marks under 24 px only |
290
+
291
+ Staggers: `--ws-stagger` (30 ms, a list's rows on first paint), `--ws-stagger-detail` (22 ms, details in an opening
292
+ part, `.ws-settle`), `--ws-stagger-row` (45 ms, a hover card's rows), `--ws-stagger-part` (70 ms, cards building in).
293
+ Loops: `--ws-loop` (the working dots), `--ws-loop-status`, `--ws-loop-shimmer`, `--ws-loop-slow`, `--ws-loop-ambient`
294
+ (the one ambient sheen, never on data). Distances: `--ws-nudge` (4 px), `--ws-rise` (6 px), `--ws-drop` (12 px);
295
+ `--ws-blur-arrive` (3 px) and `--ws-blur-panel` (8 px) on arrival.
296
+
297
+ ## Rules
298
+
299
+ - **What may move**: transform, `scale`, `translate`, opacity, colour, a blur up to 8 px on arrival, `clip-path`, and a
300
+ shimmer's `background-position`. Size, padding and grid tracks move only in a fold, a dock, the sidebar folding or a
301
+ `morph()`; never on hover.
302
+ - **From where it belongs**: a tip from the edge nearest its mark, a menu from its corner, the chat from its mode's
303
+ edge, a tile out of its slot, a card out of its place in the thread and back to it.
304
+ - **Two phases**: the frame lands, then its details settle top to bottom (`.ws-settle`, `--ws-i` on each).
305
+ - **Interruptible**: a change picks up from where it is; animation never moves focus, and none blocks input except a
306
+ `morph()` for the length of its own move (the browser's rule for a view transition).
307
+ - **Overshoot** only on marks under 24 px and indicators, never a card, a panel, a field or words.
308
+ - **A stagger runs when content arrives** (first paint, an open, a new answer), never on a re-filter.
309
+ - **Never moves**: content below a chart while its card changes size, a field as it takes focus (the ring appears,
310
+ nothing else), anything during a resize drag, a scroll reset or a theme change (every surface turns at once).
311
+
312
+ ## Reduced motion, and browsers without a feature
313
+
314
+ **Reduced motion is still: the final state, at once.** Under `prefers-reduced-motion: reduce` the kit's net makes every
315
+ transition and animation on a kit element instant: presses do not scale, indicators land, folds snap, menus and dialogs
316
+ appear and go, a dashboard shows its end, a chart its final drawing, a shimmer its still ghost (with a word: "Loading
317
+ your calls"), the working dot is still and its words say it. `morph()` and `reorder()` run the update at once (`full`
318
+ still lifts the card). Your own motion goes inside `@media (prefers-reduced-motion: no-preference)` so it is still too;
319
+ in React, `<MotionConfig reducedMotion="user">` turns the springs off.
320
+
321
+ **A browser without a feature shows the change at once**, never half-moved: without `linear()` the spring transitions
322
+ are dropped; without anchor positioning an indicator jumps to the choice; without `interpolate-size` or
323
+ `::details-content` a fold opens at once; without `@starting-style` a menu or dialog simply appears; without view
324
+ transitions `morph()` and `reorder()` just run the update; without scroll-triggered animation a `.ws-build` plays on
325
+ first paint, and a chart below the fold is whole when it is reached.
326
+
327
+ ## See it
328
+
329
+ The `Motion` card (`components/Motion/preview.html`, hosted at
330
+ `https://brand-kit-site-production.up.railway.app/latest/components/Motion/preview.html`):
331
+
332
+ - **Try it**, the playground: a product screen built only from kit components, with a numbered hint at each move
333
+ (hover a card, press a button, switch Bars / Line, open the menu, open the chart full screen, fold a section, save
334
+ for a toast, open the drawer, move the chat, sort the list, replay the arrival) and a Slow motion switch that runs
335
+ everything four times slower.
336
+ - **Reference for developers**: 206 behaviours by Seth's own label, each with North's values, the kit's token, class
337
+ or helper, a live demo and how close the kit is (exact, close, JS helper, not yet).
338
+
339
+ Compare what you built against it, side by side. In the kit's repo, `node scripts/check-geometry.mjs --only <Name>
340
+ --hover` shoots each control at rest, hovered and focused, and flags a hover that lifts and anything still moving under
341
+ reduced motion; add `--motion` to run the same pass with motion on, which catches a lift that only plays then.
@@ -4,38 +4,61 @@ The audience skews older and mobile-heavy. These are floors, part of the definit
4
4
 
5
5
  ## Floors
6
6
 
7
- - **Contrast**: 4.5:1 for words under 24 px (3:1 at 24 px or bold 19 px and up), 3:1 for every border, focus ring, icon or
8
- mark that carries meaning. Measure on the cream (#FEFBF9) and on the sunk surface; the pairs are in Colour.
9
- - **Targets**: WCAG 2.2 (2.5.8, AA) asks 24 by 24 px or the spacing to match. The team's floors are higher: 40 px for a
10
- boxed control on a touch screen, 44 px for every act on a public page (`KitButton` large is 45), 24 px
11
- tall for words that act. A small face that acts gets 4 px of room round it.
7
+ - **Contrast**: 4.5:1 for words under 24 px (3:1 at 24 px or 18.66 px bold and up), 3:1 for every border, focus ring,
8
+ icon or mark that carries meaning. Every word token is computed on all eight grounds (cream, white, plate, tray,
9
+ raised, shell, press, well) in light, night and the navy ground; the tables are in tokens.md and Colour. A word in a
10
+ tone uses the tone's word token, never the mark's tone (D2).
11
+ - **Focus**: every element that takes keyboard focus shows a 2 px navy ring 2 px outside it on `:focus-visible`
12
+ (`ws-focus-color`, `ws-focus-width`, `ws-focus-offset`; `shadow-focus-ring` is the same ring as a shadow). Inside a
13
+ dense row, a well, a list, a segmented track or a clipped container the same ring is drawn inside (`ws-focus-inset`).
14
+ Never `outline: none` without a visible replacement; a tint alone is not focus. The 2 px gap keeps the ring off a white
15
+ field. It is 12.3:1 on the cream and at least 10.2:1 on any light ground; in night at least 12.2:1 (D8).
16
+ - **Targets**: WCAG 2.2 (2.5.8, AA) asks 24 by 24 px or the spacing to match. The team's floors are higher, at every
17
+ pointer for words and on touch for boxes: 40 px for a boxed control on a touch screen (a button, a field, an icon
18
+ button through its hit area, a segmented item, a tab, a menu item, a date cell); 24 px tall for words that act; 44 px
19
+ for every act on a public page (`ws-touch-public`; `KitButton` large is 45). The kit's coarse-pointer block sets these;
20
+ a component's own min-height stays at or above them. A small face that acts gets 4 px of room round it.
12
21
  - **Fields**: a white ground (`ws-field`) on the cream, a visible edge and a label above; a field that blends into the
13
- page reads as no field. `autocomplete` and the right `type` on every field about the person (1.3.5).
14
- - **Keyboard**: everything reachable and operable; a visible focus ring (`shadow-focus-ring`, 3 px salmon at
15
- 20%, with the mid-blue field border); arrow keys inside a tab row, a segmented switch, a menu, a radio group; Home and End to the ends; Escape closes a
16
- dialog, a menu, a panel and returns focus to what opened it; Enter saves an inline edit, Escape reverts.
17
- - **Native first**: `<button>`, `<a>`, `<input type="checkbox">`, `<fieldset>` with a `legend`, `<details>` for a fold, a
18
- native `<dialog>`. Roving focus and arrow keys come from Radix where native cannot.
22
+ page reads as no field. `autocomplete` and the right `type` on every field about the person (1.3.5). A checkbox's edge
23
+ at rest reaches 3:1.
24
+ - **Keyboard**: everything reachable and operable; arrow keys inside a tab row, a segmented switch, a menu, a radio
25
+ group, a list with a detail; Home and End to the ends; Escape closes a dialog, a drawer, a menu, a panel and returns
26
+ focus to what opened it; Enter saves an inline edit, Escape reverts.
27
+ - **Native first**: `<button>`, `<a>`, `<input type="checkbox">`, `<input type="range">`, `<fieldset>` with a `legend`,
28
+ `<details>` for a fold, a native `<dialog>`, the `popover` attribute for a menu in the top layer. Roving focus and
29
+ arrow keys come from Radix where native cannot. A sidebar's rows are real links with `aria-current="page"`.
19
30
  - **Names**: every icon button has a label (read out and its tooltip); every card is a region named by its title; a chart is
20
- a `figure` whose label says the answer and the numbers; a figure that counts up is read at its value at once.
31
+ a `figure` whose label says the answer and the numbers; a tick strip is hidden and its figure said in words; a figure
32
+ is read at its value.
21
33
  - **Errors**: a message, wired with `aria-describedby` and `aria-invalid`; never a colour change alone. A pending control says
22
- `aria-busy`; a toggle says `aria-pressed`; the current tab `aria-selected`; the current page `aria-current`.
23
- - **Reduced motion**: every keyframe is `motion-safe`; the working signal is still and its words say it (the rest is in
24
- Motion).
34
+ `aria-busy` and stays focusable (`aria-disabled`); a toggle says `aria-pressed`; the current tab `aria-selected`; the
35
+ current page `aria-current`; an open row `aria-expanded`.
36
+ - **Reduced motion**: under `prefers-reduced-motion: reduce` everything is still (D7) and every state is still
37
+ reachable; the working signal is still and its words say it. How the kit does it, and what each thing looks like, is
38
+ in Motion.
25
39
  - **Zoom and reflow**: text at 200% (1.4.4) and the page at 320 px wide (1.4.10, the same as 400% zoom): columns stack, the
26
40
  panel is the screen, nothing scrolls sideways, nothing is clipped, and every region holding more than it shows scrolls.
27
41
  A product drawn at a UI zoom divides viewport heights back by it.
28
42
  - **WCAG 2.2 additions**: a sticky header, act or banner never covers the focused control (2.4.11); anything dragged (a
29
- sheet, a card on a board) also works by a press (2.5.7); sign-in allows paste and password managers, and a code can be
30
- pasted (3.3.8); nothing asked twice in one flow (3.3.7); help sits in the same place on every page (3.2.6).
31
- - **No hover-only content**: what a hover shows, touch and keyboard show too (1.4.13).
32
- - **Colour independence**: every state has a word or a mark; success and danger differ in lightness (teal #09787F and brick
33
- #B35040), never red and green by hue alone; a falling number is mid blue.
34
- - **Reading order** is the DOM order is the phone's order: a board's columns are stacked in the order the first column reads.
43
+ sheet, a card on a board, a slider's thumb) also works by a press or the keys (2.5.7); sign-in allows paste and password
44
+ managers, and a code can be pasted (3.3.8); nothing asked twice in one flow (3.3.7); help sits in the same place on
45
+ every page (3.2.6).
46
+ - **No hover-only content**: what a hover shows (a row's acts, a close, a cell's full words in a tooltip, a hover card's
47
+ reading) touch and keyboard show too, on focus and on a tap (1.4.13). A tip stays while the pointer moves onto it and
48
+ closes on Escape.
49
+ - **Colour independence**: every state has a word or a mark; success and danger differ in lightness, never red and green
50
+ by hue alone; a falling number is mid blue; a rating says its band in words ("Strong", "Needs work").
51
+ - **Reading order** is the DOM order is the phone's order: a board's columns are stacked in the order the first column
52
+ reads; a list that goes above its detail on a phone comes first in the markup.
53
+ - **Dark**: every pair above holds in dark. In a product the theme is the person's choice (`ThemeSwitch`) or their
54
+ system's; a page drawn dark for everyone (an event page on the navy ground) passes the same pairs. Switching it moves
55
+ nothing.
35
56
  - **Language**: plain words, sentence case, no abbreviations a person outside the trade would not know.
36
57
 
37
58
  ## Checks
38
59
 
39
- Automated (axe or the Storybook a11y addon) catch the markup and contrast subset; the audit crawl (every page, each
40
- role, desktop and phone) catches clipping, sideways scroll, fields with no ground and small targets; a keyboard walk, a
41
- 200% zoom, a screen reader pass (VoiceOver on a phone) and a reduced-motion run are done by hand on every new screen.
60
+ Automated (axe or the Storybook a11y addon) catch the markup and contrast subset; the geometry check catches small
61
+ targets, focus that looks like rest, clipping and text off its line (`node scripts/check-geometry.mjs --hover`, light and
62
+ dark); the audit crawl (every page, each role, desktop and phone) catches sideways scroll, fields with no ground and
63
+ pages that cannot scroll. A keyboard walk, a 200% zoom, a screen reader pass (VoiceOver on a phone) and a reduced-motion
64
+ run are done by hand on every new screen.
@@ -7,19 +7,23 @@ references, never copies.
7
7
 
8
8
  Only in its chat (one chat per assistant; an umbrella assistant may sit over several). No in-page assistant, no mission panel, no "ask to change" box
9
9
  on a page. A page's one link to the agent is "Ask about this", which opens the chat with the thing attached ("About: Jordan
10
- Lee"). Voice goes through the one Talk button, which carries the assistant's mark; when a product's own call takes the
10
+ Lee"); a drawer may carry a compact ask field that asks the same chat. The chat sits in its shell (`ChatShell`): a bar
11
+ over a page, docked beside it (the page steps aside, never covered), floating, or full screen; it moves between them as
12
+ itself. Voice goes through the one Talk button, which carries the assistant's mark; when a product's own call takes the
11
13
  microphone, the assistant steps aside and comes back after.
12
14
 
13
15
  ## The turn
14
16
 
15
- The agent's words are plain text, 15/24, no bubble, no avatar beside every line (the face is in the header). The person's
16
- words sit in a sunk bubble with 12 px corners and navy text. A reply is words plus at most one card, never both saying the
17
+ The agent's words are plain text, no bubble, no avatar beside every line (the face is in the header). The person's words
18
+ sit in a bubble with navy text (`ChatTurn` has the sizes). Starters sit under the composer as `SuggestionChip`s; one long
19
+ conversation is marked by topic (`TopicRail`), never split into threads the person did not ask for. A reply is words plus at most one card, never both saying the
17
20
  same thing. An act is a one-line receipt ("Drafted the opener for Nellie"), not a paragraph. A question is not echoed back.
18
21
 
19
22
  ## Streaming, working and cancelling
20
23
 
21
- A reply arrives as it is written; the working line's typing dots breathe on the one beat; a long job shows its steps as a
22
- `Stepper` in a card with Stop in its band. Stop is always one press away and says what was kept. The person can type the next
24
+ A reply arrives as it is written; while it works, a status line (`StatusLine`) says who is working, what it is doing and
25
+ the step, and the typing dots breathe on the one beat; a long job shows its steps as a `Stepper` in a card with Stop in its
26
+ band. Under reduced motion the answer shows whole and the status line is still. Stop is always one press away and says what was kept. The person can type the next
23
27
  message while a reply streams.
24
28
 
25
29
  ## Cards from an agent
@@ -27,7 +31,8 @@ message while a reply streams.
27
31
  A card is a reference with at most one act: a kind in its head ("Suggestion", "Task", "Question"), a title that says the
28
32
  thing, one sentence, facts on a plate, the band with the app's door on the left and the buttons on the right (secondary then
29
33
  the one navy). A rich card (a chart, a long list, a comparison) shows as one line in the chat and whole in the panel beside
30
- it. Asks and pick lists stay in the chat. Taps answer at once (the button shows its pending state).
34
+ it. Asks and pick lists stay in the chat. Taps answer at once (the button shows its pending state). A thread's first
35
+ open follows Page recipes, 22: the app's face and one line, one example on the team's own numbers, the app's tiles.
31
36
 
32
37
  ## What waits on you
33
38
 
@@ -20,7 +20,7 @@ system does not have.
20
20
  | --- | --- | --- |
21
21
  | An operational page or panel (most of the product) | little | the right chart, a sharp title, one well-placed act, cards arriving in order |
22
22
  | A chat card | some | a drawing on the dots that says the answer at a glance; a plate that holds exactly the facts |
23
- | A hero (Team, Progress) | more | a 40 px line, a still faint wash (`ws-cool-glow`, `ws-team-glow`), a vertical-tube chart |
23
+ | A hero (Team, Progress, a report's score) | more | a 40 px line or the 96 px score, a still faint wash (`ws-cool-glow`, `ws-team-glow`), a vertical-tube chart |
24
24
  | An entry page or a welcome step | more | the three faces glancing round, sample cards rising in beside |
25
25
  | A guide or a walkthrough | more | a drawn board, the assistant talking it through |
26
26
  | A report or a launch moment | the most | an expressive composition, imagery, a sequence of cards that tells one story |