@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
@@ -0,0 +1,31 @@
1
+ /* ---- Switch: North's anatomy (0.5.0, D1; style1.css:2049): a filled track, a round thumb with a soft shade, navy when
2
+ on. The off track is North's warm grey taken to the 3:1 a control asks (#7F7F7F), so off reads as a control and not as
3
+ nothing; the thumb's side and the label say the state too. 36 by 20 with a 16 thumb; --sm is North's 28 by 16 with a
4
+ 12 thumb, for a dense list. The track carries no border, so the thumb sits 2 px in on every side (the 0.4.0 one sat
5
+ 2 / 1). Track over the hover beat, thumb over the settle beat on the grow curve. ---- */
6
+ .ws-switch { --ws-switch-w: var(--ws-control-h-md); --ws-switch-h: var(--ws-icon-lg); --ws-switch-thumb: var(--ws-icon); --ws-switch-line: calc(var(--space-md) + var(--space-xxs)); position: relative; display: inline-flex; align-items: flex-start; gap: var(--space-xs-plus); width: fit-content; max-width: 100%; padding: var(--space-xxs) 0; cursor: pointer; }
7
+ .ws-switch input { position: absolute; width: var(--ws-line); height: var(--ws-line); margin: 0; opacity: 0; }
8
+ .ws-switch__track { position: relative; flex-shrink: 0; width: var(--ws-switch-w); height: var(--ws-switch-h); margin-top: calc((var(--ws-switch-line) - var(--ws-switch-h)) / 2); border: 0; border-radius: var(--radius-full); background: var(--ws-control-off); }
9
+ .ws-switch__thumb { position: absolute; top: calc((var(--ws-switch-h) - var(--ws-switch-thumb)) / 2); left: calc((var(--ws-switch-h) - var(--ws-switch-thumb)) / 2); width: var(--ws-switch-thumb); height: var(--ws-switch-thumb); border-radius: var(--radius-full); background: var(--color-surface); box-shadow: 0 var(--ws-line) var(--ws-ring) color-mix(in srgb, var(--ws-shade) 18%, transparent); }
10
+ .ws-switch input:checked + .ws-switch__track { background: var(--color-text-heading); }
11
+ .ws-switch input:checked + .ws-switch__track .ws-switch__thumb { transform: translateX(calc(var(--ws-switch-w) - var(--ws-switch-h))); background: var(--ws-on-act); }
12
+ .ws-switch input:focus-visible + .ws-switch__track { outline: var(--ws-focus-width) solid var(--ws-focus-color); outline-offset: var(--ws-focus-offset); }
13
+ /* Hover, on a mouse only, as Checkbox and Radio answer it: the off track a step toward the navy, the on track North's
14
+ brighter act (--ws-act-hover). A colour change, nothing moves. */
15
+ @media (hover: hover) {
16
+ .ws-switch:not(.ws-switch--disabled):hover input:not(:checked, :disabled) + .ws-switch__track { background-color: color-mix(in srgb, var(--ws-control-off) 85%, var(--color-text-heading)); }
17
+ .ws-switch:not(.ws-switch--disabled):hover input:checked:not(:disabled) + .ws-switch__track { background-color: var(--ws-act-hover); }
18
+ }
19
+ @media (prefers-reduced-motion: no-preference) {
20
+ .ws-switch__track { transition: background-color var(--ws-duration-hover) var(--ws-ease-soft); }
21
+ .ws-switch__thumb { transition: transform var(--ws-duration-settle) var(--ws-ease-grow), background-color var(--ws-duration-hover) var(--ws-ease-soft); }
22
+ }
23
+ .ws-switch--sm { --ws-switch-w: var(--ws-control-h-sm); --ws-switch-h: var(--space-md); --ws-switch-thumb: var(--ws-icon-sm); }
24
+ .ws-switch__words { display: flex; min-width: 0; flex-direction: column; gap: var(--space-3xs); }
25
+ .ws-switch__label { font-size: var(--ws-text-body); line-height: var(--ws-switch-line); color: var(--color-text-heading); font-weight: 500; }
26
+ .ws-switch--disabled, .ws-switch:has(input:disabled) { opacity: 0.5; cursor: not-allowed; }
27
+ /* Saving, then saved: a word beside the label, never a spinner on the thumb. */
28
+ .ws-switch__status { display: inline-flex; align-items: center; gap: var(--space-xxs); font-size: var(--ws-text-dense); line-height: var(--space-md); }
29
+ .ws-switch__saved { color: var(--ws-word-positive); }
30
+ .ws-switch__saving { color: var(--color-text-interactive); }
31
+ @media (pointer: coarse) { .ws-switch { padding-block: calc((var(--ws-touch) - var(--ws-switch-line)) / 2); } }
@@ -1,106 +1,177 @@
1
- Rows of records inside one card, read down its columns: a header of muted labels, dense rows, a sticky first column,
2
- selection, row acts and paging.
1
+ Rows of records inside one card, read down its columns: a head of muted labels, 40 px rows, a first column that stays
2
+ while the rest scroll, numbers in fixed right-aligned columns, totals in the foot, columns that fold away by priority and
3
+ a phone fold. This is the whole wide-table pattern; build every records table from it.
3
4
 
4
5
  ## Use it when
5
6
 
6
7
  - The question is about columns (comparing scores, stages or dates across many people or records), not about reading
7
8
  each item as a thing on its own.
8
- - A list is wide enough that a plain list of rows (`.ws-row`) would repeat the same words in every row's layout; a table says each
9
- column's meaning once, in its header.
10
- - Rows need to be selected together for a bulk act, sorted by a column, or paged through a long collection.
9
+ - A list is wide enough that a plain list of rows (`.ws-row`) would repeat the same words in every row's layout; a table
10
+ says each column's meaning once, in its head.
11
+ - Rows need to be selected together for a bulk act, sorted by a column, totalled, or paged through.
11
12
 
12
13
  ## Not for
13
14
 
14
15
  - A list read as individual things (a person, a lead as a whole, a chat card): use rows in a `Card`
15
16
  (`08-choosing-components.md`, "Rows vs table").
17
+ - A grid of yes-or-no answers (a question by a source): use `Matrix`.
18
+ - A list of checks with a score each: use `CheckRow`.
16
19
  - Ranking people by one number with the rank itself the point: use `Leaderboard`.
17
20
  - A history of events: use `Timeline`.
18
21
 
19
22
  ## Anatomy
20
23
 
21
- - One card (`ws-card`), the table inside it; a wide table scrolls inside the card with the first column sticky, never
22
- the page.
23
- - Header row: 32 px (`--ws-control-h`), 12 px medium muted labels (`--color-text-muted`); a sortable header is itself a
24
- button with its label and a 12 px chevron, never a bare clickable cell.
25
- - Body rows: 40 px (`--ws-row-h-dense`), a hairline between rows (`--ws-edge-slot`).
26
- - First column: sticky while the table scrolls sideways, 14 px medium navy (`--color-text-heading`), so the row's name
27
- is always visible.
28
- - Numbers: right-aligned, tabular numerals; a change lives in its own column as a `ChangeChip`.
29
- - A checkbox column: a native checkbox skinned navy when checked, the same shape as the standalone `Checkbox`.
30
- - Row acts: small ghost `Button`s at the right, always present in the DOM (not inserted on hover), so they are reachable
31
- by keyboard and on touch where hover never shows; a hover state that reveals them visually is a nicety layered on top,
32
- never the only way to reach them.
33
- - Row states: hover tints `--ws-surface-sunk`; a selected row keeps the same tint and adds a 2 px navy inset on its
34
- left edge (`--ws-focus-inset`'s look, used here as a selection mark rather than a focus ring).
35
- - Empty: the same card, a sentence and the act that clears it, no separate empty component.
36
- - Loading: skeleton bars in place of cell content, the header shown at once.
37
- - Pagination sits in the card's foot (`Pagination`), below the rows.
24
+ - One card (`ws-card ws-table`), the table inside a scroller (`.ws-table__scroll`, always there: it holds the columns
25
+ and takes the card's corners). A wide table scrolls inside its card, never the page.
26
+ - Every cell: 8 px above and below (`--space-xs`), 12 at the sides (`--space-sm`), one line (`white-space: nowrap`, so
27
+ a squeezed table scrolls instead of breaking every cell to a word a line). A cell that may wrap takes `ws-table__wrap`
28
+ (at least 200 wide).
29
+ - The outer cells sit on the card's 20 px edge (`--ws-card-inset`): the first cell's left and the last cell's right, so
30
+ the table lines up with the card's head, band and pagination.
31
+ - Head: rows at least 40 (`--ws-row-h-dense`), 13 / 18 medium muted labels (`--ws-text-control`, `--color-text-muted`),
32
+ a 0.5 px line under (`--ws-divider`). It sticks to the top of the scroller once the scroller has a height
33
+ (`--ws-table-max-h`). A sortable head is a real button (`__sort`) with a 12 px chevron; the sorted column's label
34
+ turns navy and its `th` carries `aria-sort`. An unsorted column's chevron is dimmed to 0.3 (`--ws-dim`) until it is
35
+ hovered or focused, so only the sorted column reads as the sort.
36
+ - Body: rows at least 40, a 0.5 px line between them; 14 / 20 body words; the name column (`__name`, a `th scope="row"`)
37
+ 14 / 20 medium navy.
38
+ - First column: it stays while the rest slide under it (with the check column, when there is one). Once the rows have
39
+ moved, an 8 px shade falls from its edge over them; where the browser has no scroll-driven animations a 0.5 px line
40
+ stands in for the shade, always.
41
+ - The far edge: while columns are hidden past it, the last 24 px of the rows fade out; the fade lifts when the table
42
+ reaches its end. A table that fits shows neither cue.
43
+ - Numbers: `__num`, on the `th` and on every cell of the column, right-aligned, tabular, in a fixed column 64 wide
44
+ (`--wide`: 96, for money). A wider number widens its column; it never truncates.
45
+ - A second line in a cell (`__sub`): 13 / 16 muted, under a name or a figure.
46
+ - Check column (`__check`): a fixed 56 px column (20 + a 24 px target + 12), the skinned `Checkbox` (`ws-check`) on a
47
+ 24 px target, 40 on touch through a hit area.
48
+ - Row acts (`__acts`): small ghost `Button`s at the right, always in the DOM, 4 apart.
49
+ - Totals (`tfoot`): the body's rhythm, a 0.5 px line above, 600 navy; they stay at the foot of a scroller with a height.
50
+ - Pagination sits in the card's foot (`Pagination`), below the scroller.
38
51
 
39
52
  ## Variants and sizes
40
53
 
41
54
  | Part | Value |
42
55
  | --- | --- |
43
- | Header height | 32 px |
44
- | Row height | 40 px (`--ws-row-h-dense`) |
45
- | Row with an avatar | 48 px (`--ws-row-h`), as in `Leaderboard` |
46
- | Checkbox column | 36 px wide, left-aligned |
56
+ | Head and body rows | 40 at least, 8 above and below |
57
+ | Outer cells | 20 from the card's edge |
58
+ | Number column | 64 (`--ws-table-num-w`), 96 with `__num--wide` |
59
+ | Check column | 56 (`--ws-table-check-w`) |
60
+ | Sticky shade | 8 px, navy 8 % (`--ws-table-shade`); in dark the card edge (`--ws-edge-card`) fading out, since a dark shade vanishes on the dark ground |
61
+ | Far-edge fade | 24 px |
62
+ | Low-priority columns | fold under a 48rem table |
63
+ | Row acts to More | under a 30rem table |
64
+ | Stuck name, narrow | wraps at 40 % of a table under 30rem |
47
65
 
48
66
  ## States
49
67
 
50
68
  - **Default**: as above.
51
- - **Hover**: `--ws-surface-sunk` across the row, including the sticky first column.
52
- - **Selected**: `--ws-surface-sunk` plus the 2 px navy inset on the first cell's left edge; several selected rows show a
53
- count chip and bulk acts in the card's foot (`10-patterns.md`, "Selection and bulk acts").
54
- - **Sorted column**: the header's chevron points the sort direction; only one column sorts at a time.
55
- - **Empty, no matches**: the same card, "Nobody matches your filter", the act that clears it.
56
- - **Empty, first use**: the same card, a sentence inviting the first record and the act that adds one, in the band.
57
- - **Loading**: skeleton bars sized to each column's typical content, the header already in place.
58
- - **Narrow**: columns beyond the first fold behind a "More" act per row (an `IconButton` opening a `Menu` or the row's
59
- own detail) rather than letting the table scroll off-screen on a phone.
60
- - **Touch**: row acts and the checkbox meet the 40 px floor; the sticky column still sticks under a touch scroll.
69
+ - **Hover**: North's faint navy wash (`--ws-hover-faint`) across the row, sticky cells included; nothing moves.
70
+ - **Selected**: `aria-selected="true"` (or `__row--selected`): the sunk cream (`--ws-surface-sunk`) and a 2 px navy mark
71
+ on the row's left edge, so the state is never colour alone. Where the hairline stands in for the shade, the selected row's
72
+ stuck name carries both. Several selected rows show a count and the bulk acts in
73
+ the card's foot (`10-patterns.md`, "Selection and bulk acts").
74
+ - **Sorted**: the column's label navy, its chevron at full strength pointing the way (down for descending); the other
75
+ sortable heads keep a dimmed chevron; one column sorts at a time.
76
+ - **Scrolled**: the shade on the first column's edge; the fade at the far edge until the end.
77
+ - **Narrow, 48rem**: columns marked `__low` fold away and each row's fold line (`__fold`, under the name, 13 / 16 muted)
78
+ shows what they held.
79
+ - **Narrow, 30rem**: the row acts fold into one More act (`__more`, a small `IconButton` opening the row's `Menu`), and
80
+ a name that would push the rest off the card wraps at 40 % of the table (`min-width: 40cqi`), so on a 320 phone the
81
+ stuck columns leave the sliding ones over 100 px, not a sliver. A name that fits keeps its one line.
82
+ - **Empty, no matches**: the same card, a sentence and the act that clears the filter (`__empty`).
83
+ - **Empty, first use**: the same card, a sentence inviting the first record and the act that adds one.
84
+ - **Loading**: a ghost bar per cell under the shimmer (`__placeholder ws-shimmer`), the head shown at once;
85
+ still under reduced motion.
86
+ - **Touch**: the check target, the More act and the row acts reach 40, the sort button 24.
61
87
 
62
88
  ## Behaviour
63
89
 
64
- - Keyboard: a sortable header is a real `<button>`; row acts are real buttons in the DOM at all times, reachable by Tab
65
- without a hover; a checkbox is a native input.
66
- - Pointer: a row tints on hover; clicking a sort header re-sorts; row acts respond to a plain click.
67
- - Touch: row acts stay visible rather than depending on a hover that touch never fires.
68
- - Motion: rows cross-fade when a sort or filter changes the set, never a re-stagger (`10-patterns.md`, "Search, filters
69
- and sorting").
90
+ - Keyboard: the scroller is a focusable region (`tabindex="0"`, `role="region"` and a label), so arrow keys scroll it;
91
+ its ring goes round the card, 2 px out (inside, the stuck cells would cover it). A sort head is a real button; row
92
+ acts are real buttons, reachable without a hover; a checkbox is a native input.
93
+ - Pointer: a row tints on hover; a sort head re-sorts; row acts respond to a plain click.
94
+ - Motion: the hover wash over 200 ms (`--ws-duration-hover`); the edge cues follow the scroll itself, so they are the
95
+ same with reduced motion. Rows cross-fade when a sort or a filter changes the set, never a re-stagger.
70
96
 
71
97
  ## Content
72
98
 
73
99
  - Column labels are short nouns, sentence case, never a question.
74
- - Numbers are plain, tabular, with their unit in the header only, not repeated in every cell.
100
+ - A number's unit lives in its head ("Price", "Score"), not in every cell.
101
+ - Totals say what they total ("Total, 5 leads").
75
102
  - No em dashes.
76
103
 
77
104
  ## Props
78
105
 
79
106
  | Name | Type | Meaning |
80
107
  | --- | --- | --- |
81
- | `columns` | `{ key, label, align?, sortable? }[]` | Column definitions, in order |
108
+ | `columns` | `{ key, label, align?, sortable?, priority?, wide? }[]` | Column definitions, in order; `priority: 'low'` folds under 48rem |
82
109
  | `rows` | `Record<string, ReactNode>[]` | The data, one object per row |
110
+ | `totals` | `Record<string, ReactNode>` | The foot row, when the columns add up |
83
111
  | `selected` | `string[]` | Selected row ids |
84
112
  | `onSort`, `onSelect` | functions | Sort and selection callbacks |
85
113
  | `rowActions` | `(row) => ReactNode` | A row's small ghost acts |
114
+ | `maxHeight` | `string` | Sets `--ws-table-max-h`, so the head and totals stay |
86
115
  | `pagination` | `PaginationProps` | Rendered in the card's foot |
87
116
 
88
117
  ## Rules
89
118
 
90
- - **A wide table scrolls inside its card, the first column sticky, never the page** (`08-choosing-components.md`,
91
- "Rows vs table").
92
- - **Row acts are always in the DOM**: hover-to-reveal is cosmetic only, following the system's rule that nothing
93
- essential depends on a pointer that touch and the keyboard do not have.
94
- - **A selected row never changes colour alone**: the navy inset mark travels with the tint, matching the "never a state
95
- by colour alone" rule.
96
- - **Source**: Intentional addition, decided from the system (26 Oct 2026): records with real columns to compare need a
97
- grid the first product's own chat-first cards never required (its lists read as rows of things, not columns of
98
- facts). Derived from the dense row height, the slot-edge hairline, the sunk hover and selection tint used everywhere,
99
- and `Checkbox`'s navy-when-chosen rule.
119
+ - **A wide table scrolls inside its card, the first column staying, never the page** (`08-choosing-components.md`,
120
+ "Rows vs table"), and it always shows that it scrolls: the shade and the fade.
121
+ - **One content edge per card**: the first and last cells sit on the card's 20 px edge, like its head (K8).
122
+ - **Numbers line up through fixed numeric columns** (North, A4), right-aligned, tabular, the `th` included.
123
+ - **Every row is one line**: a squeezed table scrolls; only a cell marked `__wrap` breaks, and under 30rem the stuck
124
+ name, which would otherwise leave no room for the columns sliding under it.
125
+ - **A selected row never changes colour alone**: the navy mark travels with the tint.
126
+ - **Row acts are always in the DOM**: hover-to-reveal is cosmetic only.
127
+ - **No clip on the card**: the scroller is the child that rounds; a menu opened from a row opens in the top layer
128
+ (K9), never inside the scroller.
100
129
 
101
130
  ## Source
102
131
 
103
- **Derived from**: `--ws-row-h-dense` (40 px, a plain list row) and `--ws-row-h` (48 px, a list row with an avatar),
104
- `--ws-edge-slot` for the row hairline, `--ws-surface-sunk`/`--ws-focus-inset` for hover and selection, `Checkbox`'s
105
- navy-when-chosen rule, and `Pagination` for the foot. **Precedent**: an intentional addition decided from the system,
106
- 26 Oct 2026; no card in the first product renders a column-oriented table.
132
+ **Derived from**: the dense row height, the 0.5 px divider (`--ws-divider`, D5), North's hover wash and its fixed
133
+ numeric columns (style1.css 1168, 1001), the K8 audit of Aryan's Revenue OS mockup (sticky head missing, hidden
134
+ columns with no cue, cells 12 in against the card's 20, no vertical padding, no totals), and `Checkbox`.
135
+ **Precedent**: an intentional addition decided from the system, 26 Oct 2026; completed as the wide-table pattern in
136
+ 0.5.0 (4 Nov 2026).
137
+
138
+ ## Markup
139
+
140
+ ```html
141
+ <section class="ws-card ws-table" aria-label="Leads">
142
+ <div class="ws-table__scroll" role="region" aria-label="Leads, scrolls sideways" tabindex="0">
143
+ <table>
144
+ <thead>
145
+ <tr>
146
+ <th scope="col" class="ws-table__check"><label class="ws-check"><input type="checkbox" aria-label="Select all leads"><span class="ws-check__box" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span></label></th>
147
+ <th scope="col" class="ws-table__name">Name</th>
148
+ <th scope="col" class="ws-table__num" aria-sort="descending"><button type="button" class="ws-table__sort">Score <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg></button></th>
149
+ <th scope="col" class="ws-table__num ws-table__num--wide">Price</th>
150
+ <th scope="col" class="ws-table__low">Source</th>
151
+ <th scope="col" class="ws-table__acts"><span class="ws-sr">Acts</span></th>
152
+ </tr>
153
+ </thead>
154
+ <tbody>
155
+ <tr aria-selected="false">
156
+ <td class="ws-table__check"><label class="ws-check"><input type="checkbox" aria-label="Select Priya Nair"><span class="ws-check__box" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span></label></td>
157
+ <th scope="row" class="ws-table__name">Priya Nair<span class="ws-table__fold">Zillow</span></th>
158
+ <td class="ws-table__num">82</td>
159
+ <td class="ws-table__num ws-table__num--wide">$612,000</td>
160
+ <td class="ws-table__low">Zillow</td>
161
+ <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call Priya</button><button type="button" class="ws-icon-btn ws-icon-btn--sm ws-table__more" aria-label="More for Priya Nair"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="3.6" r="0.9" fill="currentColor"/><circle cx="8" cy="8" r="0.9" fill="currentColor"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor"/></svg></button></td>
162
+ </tr>
163
+ </tbody>
164
+ <tfoot>
165
+ <tr><td class="ws-table__check"></td><th scope="row">Total, 1 lead</th><td class="ws-table__num">82</td><td class="ws-table__num ws-table__num--wide">$612,000</td><td class="ws-table__low"></td><td class="ws-table__acts"></td></tr>
166
+ </tfoot>
167
+ </table>
168
+ </div>
169
+ </section>
170
+ ```
171
+
172
+ ## Styles
173
+
174
+ `design-system/components/Table/style.css`, in `bundle.css` and `fello.css`. Light, dark and the navy ground come from
175
+ the tokens (`--color-bg-page`, `--ws-surface-sunk`, `--ws-hover-faint`, `--ws-divider`); a table on another surface
176
+ sets `--ws-table-ground`. The card is a size container named `ws-table`, so it needs the width of its column (a card in
177
+ a shrink-to-fit row collapses: give it a width). The edge cues use scroll-driven animations where the browser has them.
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Data" height=552 -->
1
+ <!-- @dsCard group="Data" height=900 -->
2
2
  <!doctype html>
3
3
  <html>
4
4
  <head>
@@ -8,135 +8,169 @@
8
8
  <link rel="stylesheet" href="../bundle.css">
9
9
  </head>
10
10
  <body>
11
- <div class="ws-stage ws-stage--grey">
11
+ <div class="ws-stage ws-stage--grey ws-stage--column">
12
12
 
13
- <div class="ws-stack" style="width: 900px; max-width: 100%;">
14
- <span class="ws-muted">900 px: checkbox column, a sortable header, a selected row (navy inset), tabular numbers, acts always in the DOM</span>
13
+ <div class="ws-stack">
14
+ <span class="ws-muted">Wide table: check column and the name stay while the rest scroll (a shade on the name's edge once they move, a fade on the far edge while columns are hidden), numbers right-aligned in fixed columns, a sorted column, a selected row, totals in the foot (under 30rem a long name wraps so the sliding columns keep room)</span>
15
15
  <section class="ws-card ws-table" aria-label="Leads">
16
- <div class="ws-table__scroll">
16
+ <div class="ws-table__scroll" role="region" aria-label="Leads, scrolls sideways" tabindex="0">
17
17
  <table>
18
18
  <thead>
19
19
  <tr>
20
- <th class="ws-table__check"><label class="ws-sr" for="chk-all">Select all</label><input id="chk-all" type="checkbox" aria-label="Select all rows"></th>
21
- <th scope="col">Name</th>
20
+ <th scope="col" class="ws-table__check"><label class="ws-check"><input type="checkbox" aria-label="Select all leads"><span class="ws-check__box" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span></label></th>
21
+ <th scope="col" class="ws-table__name">Name</th>
22
22
  <th scope="col">Stage</th>
23
- <th scope="col" class="ws-table__num">
24
- <button type="button" class="ws-table__sort" aria-label="Sort by score, ascending">Score
25
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6l4 4 4-4"/></svg>
23
+ <th scope="col" class="ws-table__num" aria-sort="descending">
24
+ <button type="button" class="ws-table__sort">Score
25
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg>
26
26
  </button>
27
27
  </th>
28
28
  <th scope="col" class="ws-table__num">Change</th>
29
+ <th scope="col" class="ws-table__num ws-table__num--wide">
30
+ <button type="button" class="ws-table__sort">Price
31
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg>
32
+ </button>
33
+ </th>
29
34
  <th scope="col">Last call</th>
30
- <th scope="col" class="ws-table__num">Acts</th>
35
+ <th scope="col" class="ws-table__low">Source</th>
36
+ <th scope="col" class="ws-table__low">Owner</th>
37
+ <th scope="col" class="ws-table__acts"><span class="ws-sr">Acts</span></th>
31
38
  </tr>
32
39
  </thead>
33
40
  <tbody>
34
41
  <tr>
35
- <td class="ws-table__check"><input type="checkbox" aria-label="Select Priya Nair"></td>
36
- <td class="ws-table__name">Priya Nair</td>
42
+ <td class="ws-table__check"><label class="ws-check"><input type="checkbox" aria-label="Select Priya Nair"><span class="ws-check__box" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span></label></td>
43
+ <th scope="row" class="ws-table__name">Priya Nair<span class="ws-table__fold">Zillow, Dana Alvarez</span></th>
37
44
  <td><span class="ws-chip ws-chip--needs">New lead</span></td>
38
45
  <td class="ws-table__num">82</td>
39
46
  <td class="ws-table__num"><span class="ws-change ws-change--up"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12L12 4M6 4h6v6"/></svg>6</span></td>
47
+ <td class="ws-table__num ws-table__num--wide">$612,000</td>
40
48
  <td>Oct 21</td>
41
- <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call</button><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Move</button></td>
49
+ <td class="ws-table__low">Zillow</td>
50
+ <td class="ws-table__low">Dana Alvarez</td>
51
+ <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call Priya</button><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Move</button><button type="button" class="ws-icon-btn ws-icon-btn--sm ws-table__more" aria-label="More for Priya Nair"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><circle cx="8" cy="3.6" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor" stroke="none"/></svg></button></td>
42
52
  </tr>
43
- <tr class="ws-table__row--selected">
44
- <td class="ws-table__check"><input type="checkbox" checked aria-label="Select Dana Alvarez"></td>
45
- <td class="ws-table__name">Dana Alvarez</td>
53
+ <tr class="ws-table__row--selected" aria-selected="true">
54
+ <td class="ws-table__check"><label class="ws-check"><input type="checkbox" checked aria-label="Select Dana Alvarez"><span class="ws-check__box" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span></label></td>
55
+ <th scope="row" class="ws-table__name">Dana Alvarez<span class="ws-table__fold">Referral, Sam Okafor</span></th>
46
56
  <td><span class="ws-chip ws-chip--live">Offer out</span></td>
47
57
  <td class="ws-table__num">91</td>
48
58
  <td class="ws-table__num"><span class="ws-change ws-change--up"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12L12 4M6 4h6v6"/></svg>3</span></td>
59
+ <td class="ws-table__num ws-table__num--wide">$1,245,000</td>
49
60
  <td>Oct 24</td>
50
- <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call</button><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Move</button></td>
61
+ <td class="ws-table__low">Referral</td>
62
+ <td class="ws-table__low">Sam Okafor</td>
63
+ <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call Dana</button><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Move</button><button type="button" class="ws-icon-btn ws-icon-btn--sm ws-table__more" aria-label="More for Dana Alvarez"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><circle cx="8" cy="3.6" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor" stroke="none"/></svg></button></td>
51
64
  </tr>
52
65
  <tr>
53
- <td class="ws-table__check"><input type="checkbox" aria-label="Select Sam Okafor"></td>
54
- <td class="ws-table__name">Sam Okafor</td>
66
+ <td class="ws-table__check"><label class="ws-check"><input type="checkbox" aria-label="Select Sam Okafor"><span class="ws-check__box" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span></label></td>
67
+ <th scope="row" class="ws-table__name">Sam Okafor<span class="ws-table__fold">Open house, Dana Alvarez</span></th>
55
68
  <td><span class="ws-chip ws-chip--sunk">Showing booked</span></td>
56
69
  <td class="ws-table__num">67</td>
57
70
  <td class="ws-table__num"><span class="ws-change ws-change--down"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 4l8 8M12 6v6H6"/></svg>4</span></td>
71
+ <td class="ws-table__num ws-table__num--wide">$489,500</td>
58
72
  <td>Oct 18</td>
59
- <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call</button><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Move</button></td>
73
+ <td class="ws-table__low">Open house</td>
74
+ <td class="ws-table__low">Dana Alvarez</td>
75
+ <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call Sam</button><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Move</button><button type="button" class="ws-icon-btn ws-icon-btn--sm ws-table__more" aria-label="More for Sam Okafor"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><circle cx="8" cy="3.6" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor" stroke="none"/></svg></button></td>
60
76
  </tr>
61
77
  <tr>
62
- <td class="ws-table__check"><input type="checkbox" aria-label="Select Nellie Park"></td>
63
- <td class="ws-table__name">Nellie Park</td>
78
+ <td class="ws-table__check"><label class="ws-check"><input type="checkbox" aria-label="Select Nellie Park-Whitcombe"><span class="ws-check__box" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span></label></td>
79
+ <th scope="row" class="ws-table__name">Nellie Park-Whitcombe<span class="ws-table__sub">Buyer, first home</span><span class="ws-table__fold">Zillow, Jo Whitfield</span></th>
64
80
  <td><span class="ws-chip ws-chip--sunk">Follow-up sent</span></td>
65
- <td class="ws-table__num">74</td>
81
+ <td class="ws-table__num">74<span class="ws-table__sub">of 100</span></td>
66
82
  <td class="ws-table__num"><span class="ws-change"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 8h8"/></svg>0</span></td>
83
+ <td class="ws-table__num ws-table__num--wide">$530,000</td>
67
84
  <td>Oct 22</td>
68
- <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call</button><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Move</button></td>
85
+ <td class="ws-table__low">Zillow</td>
86
+ <td class="ws-table__low">Jo Whitfield</td>
87
+ <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call Nellie</button><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Move</button><button type="button" class="ws-icon-btn ws-icon-btn--sm ws-table__more" aria-label="More for Nellie Park-Whitcombe"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><circle cx="8" cy="3.6" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor" stroke="none"/></svg></button></td>
69
88
  </tr>
70
89
  <tr>
71
- <td class="ws-table__check"><input type="checkbox" aria-label="Select Marco Diaz"></td>
72
- <td class="ws-table__name">Marco Diaz</td>
90
+ <td class="ws-table__check"><label class="ws-check"><input type="checkbox" aria-label="Select Marco Diaz"><span class="ws-check__box" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span></label></td>
91
+ <th scope="row" class="ws-table__name">Marco Diaz<span class="ws-table__fold">Website, Sam Okafor</span></th>
73
92
  <td><span class="ws-chip ws-chip--needs">New lead</span></td>
74
93
  <td class="ws-table__num">58</td>
75
94
  <td class="ws-table__num"><span class="ws-change ws-change--up"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12L12 4M6 4h6v6"/></svg>9</span></td>
95
+ <td class="ws-table__num ws-table__num--wide">$375,000</td>
76
96
  <td>Oct 15</td>
77
- <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call</button><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Move</button></td>
97
+ <td class="ws-table__low">Website</td>
98
+ <td class="ws-table__low">Sam Okafor</td>
99
+ <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call Marco</button><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Move</button><button type="button" class="ws-icon-btn ws-icon-btn--sm ws-table__more" aria-label="More for Marco Diaz"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><circle cx="8" cy="3.6" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor" stroke="none"/></svg></button></td>
78
100
  </tr>
101
+ </tbody>
102
+ <tfoot>
79
103
  <tr>
80
- <td class="ws-table__check"><input type="checkbox" aria-label="Select Jo Whitfield"></td>
81
- <td class="ws-table__name">Jo Whitfield</td>
82
- <td><span class="ws-chip ws-chip--live">Closed</span></td>
83
- <td class="ws-table__num">88</td>
84
- <td class="ws-table__num"><span class="ws-change ws-change--up"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12L12 4M6 4h6v6"/></svg>2</span></td>
85
- <td>Oct 9</td>
86
- <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call</button><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Move</button></td>
104
+ <td class="ws-table__check"></td>
105
+ <th scope="row">Total, 5 leads</th>
106
+ <td></td>
107
+ <td class="ws-table__num"></td>
108
+ <td class="ws-table__num"></td>
109
+ <td class="ws-table__num ws-table__num--wide">$3,251,500</td>
110
+ <td></td>
111
+ <td class="ws-table__low"></td>
112
+ <td class="ws-table__low"></td>
113
+ <td class="ws-table__acts"></td>
87
114
  </tr>
88
- </tbody>
115
+ </tfoot>
89
116
  </table>
90
117
  </div>
91
118
  </section>
92
119
  </div>
93
120
 
94
- <div class="ws-cluster ws-cluster--component ws-cluster--start" style="width: 100%;">
95
- <figure class="ws-stack" style="width: 300px;">
96
- <span class="ws-muted">480 px: name, stage, score stay; the rest folds into "More" per row (caption)</span>
121
+ <div class="ws-cluster ws-cluster--component ws-cluster--start">
122
+ <figure class="ws-stack" style="width: 340px;">
123
+ <span class="ws-muted">Under 48rem the low-priority columns fold into a line under each name; under 30rem the row acts become one More act</span>
97
124
  <section class="ws-card ws-table" aria-label="Leads, narrow">
98
- <table>
99
- <thead><tr><th scope="col">Name</th><th scope="col">Stage</th><th scope="col" class="ws-table__num">More</th></tr></thead>
100
- <tbody>
101
- <tr>
102
- <td class="ws-table__name">Priya Nair</td>
103
- <td><span class="ws-chip ws-chip--needs">New lead</span></td>
104
- <td class="ws-table__acts"><button type="button" class="ws-icon-btn" aria-label="More for Priya Nair"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="3.6" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor" stroke="none"/></svg></button></td>
105
- </tr>
106
- <tr class="ws-table__row--selected">
107
- <td class="ws-table__name">Dana Alvarez</td>
108
- <td><span class="ws-chip ws-chip--live">Offer out</span></td>
109
- <td class="ws-table__acts"><button type="button" class="ws-icon-btn" aria-label="More for Dana Alvarez"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="3.6" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor" stroke="none"/></svg></button></td>
110
- </tr>
111
- <tr>
112
- <td class="ws-table__name">Sam Okafor</td>
113
- <td><span class="ws-chip ws-chip--sunk">Showing booked</span></td>
114
- <td class="ws-table__acts"><button type="button" class="ws-icon-btn" aria-label="More for Sam Okafor"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="3.6" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor" stroke="none"/></svg></button></td>
115
- </tr>
116
- </tbody>
117
- </table>
125
+ <div class="ws-table__scroll" role="region" aria-label="Leads, narrow" tabindex="0">
126
+ <table>
127
+ <thead><tr><th scope="col" class="ws-table__name">Name</th><th scope="col" class="ws-table__num">Score</th><th scope="col" class="ws-table__low">Source</th><th scope="col" class="ws-table__acts"><span class="ws-sr">Acts</span></th></tr></thead>
128
+ <tbody>
129
+ <tr>
130
+ <th scope="row" class="ws-table__name">Priya Nair<span class="ws-table__fold">Zillow, Oct 21</span></th>
131
+ <td class="ws-table__num">82</td>
132
+ <td class="ws-table__low">Zillow</td>
133
+ <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call Priya</button><button type="button" class="ws-icon-btn ws-icon-btn--sm ws-table__more" aria-label="More for Priya Nair"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><circle cx="8" cy="3.6" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor" stroke="none"/></svg></button></td>
134
+ </tr>
135
+ <tr class="ws-table__row--selected" aria-selected="true">
136
+ <th scope="row" class="ws-table__name">Dana Alvarez<span class="ws-table__fold">Referral, Oct 24</span></th>
137
+ <td class="ws-table__num">91</td>
138
+ <td class="ws-table__low">Referral</td>
139
+ <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call Dana</button><button type="button" class="ws-icon-btn ws-icon-btn--sm ws-table__more" aria-label="More for Dana Alvarez"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><circle cx="8" cy="3.6" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor" stroke="none"/></svg></button></td>
140
+ </tr>
141
+ <tr>
142
+ <th scope="row" class="ws-table__name">Sam Okafor<span class="ws-table__fold">Open house, Oct 18</span></th>
143
+ <td class="ws-table__num">67</td>
144
+ <td class="ws-table__low">Open house</td>
145
+ <td class="ws-table__acts"><button type="button" class="ws-btn ws-btn--ghost ws-btn--sm">Call Sam</button><button type="button" class="ws-icon-btn ws-icon-btn--sm ws-table__more" aria-label="More for Sam Okafor"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><circle cx="8" cy="3.6" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="0.9" fill="currentColor" stroke="none"/><circle cx="8" cy="12.4" r="0.9" fill="currentColor" stroke="none"/></svg></button></td>
146
+ </tr>
147
+ </tbody>
148
+ </table>
149
+ </div>
118
150
  </section>
119
151
  </figure>
120
152
 
121
- <div class="ws-stack" style="width: 240px;">
122
- <span class="ws-muted">Loading: skeleton rows, the head shown at once</span>
153
+ <div class="ws-stack" style="width: 300px;">
154
+ <span class="ws-muted">Loading: ghost bars under the shimmer, the head shown at once</span>
123
155
  <section class="ws-card ws-table" aria-busy="true" aria-label="Leads, loading">
124
- <table>
125
- <thead><tr><th scope="col">Name</th><th scope="col">Score</th></tr></thead>
126
- <tbody>
127
- <tr><td><div class="ws-table__placeholder" style="width: var(--space-6xl);"></div></td><td><div class="ws-table__placeholder" style="width: var(--space-lg);"></div></td></tr>
128
- <tr><td><div class="ws-table__placeholder" style="width: calc(var(--space-6xl) + var(--space-md));"></div></td><td><div class="ws-table__placeholder" style="width: var(--space-lg);"></div></td></tr>
129
- <tr><td><div class="ws-table__placeholder" style="width: var(--space-5xl);"></div></td><td><div class="ws-table__placeholder" style="width: var(--space-lg);"></div></td></tr>
130
- </tbody>
131
- </table>
156
+ <div class="ws-table__scroll">
157
+ <table>
158
+ <thead><tr><th scope="col" class="ws-table__name">Name</th><th scope="col" class="ws-table__num">Score</th></tr></thead>
159
+ <tbody>
160
+ <tr><td><div class="ws-table__placeholder ws-shimmer" style="width: var(--space-6xl);"></div></td><td class="ws-table__num"><div class="ws-table__placeholder ws-shimmer" style="width: var(--space-lg); margin-left: auto;"></div></td></tr>
161
+ <tr><td><div class="ws-table__placeholder ws-shimmer" style="width: calc(var(--space-6xl) + var(--space-md));"></div></td><td class="ws-table__num"><div class="ws-table__placeholder ws-shimmer" style="width: var(--space-lg); margin-left: auto;"></div></td></tr>
162
+ <tr><td><div class="ws-table__placeholder ws-shimmer" style="width: var(--space-5xl);"></div></td><td class="ws-table__num"><div class="ws-table__placeholder ws-shimmer" style="width: var(--space-lg); margin-left: auto;"></div></td></tr>
163
+ </tbody>
164
+ </table>
165
+ </div>
132
166
  </section>
133
167
  </div>
134
168
 
135
- <div class="ws-stack" style="width: 240px;">
169
+ <div class="ws-stack" style="width: 300px;">
136
170
  <span class="ws-muted">Empty, no matches: the same card, the act that clears the filter</span>
137
- <section class="ws-card ws-table">
171
+ <section class="ws-card ws-table" aria-label="Leads, no matches">
138
172
  <div class="ws-table__empty">
139
- <p class="ws-body">Nobody matches "offer out, over 90".</p>
173
+ <p class="ws-body">Nobody matches “offer out, over 90”.</p>
140
174
  <button type="button" class="ws-btn ws-btn--secondary">Clear the filter</button>
141
175
  </div>
142
176
  </section>