@felloinnovations/brand-kit 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/AGENTS.md +198 -24
  2. package/CHANGELOG.md +197 -0
  3. package/README.md +34 -7
  4. package/design-system/01-how-claude-decides.md +26 -17
  5. package/design-system/02-principles.md +11 -6
  6. package/design-system/03-colour.md +134 -47
  7. package/design-system/04-type.md +45 -23
  8. package/design-system/05-space-and-layout.md +175 -52
  9. package/design-system/06-sizing-profiles.md +4 -4
  10. package/design-system/07-scrolling.md +66 -20
  11. package/design-system/08-choosing-components.md +50 -22
  12. package/design-system/09-charts.md +71 -28
  13. package/design-system/10-patterns.md +33 -10
  14. package/design-system/11-page-recipes.md +110 -23
  15. package/design-system/12-content.md +2 -1
  16. package/design-system/13-motion.md +330 -47
  17. package/design-system/14-accessibility.md +47 -24
  18. package/design-system/15-ai-experiences.md +11 -6
  19. package/design-system/16-creativity.md +1 -1
  20. package/design-system/17-decisions.md +357 -1
  21. package/design-system/18-checklist.md +79 -16
  22. package/design-system/19-public-pages.md +6 -4
  23. package/design-system/20-palettes.md +275 -0
  24. package/design-system/README.md +30 -17
  25. package/design-system/components/ActionList/README.md +96 -10
  26. package/design-system/components/ActionList/preview.html +52 -7
  27. package/design-system/components/ActionList/style.css +64 -0
  28. package/design-system/components/ActivityGrid/README.md +38 -2
  29. package/design-system/components/ActivityGrid/preview.html +1 -1
  30. package/design-system/components/ActivityGrid/style.css +35 -0
  31. package/design-system/components/AppShell/README.md +205 -75
  32. package/design-system/components/AppShell/preview.html +339 -58
  33. package/design-system/components/AppShell/style.css +154 -0
  34. package/design-system/components/Avatar/README.md +37 -10
  35. package/design-system/components/Avatar/preview.html +13 -4
  36. package/design-system/components/Avatar/style.css +14 -0
  37. package/design-system/components/Badge/README.md +41 -19
  38. package/design-system/components/Badge/preview.html +13 -10
  39. package/design-system/components/Badge/style.css +23 -0
  40. package/design-system/components/Banner/README.md +30 -9
  41. package/design-system/components/Banner/preview.html +1 -1
  42. package/design-system/components/Banner/style.css +19 -0
  43. package/design-system/components/Breadcrumb/README.md +58 -46
  44. package/design-system/components/Breadcrumb/preview.html +16 -16
  45. package/design-system/components/Breadcrumb/style.css +17 -0
  46. package/design-system/components/Button/README.md +113 -55
  47. package/design-system/components/Button/preview.html +98 -25
  48. package/design-system/components/Button/style.css +86 -0
  49. package/design-system/components/Card/README.md +158 -49
  50. package/design-system/components/Card/preview.html +141 -19
  51. package/design-system/components/Card/style.css +115 -0
  52. package/design-system/components/CardBoard/README.md +58 -37
  53. package/design-system/components/CardBoard/preview.html +26 -29
  54. package/design-system/components/ChatCard/README.md +115 -29
  55. package/design-system/components/ChatCard/preview.html +149 -32
  56. package/design-system/components/ChatCard/style.css +49 -0
  57. package/design-system/components/ChatShell/README.md +116 -0
  58. package/design-system/components/ChatShell/preview.html +201 -0
  59. package/design-system/components/ChatShell/style.css +86 -0
  60. package/design-system/components/ChatTurn/README.md +78 -35
  61. package/design-system/components/ChatTurn/preview.html +60 -28
  62. package/design-system/components/ChatTurn/style.css +50 -0
  63. package/design-system/components/CheckRow/README.md +141 -0
  64. package/design-system/components/CheckRow/preview.html +140 -0
  65. package/design-system/components/CheckRow/style.css +88 -0
  66. package/design-system/components/Checkbox/README.md +58 -22
  67. package/design-system/components/Checkbox/preview.html +112 -50
  68. package/design-system/components/Checkbox/style.css +45 -0
  69. package/design-system/components/Chip/README.md +78 -47
  70. package/design-system/components/Chip/preview.html +29 -4
  71. package/design-system/components/Chip/style.css +17 -0
  72. package/design-system/components/Combobox/README.md +44 -11
  73. package/design-system/components/Combobox/preview.html +35 -12
  74. package/design-system/components/Combobox/style.css +54 -0
  75. package/design-system/components/Composer/README.md +137 -35
  76. package/design-system/components/Composer/preview.html +115 -40
  77. package/design-system/components/Composer/style.css +81 -0
  78. package/design-system/components/ConfirmDialog/README.md +73 -52
  79. package/design-system/components/ConfirmDialog/preview.html +70 -26
  80. package/design-system/components/ConfirmDialog/style.css +5 -0
  81. package/design-system/components/Cover/preview.html +3 -3
  82. package/design-system/components/Cover/style.css +19 -0
  83. package/design-system/components/DateInput/README.md +77 -12
  84. package/design-system/components/DateInput/preview.html +27 -12
  85. package/design-system/components/DateInput/style.css +38 -0
  86. package/design-system/components/Dialog/README.md +112 -44
  87. package/design-system/components/Dialog/preview.html +141 -18
  88. package/design-system/components/Dialog/style.css +74 -0
  89. package/design-system/components/EmptyState/README.md +42 -12
  90. package/design-system/components/EmptyState/preview.html +11 -11
  91. package/design-system/components/EmptyState/style.css +9 -0
  92. package/design-system/components/EntryShell/README.md +73 -48
  93. package/design-system/components/EntryShell/preview.html +60 -27
  94. package/design-system/components/EntryShell/style.css +19 -0
  95. package/design-system/components/FeatureGrid/README.md +61 -39
  96. package/design-system/components/FeatureGrid/preview.html +2 -2
  97. package/design-system/components/FeatureGrid/style.css +20 -0
  98. package/design-system/components/FileUpload/README.md +33 -3
  99. package/design-system/components/FileUpload/preview.html +18 -4
  100. package/design-system/components/FileUpload/style.css +23 -0
  101. package/design-system/components/FilterBar/README.md +114 -0
  102. package/design-system/components/FilterBar/preview.html +82 -0
  103. package/design-system/components/FilterBar/style.css +22 -0
  104. package/design-system/components/Fold/README.md +84 -26
  105. package/design-system/components/Fold/preview.html +77 -34
  106. package/design-system/components/Fold/style.css +48 -0
  107. package/design-system/components/Footer/README.md +62 -39
  108. package/design-system/components/Footer/preview.html +5 -5
  109. package/design-system/components/Footer/style.css +30 -0
  110. package/design-system/components/FunnelBars/README.md +24 -3
  111. package/design-system/components/FunnelBars/preview.html +5 -5
  112. package/design-system/components/FunnelBars/style.css +13 -0
  113. package/design-system/components/GoalBars/README.md +54 -10
  114. package/design-system/components/GoalBars/preview.html +69 -28
  115. package/design-system/components/GoalBars/style.css +51 -0
  116. package/design-system/components/GoalTicks/README.md +74 -58
  117. package/design-system/components/GoalTicks/preview.html +41 -118
  118. package/design-system/components/GoalTicks/style.css +37 -0
  119. package/design-system/components/GoalTubes/README.md +29 -3
  120. package/design-system/components/GoalTubes/preview.html +6 -6
  121. package/design-system/components/GoalTubes/style.css +23 -0
  122. package/design-system/components/Heatmap/README.md +133 -0
  123. package/design-system/components/Heatmap/preview.html +168 -0
  124. package/design-system/components/Heatmap/style.css +119 -0
  125. package/design-system/components/Hero/README.md +58 -40
  126. package/design-system/components/Hero/preview.html +1 -1
  127. package/design-system/components/Hero/style.css +19 -0
  128. package/design-system/components/HoverCard/README.md +114 -0
  129. package/design-system/components/HoverCard/preview.html +107 -0
  130. package/design-system/components/HoverCard/style.css +59 -0
  131. package/design-system/components/IconButton/README.md +69 -38
  132. package/design-system/components/IconButton/preview.html +77 -43
  133. package/design-system/components/IconButton/style.css +45 -0
  134. package/design-system/components/Input/README.md +36 -11
  135. package/design-system/components/Input/preview.html +1 -1
  136. package/design-system/components/Input/style.css +23 -0
  137. package/design-system/components/KanbanBoard/README.md +93 -45
  138. package/design-system/components/KanbanBoard/preview.html +159 -43
  139. package/design-system/components/KanbanBoard/style.css +53 -0
  140. package/design-system/components/Kbd/README.md +25 -9
  141. package/design-system/components/Kbd/preview.html +6 -2
  142. package/design-system/components/Kbd/style.css +9 -0
  143. package/design-system/components/KitButton/README.md +81 -47
  144. package/design-system/components/KitButton/preview.html +35 -13
  145. package/design-system/components/KitButton/style.css +46 -0
  146. package/design-system/components/KitCard/README.md +75 -44
  147. package/design-system/components/KitCard/preview.html +18 -10
  148. package/design-system/components/KitCard/style.css +15 -0
  149. package/design-system/components/KitInput/README.md +54 -39
  150. package/design-system/components/KitInput/preview.html +7 -7
  151. package/design-system/components/KitInput/style.css +23 -0
  152. package/design-system/components/Leaderboard/README.md +76 -49
  153. package/design-system/components/Leaderboard/preview.html +61 -26
  154. package/design-system/components/Leaderboard/style.css +44 -0
  155. package/design-system/components/ListDetail/README.md +222 -0
  156. package/design-system/components/ListDetail/preview.html +213 -0
  157. package/design-system/components/ListDetail/style.css +148 -0
  158. package/design-system/components/LoadBar/README.md +79 -0
  159. package/design-system/components/LoadBar/preview.html +40 -0
  160. package/design-system/components/LoadBar/style.css +17 -0
  161. package/design-system/components/MarketingNav/README.md +76 -42
  162. package/design-system/components/MarketingNav/preview.html +37 -8
  163. package/design-system/components/MarketingNav/style.css +45 -0
  164. package/design-system/components/Matrix/README.md +129 -0
  165. package/design-system/components/Matrix/preview.html +99 -0
  166. package/design-system/components/Matrix/style.css +84 -0
  167. package/design-system/components/Menu/README.md +117 -41
  168. package/design-system/components/Menu/preview.html +85 -23
  169. package/design-system/components/Menu/style.css +61 -0
  170. package/design-system/components/Meter/README.md +39 -4
  171. package/design-system/components/Meter/preview.html +18 -1
  172. package/design-system/components/Meter/style.css +23 -0
  173. package/design-system/components/MetricTile/README.md +237 -0
  174. package/design-system/components/MetricTile/preview.html +241 -0
  175. package/design-system/components/MetricTile/style.css +129 -0
  176. package/design-system/components/Morph/README.md +106 -0
  177. package/design-system/components/Morph/preview.html +103 -0
  178. package/design-system/components/Morph/style.css +31 -0
  179. package/design-system/components/Motion/README.md +164 -0
  180. package/design-system/components/Motion/preview.html +2537 -0
  181. package/design-system/components/NumberInput/README.md +27 -8
  182. package/design-system/components/NumberInput/preview.html +21 -5
  183. package/design-system/components/NumberInput/style.css +34 -0
  184. package/design-system/components/PaceBar/README.md +75 -0
  185. package/design-system/components/PaceBar/preview.html +67 -0
  186. package/design-system/components/PaceBar/style.css +25 -0
  187. package/design-system/components/Page/README.md +57 -18
  188. package/design-system/components/Page/preview.html +15 -17
  189. package/design-system/components/Page/style.css +7 -0
  190. package/design-system/components/PageBar/README.md +90 -34
  191. package/design-system/components/PageBar/preview.html +60 -19
  192. package/design-system/components/PageBar/style.css +35 -0
  193. package/design-system/components/PageHero/README.md +87 -51
  194. package/design-system/components/PageHero/preview.html +35 -6
  195. package/design-system/components/PageHero/style.css +31 -0
  196. package/design-system/components/Pagination/README.md +70 -49
  197. package/design-system/components/Pagination/preview.html +24 -15
  198. package/design-system/components/Pagination/style.css +12 -0
  199. package/design-system/components/Panel/README.md +109 -51
  200. package/design-system/components/Panel/preview.html +118 -20
  201. package/design-system/components/Panel/style.css +51 -0
  202. package/design-system/components/PasswordInput/README.md +50 -18
  203. package/design-system/components/PasswordInput/preview.html +71 -21
  204. package/design-system/components/PasswordInput/style.css +31 -0
  205. package/design-system/components/Plate/README.md +75 -17
  206. package/design-system/components/Plate/preview.html +40 -7
  207. package/design-system/components/Plate/style.css +37 -0
  208. package/design-system/components/Popover/README.md +70 -49
  209. package/design-system/components/Popover/preview.html +44 -22
  210. package/design-system/components/Popover/style.css +41 -0
  211. package/design-system/components/PricingTable/README.md +69 -49
  212. package/design-system/components/PricingTable/preview.html +21 -21
  213. package/design-system/components/PricingTable/style.css +21 -0
  214. package/design-system/components/ProgressPetals/README.md +31 -3
  215. package/design-system/components/ProgressPetals/preview.html +14 -15
  216. package/design-system/components/ProgressPetals/style.css +27 -0
  217. package/design-system/components/README.md +151 -0
  218. package/design-system/components/Radio/README.md +40 -17
  219. package/design-system/components/Radio/preview.html +16 -1
  220. package/design-system/components/Radio/style.css +21 -0
  221. package/design-system/components/RankBar/README.md +29 -2
  222. package/design-system/components/RankBar/preview.html +14 -12
  223. package/design-system/components/RankBar/style.css +18 -0
  224. package/design-system/components/Ring/README.md +61 -11
  225. package/design-system/components/Ring/preview.html +55 -10
  226. package/design-system/components/Ring/style.css +49 -0
  227. package/design-system/components/ScoreHero/README.md +91 -0
  228. package/design-system/components/ScoreHero/preview.html +104 -0
  229. package/design-system/components/ScoreHero/style.css +32 -0
  230. package/design-system/components/Section/README.md +72 -33
  231. package/design-system/components/Section/preview.html +46 -16
  232. package/design-system/components/Section/style.css +18 -0
  233. package/design-system/components/Segmented/README.md +100 -55
  234. package/design-system/components/Segmented/preview.html +107 -26
  235. package/design-system/components/Segmented/style.css +94 -0
  236. package/design-system/components/SegmentedProgress/README.md +64 -0
  237. package/design-system/components/SegmentedProgress/preview.html +69 -0
  238. package/design-system/components/SegmentedProgress/style.css +11 -0
  239. package/design-system/components/Select/README.md +47 -12
  240. package/design-system/components/Select/preview.html +28 -2
  241. package/design-system/components/Select/style.css +22 -0
  242. package/design-system/components/ShareBar/README.md +69 -0
  243. package/design-system/components/ShareBar/preview.html +72 -0
  244. package/design-system/components/ShareBar/style.css +25 -0
  245. package/design-system/components/SideList/README.md +147 -0
  246. package/design-system/components/SideList/preview.html +139 -0
  247. package/design-system/components/SideList/style.css +94 -0
  248. package/design-system/components/Skeleton/README.md +52 -16
  249. package/design-system/components/Skeleton/preview.html +35 -23
  250. package/design-system/components/Skeleton/style.css +22 -0
  251. package/design-system/components/Slider/README.md +95 -0
  252. package/design-system/components/Slider/preview.html +49 -0
  253. package/design-system/components/Slider/style.css +13 -0
  254. package/design-system/components/Split/README.md +112 -0
  255. package/design-system/components/Split/preview.html +105 -0
  256. package/design-system/components/Split/style.css +30 -0
  257. package/design-system/components/Starter/README.md +21 -9
  258. package/design-system/components/Starter/preview.html +5 -5
  259. package/design-system/components/Stat/README.md +64 -43
  260. package/design-system/components/Stat/preview.html +3 -3
  261. package/design-system/components/Stat/style.css +15 -0
  262. package/design-system/components/StatTiles/README.md +88 -44
  263. package/design-system/components/StatTiles/preview.html +142 -71
  264. package/design-system/components/StatTiles/style.css +64 -0
  265. package/design-system/components/StatusLine/README.md +85 -0
  266. package/design-system/components/StatusLine/preview.html +49 -0
  267. package/design-system/components/StatusLine/style.css +14 -0
  268. package/design-system/components/StatusScreen/README.md +49 -35
  269. package/design-system/components/StatusScreen/preview.html +20 -5
  270. package/design-system/components/StatusScreen/style.css +9 -0
  271. package/design-system/components/StepLine/README.md +97 -0
  272. package/design-system/components/StepLine/preview.html +108 -0
  273. package/design-system/components/StepLine/style.css +62 -0
  274. package/design-system/components/Stepper/README.md +35 -13
  275. package/design-system/components/Stepper/style.css +13 -0
  276. package/design-system/components/StreakCalendar/README.md +22 -1
  277. package/design-system/components/StreakCalendar/preview.html +10 -10
  278. package/design-system/components/StreakCalendar/style.css +12 -0
  279. package/design-system/components/SuggestionChip/README.md +87 -0
  280. package/design-system/components/SuggestionChip/preview.html +42 -0
  281. package/design-system/components/SuggestionChip/style.css +20 -0
  282. package/design-system/components/Switch/README.md +44 -24
  283. package/design-system/components/Switch/preview.html +23 -8
  284. package/design-system/components/Switch/style.css +31 -0
  285. package/design-system/components/Table/README.md +129 -58
  286. package/design-system/components/Table/preview.html +106 -72
  287. package/design-system/components/Table/style.css +104 -0
  288. package/design-system/components/Tabs/README.md +71 -46
  289. package/design-system/components/Tabs/preview.html +56 -24
  290. package/design-system/components/Tabs/style.css +44 -0
  291. package/design-system/components/Testimonial/README.md +48 -32
  292. package/design-system/components/Testimonial/preview.html +14 -14
  293. package/design-system/components/Testimonial/style.css +12 -0
  294. package/design-system/components/TextArea/README.md +27 -11
  295. package/design-system/components/TextArea/preview.html +8 -2
  296. package/design-system/components/TextArea/style.css +12 -0
  297. package/design-system/components/ThemeSwitch/README.md +116 -0
  298. package/design-system/components/ThemeSwitch/preview.html +57 -0
  299. package/design-system/components/ThemeSwitch/style.css +6 -0
  300. package/design-system/components/TickRow/README.md +52 -36
  301. package/design-system/components/TickRow/preview.html +64 -41
  302. package/design-system/components/TickRow/style.css +23 -0
  303. package/design-system/components/TickStrip/README.md +95 -0
  304. package/design-system/components/TickStrip/preview.html +88 -0
  305. package/design-system/components/TickStrip/style.css +42 -0
  306. package/design-system/components/Tile/README.md +79 -18
  307. package/design-system/components/Tile/preview.html +91 -40
  308. package/design-system/components/Tile/style.css +36 -0
  309. package/design-system/components/Timeline/README.md +68 -48
  310. package/design-system/components/Timeline/preview.html +27 -15
  311. package/design-system/components/Timeline/style.css +25 -0
  312. package/design-system/components/Toast/README.md +70 -38
  313. package/design-system/components/Toast/preview.html +43 -8
  314. package/design-system/components/Toast/style.css +25 -0
  315. package/design-system/components/Tooltip/README.md +93 -35
  316. package/design-system/components/Tooltip/preview.html +69 -15
  317. package/design-system/components/Tooltip/style.css +78 -0
  318. package/design-system/components/TopBar/README.md +67 -53
  319. package/design-system/components/TopBar/preview.html +14 -27
  320. package/design-system/components/TopBar/style.css +35 -0
  321. package/design-system/components/TopicRail/README.md +108 -0
  322. package/design-system/components/TopicRail/preview.html +58 -0
  323. package/design-system/components/TopicRail/style.css +48 -0
  324. package/design-system/components/TrendBars/README.md +52 -14
  325. package/design-system/components/TrendBars/preview.html +65 -32
  326. package/design-system/components/TrendBars/style.css +25 -0
  327. package/design-system/components/TrendLine/README.md +164 -0
  328. package/design-system/components/TrendLine/preview.html +373 -0
  329. package/design-system/components/TrendLine/style.css +155 -0
  330. package/design-system/components/Well/README.md +64 -22
  331. package/design-system/components/Well/preview.html +14 -14
  332. package/design-system/components/Well/style.css +22 -0
  333. package/design-system/components/_house.css +324 -0
  334. package/design-system/components/bundle.css +4091 -744
  335. package/design-system/tokens.json +1314 -124
  336. package/dist/fello-core.css +2 -2
  337. package/dist/fello.css +6 -1369
  338. package/dist/fello.scoped.css +7 -0
  339. package/dist/index.d.ts +110 -11
  340. package/dist/index.js +781 -96
  341. package/dist/palettes.d.ts +464 -0
  342. package/dist/palettes.js +497 -0
  343. package/dist/scoped.d.ts +3 -0
  344. package/dist/scoped.js +16 -0
  345. package/dist/toast.d.ts +14 -0
  346. package/dist/toast.js +33 -29
  347. package/dist/tokens.d.ts +1686 -62
  348. package/dist/tokens.js +1668 -61
  349. package/package.json +20 -4
  350. package/scripts/check-palette.mjs +295 -0
  351. package/scripts/token-model.mjs +552 -0
  352. package/tokens/_dark.css +174 -0
  353. package/tokens/_palettes.css +46 -0
  354. package/tokens/_product.css +266 -53
  355. package/tokens/_source.hubl.css +39 -19
  356. package/tokens/design-tokens.json +319 -0
  357. package/tokens/palettes.ts +504 -0
  358. package/tokens/shadcn-compat.css +19 -19
  359. package/tokens/shadcn-compat.hsl.css +76 -0
  360. package/tokens/tokens.css +1292 -62
  361. package/tokens/tokens.md +588 -61
  362. package/tokens/tokens.root.css +1298 -62
  363. package/tokens/tokens.ts +1677 -64
@@ -1,6 +1,6 @@
1
1
  The kit's marketing piece: for a public page, never a product screen.
2
2
 
3
- Three features in a row, each a `KitCard` with an icon, a title, a sentence and a link.
3
+ Three features in a row, each a `KitCard`-style card with an icon, a title, a sentence and a link.
4
4
 
5
5
  ## Use it when
6
6
 
@@ -11,43 +11,45 @@ Three features in a row, each a `KitCard` with an icon, a title, a sentence and
11
11
 
12
12
  - More than three or four things of unequal importance: a longer list reads better as rows, not a grid of cards.
13
13
  - A single deep feature that needs its own section and screenshot: give it its own full-width block instead.
14
- - Any product screen: the product has no feature-grid idea; a page inside the main workspace shows state, not
15
- a pitch for the product itself.
14
+ - Any product screen: a page inside the workspace shows state, not a pitch for the product itself.
16
15
 
17
16
  ## Anatomy
18
17
 
19
- - Row: three `KitCard`s (`surface="white"`), `--layout-col-gap` (24px) apart, wrapping to one column under the
20
- content width.
21
- - Each card: `--space-lg` (24px) padding (via `CardHeader`/`CardContent`), a 40px `ws-disc` icon at the top, a
22
- title `--space-md` (16px) below it, a body paragraph `--space-xs` (8px) under the title, a link
23
- `--space-md` below that.
24
- - Icon: the product's own `ws-disc` (a 40px round disc, `--ws-surface-sunk` fill, `--color-text-heading` icon
25
- colour), holding a 20px hand-drawn line icon.
26
- - Title: `--font-size-lg2` (20px) semibold, `--color-brand-navy`.
27
- - Body: `--font-size-md` (16px), `--color-text-primary`.
28
- - Link: `--font-size-sm` (14px) medium, `--color-text-interactive` (mid blue), with a trailing arrow icon,
29
- underlining on hover.
18
+ - Band: `--color-surface`, `--space-xl` (32px) top and bottom, `--layout-margin` (48px) sides (16px under 40rem).
19
+ - Row (`__grid`): a grid of columns at least 260px wide, `--layout-col-gap` (24px) apart, capped at
20
+ `--layout-content-max`; the cards are equal height in each row.
21
+ - Card (`__card`): 4px corners, a 1px `--color-border-default` edge, `--color-surface`, `--space-lg` (24px) padding;
22
+ a column whose link sits at the foot, so cards of uneven copy line their links up.
23
+ - Icon (`__icon`): the house `ws-disc`, 40px, `--ws-surface-sunk` fill, a 20px line icon in `--color-text-heading`.
24
+ - Title (`__title`): `--space-md` (16px) under the icon, 20/28 semibold `--color-text-heading`.
25
+ - Body (`__body`): `--space-xs` (8px) under the title, 16/24 `--color-text-primary`, at least `--space-md` above the link.
26
+ - Link (`__link`): 14/20 medium `--color-text-interactive` (mid blue), a 12px trailing arrow `--space-xxs` from the
27
+ words, underlining on hover.
30
28
 
31
29
  ## Variants and sizes
32
30
 
33
- One layout: three columns, one gap size. A fourth card wraps to a second row at the same gap rather than
34
- shrinking the columns further.
31
+ One layout: as many 260px-or-wider columns as the row holds, one gap. Three fit a screen from 924px wide; on a
32
+ tablet two sit in a row and the third takes the first column of the next, the same width as the others; on a phone,
33
+ one column. A fourth card joins the row where there is room for it and otherwise starts the next row, in the same
34
+ columns.
35
35
 
36
36
  ## States
37
37
 
38
38
  - **Default:** as above.
39
- - **Hover:** only the link reacts (underline); the card itself is not `interactive`, since the click target is
40
- the link, not the whole card.
41
- - **Selected / pending / disabled / error:** not applicable.
42
- - **Empty:** not applicable; a feature section is never shown with fewer than its real features.
43
- - **Long label:** a longer title wraps to a second line; the body and link below it shift down with it, keeping
44
- the three cards' internal rhythm even if their total heights differ.
45
- - **Narrow:** below the content width the three cards stack to one column, full width, in the same order.
39
+ - **Hover:** only the link reacts (underline); the card is not interactive, since the click target is the link.
40
+ Only on a pointer that hovers (`@media (hover: hover)`), so a tap on a phone leaves nothing behind.
41
+ - **Focus:** the link takes the house ring, 2px navy, 2px out.
42
+ - **Selected / pending / disabled / error / empty:** not applicable.
43
+ - **Long label:** a longer title wraps; the body follows it, and the link stays on the card's foot, level with its
44
+ neighbours.
45
+ - **Narrow:** two to a row on a tablet, then one column on a phone, in the same order; a card that wraps never
46
+ stretches wider than its column.
47
+ - **Touch:** the link keeps its look and takes a 44px hit area above and below its words.
46
48
 
47
49
  ## Behaviour
48
50
 
49
- - Keyboard: each card's link is a real `<a>`, focusable in document order; the card itself takes no focus.
50
- - Pointer / touch: the link is the only interactive target.
51
+ - Keyboard: each card's link is a real `<a>`, focusable in document order; the card takes no focus.
52
+ - Pointer / touch: the link is the only target; 44px tall on touch.
51
53
  - Motion: none of its own.
52
54
 
53
55
  ## Content
@@ -58,7 +60,7 @@ shrinking the columns further.
58
60
 
59
61
  ## Props
60
62
 
61
- Not a kit export; composed from `KitCard` and `ws-disc`. A reusable version would take:
63
+ Not a kit export. A reusable version would take:
62
64
 
63
65
  | Prop | Type | Meaning |
64
66
  | --- | --- | --- |
@@ -66,19 +68,39 @@ Not a kit export; composed from `KitCard` and `ws-disc`. A reusable version woul
66
68
 
67
69
  ## Rules
68
70
 
69
- - **Intentional addition, decided from the system (26 Oct 2026):** the kit ships `Card` but no grid pattern for
70
- it; a landing page needs exactly this arrangement for its "what you get" section, built from `KitCard` and the
71
- kit's own layout gap token.
72
- - The gap between the cards is `--layout-col-gap` (24px), named in `tokens/tokens.md` as the kit's own column gap,
73
- the same value the brief calls out directly: "the 24 px column gap (`--layout-col-gap`)."
74
- - The title size, `--font-size-lg2` (20px), is `$P/tokens.json`'s own label for this exact job: "font-size-lg2:
75
- marketing small heading."
76
- - The icon reuses the product's `ws-disc` rather than inventing a second disc shape, since the brief and the
77
- system agree a 40px disc already exists and a landing page is still built from the one system (`08-choosing-components.md`'s
78
- method: find the existing piece before adding one).
71
+ - **44px for every act on a public page** (`14-accessibility.md`): the link was 20px tall on touch. Its hit area grows,
72
+ its words do not move.
73
+ - **A wrapped card keeps its column** (4 Nov 2026): the row was a wrapping flex row, so at 768px the third card ran the
74
+ full width under the other two. It is a grid now.
75
+ - **Links on one line across the row** (4 Nov 2026): the link sits on each card's foot, so a two-line title in one card
76
+ no longer drops its link below its neighbours'.
77
+ - The gap between the cards is `--layout-col-gap` (24px), the kit's own column gap.
78
+ - The title size, `--font-size-lg2` (20px), is the kit's "marketing small heading".
79
+ - The icon reuses the house `ws-disc` rather than a second disc shape.
79
80
 
80
81
  ## Source
81
82
 
82
- **Derived from**: `KitCard`, the system's own `ws-disc`, and the kit's layout gap and type-scale tokens
83
- (`layout-col-gap`, `font-size-lg2`, `font-size-md`). **Precedent**: an intentional addition decided from the
84
- system, 26 Oct 2026 (no product source and no kit component built this pattern before).
83
+ **Derived from**: `KitCard`, the house `ws-disc`, the kit's layout gap and type-scale tokens (`layout-col-gap`,
84
+ `font-size-lg2`, `font-size-md`), the touch floors and the geometry check at 390. **Precedent**: an intentional addition
85
+ decided from the system, 26 Oct 2026.
86
+
87
+ ## Markup
88
+
89
+ ```html
90
+ <section class="ws-feature-grid">
91
+ <div class="ws-feature-grid__grid">
92
+ <div class="ws-feature-grid__card">
93
+ <span class="ws-disc ws-feature-grid__icon" aria-hidden="true">
94
+ <svg viewBox="0 0 16 16" fill="none"><path d="M3 12V8M8 12V4M13 12V9.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
95
+ </span>
96
+ <h3 class="ws-feature-grid__title">Live call insights</h3>
97
+ <p class="ws-feature-grid__body">Every outreach call logged as it happens.</p>
98
+ <a class="ws-feature-grid__link" href="/insights">See how it works
99
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M5 11 11 5M5.5 5h5.5v5.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
100
+ </a>
101
+ </div>
102
+ </div>
103
+ </section>
104
+ ```
105
+
106
+ Styles: the `FeatureGrid` block (`components/FeatureGrid/style.css`); `ws-disc` is in `fello-core.css`.
@@ -1,6 +1,6 @@
1
- <!-- @dsCard group="Marketing" height=334 -->
1
+ <!-- @dsCard group="Marketing" height=306 -->
2
2
  <!doctype html>
3
- <html>
3
+ <html lang="en">
4
4
  <head>
5
5
  <meta charset="utf-8">
6
6
  <title>FeatureGrid</title>
@@ -0,0 +1,20 @@
1
+ /* ---- FeatureGrid: the kit's three feature cards in a row, wrapping to one column ---- */
2
+ .ws-feature-grid { background: var(--color-surface); width: 100%; padding: var(--space-xl) var(--layout-margin); }
3
+ /* A grid of columns at least 260 px wide: a card that wraps keeps its column's width instead of stretching across the row. */
4
+ .ws-feature-grid__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(var(--space-9xl) + var(--space-3xl) + var(--space-sm))), 1fr)); gap: var(--layout-col-gap); max-width: var(--layout-content-max); margin: 0 auto; }
5
+ .ws-feature-grid__card { display: flex; flex-direction: column; align-items: flex-start; min-width: 0; border-radius: var(--ws-radius-control); border: var(--ws-line) solid var(--color-border-default); background: var(--color-surface); padding: var(--space-lg); }
6
+ .ws-feature-grid__icon { width: var(--space-2xl); height: var(--space-2xl); }
7
+ .ws-feature-grid__icon svg { width: var(--ws-icon-lg); height: var(--ws-icon-lg); }
8
+ .ws-feature-grid__title { margin-top: var(--space-md); font-size: var(--font-size-lg2); font-weight: 600; line-height: var(--ws-leading-title); color: var(--color-text-heading); text-wrap: balance; overflow-wrap: break-word; }
9
+ .ws-feature-grid__body { margin-top: var(--space-xs); margin-bottom: var(--space-md); font-size: var(--font-size-md); line-height: var(--space-lg); color: var(--color-text-primary); }
10
+ /* The link sits at the card's foot, so cards of uneven copy still line their links up. */
11
+ .ws-feature-grid__link { position: relative; margin-top: auto; display: inline-flex; align-items: center; gap: var(--space-xxs); font-size: var(--font-size-sm); line-height: calc(var(--space-md) + var(--space-xxs)); font-weight: 500; color: var(--color-text-interactive); text-decoration: none; }
12
+ @media (hover: hover) { .ws-feature-grid__link:hover { text-decoration: underline; } }
13
+ .ws-feature-grid__link svg { width: var(--ws-icon-sm); height: var(--ws-icon-sm); }
14
+ /* Touch: the public page's 44 px target, as a hit area round the words so the card keeps its rhythm. */
15
+ @media (pointer: coarse) {
16
+ .ws-feature-grid__link::after { content: ""; position: absolute; inset: min(0px, calc((100% - var(--ws-touch-public)) / 2)) 0; }
17
+ }
18
+ @media (max-width: 40rem) {
19
+ .ws-feature-grid { padding-inline: var(--space-md); }
20
+ }
@@ -42,9 +42,11 @@ There is one size for the zone; it spans the width of its container.
42
42
  ## States
43
43
 
44
44
  - **Empty:** the dotted zone, its icon, words and the "Choose a file" button.
45
- - **Dragging over:** the zone's hairline edge turns `--color-brand-mid-blue`, the same colour `Input` uses for its own
46
- focus edge, since a drag-over is an active, not an error, state.
47
- - **Uploading:** a file row shows its `Meter` bar growing to the latest share.
45
+ - **Focus:** the "Choose a file" act takes the kit's ring when its file input is focused.
46
+ - **Dragging over:** the zone's edge turns a 1 px mid blue (`--color-text-interactive`), the kit's working colour, since
47
+ a drag-over is an active, not an error, state (the navy ring stays the focus mark).
48
+ - **Uploading:** a file row shows its `Meter` bar growing to the latest share; the bar is a `role="progressbar"` with
49
+ `aria-valuenow` and a label naming the file, so its share is heard, not only seen.
48
50
  - **Done:** the bar is replaced by a `--ws-word-positive` tick.
49
51
  - **Rejected:** the row shows its reason in `--ws-word-needs` words instead of a bar.
50
52
 
@@ -85,3 +87,31 @@ There is one size for the zone; it spans the width of its container.
85
87
 
86
88
  **Derived from**: the `.ws-dots` dotted field, `.ws-disc`, `Meter`'s progress bar, and `Button`'s secondary 32 px
87
89
  size. **Precedent**: an intentional addition decided from the system, 26 Oct 2026 (no file upload control existed).
90
+
91
+ ## Markup
92
+
93
+ ```html
94
+ <div class="ws-file-upload ws-dots">
95
+ <span class="ws-disc ws-file-upload__disc">...</span>
96
+ <p class="ws-body">Drop a file here, or</p>
97
+ <label class="ws-btn ws-btn--secondary">Choose a file <input type="file" accept=".png,.jpg,.jpeg,.pdf"></label>
98
+ <p class="ws-muted">PNG, JPG or PDF, up to 10 MB</p>
99
+ </div>
100
+ <div class="ws-file-upload__file">
101
+ <span class="ws-disc ws-file-upload__file-disc">...</span>
102
+ <div class="ws-file-upload__file-body">
103
+ <span class="ws-file-upload__file-name">lead-photo.jpg</span>
104
+ <span class="ws-file-upload__file-meta">
105
+ <span class="ws-file-upload__bar" role="progressbar" aria-label="Uploading lead-photo.jpg" aria-valuenow="64" aria-valuemin="0" aria-valuemax="100"><span class="ws-file-upload__bar-fill" style="width: 64%;"></span></span>
106
+ <span class="ws-file-upload__file-size">2.1 MB</span>
107
+ </span>
108
+ </div>
109
+ <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Remove lead-photo.jpg">...</button>
110
+ </div>
111
+ ```
112
+
113
+ ## Styles
114
+
115
+ `design-system/components/FileUpload/style.css`: `ws-file-upload` and `--drag`, `__disc`, `__file`, `__file-disc`,
116
+ `__file-body`, `__file-name`, `__file-meta`, `__file-size`, `__bar`, `__bar-fill`, `__done`, `__error`. The file input is
117
+ laid over its act, unseen, so the act takes its focus ring.
@@ -9,7 +9,7 @@
9
9
  </head>
10
10
  <body>
11
11
  <div class="ws-stage">
12
- <div style="display: grid; grid-template-columns: repeat(2, minmax(260px, 1fr)); gap: var(--ws-gap-component); width: 100%;">
12
+ <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: var(--ws-gap-component); width: 100%;">
13
13
 
14
14
  <div class="ws-stack">
15
15
  <span class="ws-muted">Empty</span>
@@ -20,7 +20,7 @@
20
20
  <p class="ws-body">Drop a file here, or</p>
21
21
  <label class="ws-btn ws-btn--secondary">
22
22
  Choose a file
23
- <input type="file" class="ws-sr">
23
+ <input type="file" accept=".png,.jpg,.jpeg,.pdf">
24
24
  </label>
25
25
  <p class="ws-muted">PNG, JPG or PDF, up to 10 MB</p>
26
26
  </div>
@@ -35,7 +35,7 @@
35
35
  <p class="ws-body">Drop a file here, or</p>
36
36
  <label class="ws-btn ws-btn--secondary">
37
37
  Choose a file
38
- <input type="file" class="ws-sr">
38
+ <input type="file" accept=".png,.jpg,.jpeg,.pdf">
39
39
  </label>
40
40
  <p class="ws-muted">PNG, JPG or PDF, up to 10 MB</p>
41
41
  </div>
@@ -48,7 +48,7 @@
48
48
  <div class="ws-file-upload__file-body">
49
49
  <span class="ws-file-upload__file-name">lead-photo.jpg</span>
50
50
  <span class="ws-file-upload__file-meta">
51
- <span class="ws-file-upload__bar" aria-hidden="true"><span class="ws-file-upload__bar-fill" style="width: 64%;"></span></span>
51
+ <span class="ws-file-upload__bar" role="progressbar" aria-label="Uploading lead-photo.jpg" aria-valuenow="64" aria-valuemin="0" aria-valuemax="100"><span class="ws-file-upload__bar-fill" style="width: 64%;"></span></span>
52
52
  <span class="ws-file-upload__file-size">2.1 MB</span>
53
53
  </span>
54
54
  </div>
@@ -85,6 +85,20 @@
85
85
  </div>
86
86
  </div>
87
87
 
88
+ <div class="ws-stack">
89
+ <span class="ws-muted">A long file name wraps beside its act</span>
90
+ <div class="ws-file-upload__file">
91
+ <span class="ws-disc ws-file-upload__file-disc"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="2" width="10" height="12" rx="1"/><path d="M6 6h4M6 9h4"/></svg></span>
92
+ <div class="ws-file-upload__file-body">
93
+ <span class="ws-file-upload__file-name">2026-10-buyer-consultation-notes-priya-nair-lakeview-estates.pdf</span>
94
+ <span class="ws-file-upload__done"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4 8.3l2.6 2.6L12 5.2"/></svg>1.4 MB, done</span>
95
+ </div>
96
+ <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Remove 2026-10-buyer-consultation-notes-priya-nair-lakeview-estates.pdf">
97
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8"/></svg>
98
+ </button>
99
+ </div>
100
+ </div>
101
+
88
102
  </div>
89
103
  </div>
90
104
  </body>
@@ -0,0 +1,23 @@
1
+ /* ---- FileUpload: a drop zone on the dotted field with one act, then a row a file with its progress, done or error.
2
+ The zone's edge is drawn inside; dragging over turns it mid blue at 1 px. The act is a label holding the file input
3
+ (laid over it, unseen), so it takes the focus ring when the input does. A long file name wraps, never pushes the
4
+ remove act out. ---- */
5
+ .ws-file-upload { display: flex; flex-direction: column; align-items: center; gap: var(--space-xs); padding: var(--space-lg); border-radius: var(--ws-radius-card); box-shadow: inset 0 0 0 var(--ws-hairline) var(--ws-edge-card); text-align: center; transition: box-shadow var(--ws-duration-hover) var(--ws-ease-soft); }
6
+ .ws-file-upload--drag { box-shadow: inset 0 0 0 var(--ws-line) var(--color-text-interactive); }
7
+ .ws-file-upload .ws-btn > input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
8
+ .ws-file-upload .ws-btn:has(> input:focus-visible) { outline: var(--ws-focus-width) solid var(--ws-focus-color); outline-offset: var(--ws-focus-offset); }
9
+ .ws-file-upload__disc { width: var(--space-2xl); height: var(--space-2xl); }
10
+ .ws-file-upload__disc svg { width: var(--ws-icon-lg); height: var(--ws-icon-lg); }
11
+ .ws-file-upload__file { display: flex; align-items: center; gap: var(--space-xs); padding: var(--space-xs) 0; }
12
+ .ws-file-upload__file-disc { width: var(--ws-control-h-sm); height: var(--ws-control-h-sm); flex-shrink: 0; }
13
+ .ws-file-upload__file-disc svg { width: var(--ws-icon-sm); height: var(--ws-icon-sm); }
14
+ .ws-file-upload__file-body { display: flex; flex: 1; min-width: 0; flex-direction: column; gap: var(--space-3xs); }
15
+ .ws-file-upload__file-name { font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); font-weight: 600; color: var(--color-text-heading); overflow-wrap: anywhere; }
16
+ .ws-file-upload__file-meta { display: flex; align-items: center; gap: var(--space-xs); }
17
+ .ws-file-upload__file-size { flex-shrink: 0; font-size: var(--ws-text-dense); line-height: var(--space-md); color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
18
+ .ws-file-upload__bar { flex: 1; height: var(--space-xxs); overflow: hidden; border-radius: var(--ws-radius-chip); background: var(--ws-track); }
19
+ .ws-file-upload__bar-fill { display: block; height: 100%; border-radius: inherit; background: var(--color-text-heading); transition: width var(--ws-duration-gentle) var(--ws-ease-soft); }
20
+ .ws-file-upload__done, .ws-file-upload__error { display: flex; align-items: center; gap: var(--space-xxs); font-size: var(--ws-text-dense); line-height: var(--space-md); }
21
+ .ws-file-upload__done { color: var(--ws-word-positive); }
22
+ .ws-file-upload__error { color: var(--ws-word-needs); }
23
+ .ws-file-upload__done svg, .ws-file-upload__error svg { width: var(--ws-icon-sm); height: var(--ws-icon-sm); flex-shrink: 0; }
@@ -0,0 +1,114 @@
1
+ A page's filters in one row: a period switch at the start and the pickers that scope the page at the end (North's
2
+ filter bar).
3
+
4
+ ## Use it when
5
+
6
+ - A dashboard or a report page is read for a period and a scope (this month, one team, one source), and every card on
7
+ the page answers to the same choice.
8
+ - The filters belong to the whole page, not to one chart or one list.
9
+
10
+ ## Not for
11
+
12
+ - A filter that belongs to one chart or one list: put it in that card's head (`Segmented --sm`, `Select --sm`).
13
+ - A search: use the search box (`Input`'s `ws-search`).
14
+ - A form's choices: use the fields.
15
+
16
+ ## Anatomy
17
+
18
+ - Bar: a row at least 28 px tall, two groups at the two ends (12 apart, 10 between lines when they wrap); a group that
19
+ wraps starts its own line at the left. It sizes from its own width, not the window's.
20
+ - Start group: the period, a `Segmented --sm` (a 28 px track, 24 px items, 12 / 16 words).
21
+ - End group: the pickers (`ws-filter-pick`), 8 apart: 28 px tall, 4 px corners, the surface with the 0.5 px card edge
22
+ drawn inside, 10 / 8 inside, 12 / 16 words: the label in the muted words, 6 px, then the value in navy medium, then a
23
+ 12 px navy chevron.
24
+ - Narrower than 76rem the pickers tighten (8 / 6 inside, 4 apart); narrower than 48rem their labels go and only the
25
+ values show (each picker's `aria-label` carries its label and value). Both steps read the bar's own width (a named
26
+ container), so a picker used outside a bar, in a list head or a detail, keeps North's 10 / 8 wherever it sits.
27
+
28
+ ## Variants and sizes
29
+
30
+ One size. The bar holds one period switch and up to four pickers; more than that is a sign the page asks too much.
31
+
32
+ ## States
33
+
34
+ - **Default:** each picker shows its label and its current value.
35
+ - **Hover (a mouse only):** a picker's edge darkens (#AAA49D), no fill.
36
+ - **Focus:** the kit's ring, 2 px navy, 2 px out, round the picker or the period item.
37
+ - **Pressed:** a picker gives to 0.97.
38
+ - **Open:** the picker's `aria-expanded="true"`, its `Menu` under it (8 below, from its corner), the chosen row showing
39
+ its tick (`ws-menu-item__tick` in every row; only the `aria-checked="true"` one shows).
40
+ - **Long value:** cut with an ellipsis, whole in the picker's `title`.
41
+ - **Narrow:** the groups wrap, each from the left; the labels go under 48rem.
42
+ - **Touch:** pickers and period items 40 tall.
43
+ - **Dark:** the surface, the edge and the words take their dark values.
44
+ - **Empty / loading / error:** not applicable; a filter always holds a value ("All teams" is a value).
45
+
46
+ ## Behaviour
47
+
48
+ - A picker is a `<button aria-haspopup="menu" aria-expanded>` opening a `Menu` of `menuitemradio`s; choosing one closes
49
+ it and updates the page.
50
+ - The period is a `Segmented` (buttons with `aria-pressed`, or links when the period lives in the URL).
51
+ - The bar is `role="group"` with an `aria-label` ("Filters").
52
+ - In North the bar docks into the top bar when the page scrolls under it; that belongs to the shell (`AppShell`).
53
+ - Motion: colours over the hover beat; the menu opens as `Menu`'s.
54
+
55
+ ## Content
56
+
57
+ - A picker's label is the dimension ("Team", "Source"), its value the choice ("All teams", "Zillow, Realtor.com").
58
+ - "All" values say what they cover ("All teams", not "All").
59
+ - No em dashes.
60
+
61
+ ## Props
62
+
63
+ | Name | Type | Meaning |
64
+ | --- | --- | --- |
65
+ | `period` | `SegmentedItem[]` | the period switch |
66
+ | `picks` | `{ key, label, value, options, onSelect }[]` | the pickers, at the end |
67
+ | `label` | `string` | the bar's name, default "Filters" |
68
+
69
+ ## Rules
70
+
71
+ - Page-wide filters live in one `FilterBar` at the top of the page, under its title (North; overturns 10-patterns.md's
72
+ "nothing page-wide looks like a filter").
73
+ - One period switch, at the start; pickers at the end.
74
+ - A picker never hides its label without an `aria-label` that carries it.
75
+
76
+ ## Source
77
+
78
+ **Derived from**: Seth's North (style1.css:417, :802-812, :1056-1060, :1081-1084): the 28 px filter bar, the filter
79
+ segmented, the label-and-value picker with its darker edge on hover, the 10 / 12 gaps, the tighter step and the hidden
80
+ label on a narrow page. North's 820 and 1120 px page steps snap to the kit's 48rem and 76rem container steps; its
81
+ #8A8A8A label (3.35:1) takes the muted words' AA step.
82
+
83
+ ## Markup
84
+
85
+ ```html
86
+ <div class="ws-filter-bar" role="group" aria-label="Filters">
87
+ <div class="ws-filter-bar__group">
88
+ <div class="ws-segmented ws-segmented--sm" role="group" aria-label="Period">
89
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Week</button>
90
+ <button type="button" class="ws-segmented__item" aria-pressed="true">Month</button>
91
+ </div>
92
+ </div>
93
+ <div class="ws-filter-bar__group">
94
+ <button type="button" class="ws-filter-pick" aria-haspopup="menu" aria-expanded="false" aria-label="Team: All teams" popovertarget="team-menu">
95
+ <span class="ws-filter-pick__label">Team</span><span class="ws-filter-pick__value">All teams</span>
96
+ <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 4.5l3 3 3-3"/></svg>
97
+ </button>
98
+ </div>
99
+ </div>
100
+ <!-- the picker's list: Menu's choice rows, the tick on the chosen one -->
101
+ <div id="team-menu" class="ws-menu" role="menu" aria-label="Team" popover>
102
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="true">All teams
103
+ <svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
104
+ </button>
105
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false">North region
106
+ <svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
107
+ </button>
108
+ </div>
109
+ ```
110
+
111
+ ## Styles
112
+
113
+ `design-system/components/FilterBar/style.css`: `ws-filter-bar`, `__group`, `ws-filter-pick`, `__label`, `__value`. The
114
+ period is `Segmented`'s `--sm`; the open picker's list is `Menu`.
@@ -0,0 +1,82 @@
1
+ <!-- @dsCard group="Navigation" height=380 -->
2
+ <!doctype html>
3
+ <html>
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <title>FilterBar</title>
7
+ <link rel="stylesheet" href="../../tokens.css">
8
+ <link rel="stylesheet" href="../bundle.css">
9
+ </head>
10
+ <body>
11
+ <div class="ws-stage ws-stage--column">
12
+
13
+ <div class="ws-stack">
14
+ <span class="ws-muted">A page's filters: the period at the start, the pickers at the end (28 px)</span>
15
+ <div class="ws-filter-bar" role="group" aria-label="Filters">
16
+ <div class="ws-filter-bar__group">
17
+ <div class="ws-segmented ws-segmented--sm" role="group" aria-label="Period">
18
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Week</button>
19
+ <button type="button" class="ws-segmented__item" aria-pressed="true">Month</button>
20
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Quarter</button>
21
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Year</button>
22
+ </div>
23
+ </div>
24
+ <div class="ws-filter-bar__group">
25
+ <button type="button" class="ws-filter-pick" aria-haspopup="menu" aria-expanded="false" aria-label="Team: All teams">
26
+ <span class="ws-filter-pick__label">Team</span><span class="ws-filter-pick__value">All teams</span>
27
+ <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 4.5l3 3 3-3"/></svg>
28
+ </button>
29
+ <button type="button" class="ws-filter-pick" aria-haspopup="menu" aria-expanded="false" aria-label="Source: Zillow, Realtor.com">
30
+ <span class="ws-filter-pick__label">Source</span><span class="ws-filter-pick__value">Zillow, Realtor.com</span>
31
+ <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 4.5l3 3 3-3"/></svg>
32
+ </button>
33
+ <button type="button" class="ws-filter-pick" aria-haspopup="menu" aria-expanded="false" aria-label="Agent: Anyone">
34
+ <span class="ws-filter-pick__label">Agent</span><span class="ws-filter-pick__value">Anyone</span>
35
+ <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 4.5l3 3 3-3"/></svg>
36
+ </button>
37
+ </div>
38
+ </div>
39
+ </div>
40
+
41
+ <!-- The open menu hangs 8 under its picker, left edges flush (it starts its line, so it flips to the side with room);
42
+ the stack keeps the room it covers, since a menu floats over what is below it. -->
43
+ <div class="ws-stack" style="width: 620px; max-width: 100%; padding-bottom: var(--space-8xl);">
44
+ <span class="ws-muted">In a narrower region: the groups wrap, each from the left, and the pickers show their values only; Team is open</span>
45
+ <div class="ws-filter-bar" role="group" aria-label="Filters, narrow">
46
+ <div class="ws-filter-bar__group">
47
+ <div class="ws-segmented ws-segmented--sm" role="group" aria-label="Period">
48
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Week</button>
49
+ <button type="button" class="ws-segmented__item" aria-pressed="true">Month</button>
50
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Quarter</button>
51
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Year</button>
52
+ </div>
53
+ </div>
54
+ <div class="ws-filter-bar__group">
55
+ <button type="button" class="ws-filter-pick" aria-haspopup="menu" aria-expanded="false" aria-label="Source: Zillow, Realtor.com and three more lead sources" title="Zillow, Realtor.com and three more lead sources">
56
+ <span class="ws-filter-pick__label">Source</span><span class="ws-filter-pick__value">Zillow, Realtor.com and three more lead sources</span>
57
+ <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 4.5l3 3 3-3"/></svg>
58
+ </button>
59
+ <span style="position: relative; display: inline-flex;">
60
+ <button type="button" class="ws-filter-pick" aria-haspopup="menu" aria-expanded="true" aria-controls="fb-team" aria-label="Team: All teams">
61
+ <span class="ws-filter-pick__label">Team</span><span class="ws-filter-pick__value">All teams</span>
62
+ <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 4.5l3 3 3-3"/></svg>
63
+ </button>
64
+ <div class="ws-menu" role="menu" id="fb-team" aria-label="Team" style="position: absolute; top: calc(100% + var(--space-xs)); left: 0;">
65
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="true">All teams
66
+ <svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
67
+ </button>
68
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false">North region
69
+ <svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
70
+ </button>
71
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false">South region
72
+ <svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
73
+ </button>
74
+ </div>
75
+ </span>
76
+ </div>
77
+ </div>
78
+ </div>
79
+
80
+ </div>
81
+ </body>
82
+ </html>
@@ -0,0 +1,22 @@
1
+ /* ---- FilterBar: North's page filters (0.5.0, D1; style1.css:417, :802-812): a period switch (Segmented --sm) and the
2
+ pickers that scope the page (FilterPick), 28 tall, the two groups at the two ends, 12 apart and 10 between lines
3
+ when they wrap; a wrapped group starts its own line at the left. It sizes from its own width: under 76rem the
4
+ pickers tighten, under 48rem their labels go and only the values show (each pick's aria-label carries its label and value). ---- */
5
+ .ws-filter-bar { container: ws-filter-bar / inline-size; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-xs-plus) var(--space-sm); min-height: var(--ws-control-h-sm); }
6
+ .ws-filter-bar__group { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-xs); min-width: 0; max-width: 100%; }
7
+ /* A picker: the label in the muted words, then the value in navy medium and a 12 px chevron; it opens a Menu. */
8
+ .ws-filter-pick { display: inline-flex; flex-shrink: 0; align-items: center; gap: var(--space-xxs-plus); max-width: 100%; height: var(--ws-control-h-sm); padding: 0 var(--space-xs) 0 var(--space-xs-plus); border: 0; border-radius: var(--ws-radius-control); background: var(--color-surface); box-shadow: var(--ws-shadow-hairline-in); color: var(--color-text-heading); font-size: var(--ws-text-dense); line-height: var(--space-md); white-space: nowrap; cursor: pointer; transition: box-shadow var(--ws-duration-hover) var(--ws-ease-soft), transform var(--ws-duration-hover) var(--ws-ease-soft); }
9
+ .ws-filter-pick__label { color: var(--color-text-muted); }
10
+ .ws-filter-pick__value { min-width: 0; overflow: hidden; text-overflow: ellipsis; font-weight: 500; }
11
+ .ws-filter-pick svg { flex-shrink: 0; width: var(--ws-icon-sm); height: var(--ws-icon-sm); }
12
+ @media (hover: hover) { .ws-filter-pick:hover { box-shadow: inset 0 0 0 var(--ws-hairline) var(--ws-edge-hover); } }
13
+ @media (prefers-reduced-motion: no-preference) { .ws-filter-pick:active { transform: scale(var(--ws-press-scale)); transition-duration: var(--ws-duration-instant); } }
14
+ /* The bar's own width (a named container: a picker outside a bar, in a list head or a detail, keeps North's 10 / 8 whatever
15
+ region it sits in). */
16
+ @container ws-filter-bar (max-width: 76rem) {
17
+ .ws-filter-bar__group { gap: var(--space-xxs-plus); }
18
+ .ws-filter-pick { gap: var(--space-xxs); padding: 0 var(--space-xxs-plus) 0 var(--space-xs); }
19
+ .ws-filter-bar .ws-segmented--sm .ws-segmented__item { padding: 0 var(--space-xs); }
20
+ }
21
+ @container ws-filter-bar (max-width: 48rem) { .ws-filter-pick__label { display: none; } }
22
+ @media (pointer: coarse) { .ws-filter-pick { min-height: var(--ws-touch); } }