@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,94 +1,139 @@
1
- Every switch and tab row on the platform: a cream track with a sliding navy thumb, one component so the thumb always
2
- slides the same way.
1
+ Every switch and tab row on the platform: Seth's grey well with a navy current item, one component so the current
2
+ item always moves the same way.
3
3
 
4
4
  ## Use it when
5
5
 
6
6
  - A view or a mode needs switching on one page (cold call, live transfer, follow-up; this week, this month, all time).
7
- - A set of panels needs real tabs (`tabs`, a `role="tablist"` with arrow-key navigation).
8
- - A switch must fill its box on a phone (`stretch`) or sit tight beside a chat (`dense`).
7
+ - A pane needs real tabs (`tabs`: a `role="tablist"` with arrow-key navigation), such as Seth's drawer tabs.
8
+ - A report's views carry a figure each (Seth's view tabs: "Your score 72"): `figures`.
9
+ - A page's period filter (`sm`, inside `FilterBar`) or a list head's filter (`clear`).
10
+ - A form's single choice among two to four short options (native radios inside the items).
9
11
 
10
12
  ## Not for
11
13
 
12
- - A form's single choice among several: use `Radio`/`RadioGroup` or `Select`.
13
- - An act that does something once, not a state the page remembers: use `Button`.
14
+ - A form's choice among many, or long options: use `Radio`/`RadioGroup` or `Select`.
15
+ - Five or more sections of one page: use `Tabs`.
16
+ - An act that does something once: use `Button`.
14
17
  - A removable or markable fact: use `Chip`.
15
18
 
16
19
  ## Anatomy
17
20
 
18
- - Track: `--ws-radius-row` (6px) corners, `--color-bg-page` (cream) ground, the fine hairline edge
19
- (`--ws-shadow-hairline`), 2px padding inside, 2px gap between items.
20
- - Item: `--ws-radius-control` (4px) corners, 28px tall, 12px medium words, `--space-sm` sides (tighter, `--space-xs`, when
21
- `dense`).
22
- - Current item: a navy (`--color-text-heading`) thumb that slides under the item (`layoutId`, a spring), white 12px
23
- medium words; the rest `--color-text-body`, navy on hover.
24
- - Icon (optional): 16px (`--space-md`), before the label.
25
- - Count (optional): a small pill after the label, white at 70% opacity on the current item.
21
+ - Track: the well (`--ws-well`, #EDEDED), no edge, 8 px corners (`--ws-radius-card`), 3 px inside (`--ws-halo`), items
22
+ 2 px apart (`--space-3xs`). It sits at its own width (a flex column never stretches it), never wider than its column:
23
+ past that it scrolls sideways inside and fades at the edge that hides items.
24
+ - Item: 32 px (`--ws-control-h`) tall, 12 px sides, 6 px corners (`--ws-radius-row`), 13 / 18 medium navy words, a 16 px
25
+ icon 6 px before them; 40 px on a touch screen. The track is 38 tall (46 on touch).
26
+ - Current item: navy (`--color-text-heading`) with `--ws-on-act` words.
27
+ - Count: the item's own words after the label ("Needs a reply 10", 8 apart), numerals even; or inline ("Fix · 2").
26
28
 
27
29
  ## Variants and sizes
28
30
 
29
31
  | Variant | What it looks like | Where |
30
32
  | --- | --- | --- |
31
- | Switch (default) | a `role="group"` of buttons, or a `nav` of links when every item has an `href` | a mode or filter kept on the page or in the URL |
32
- | `tabs` | a real `role="tablist"`, each item a `tab` with `aria-selected`, arrow keys and Home/End move and choose | a set of panels (the screen fades between them with `CrossFade`) |
33
- | `stretch` | each item an equal share of the width, full width on a phone (`stretch="always"`: at every width) | a switch inside a narrow card or a phone screen |
34
- | `quiet` | the current item wears a sunk cream thumb with heading words, not navy | a switch that sits beside the page's one primary button, so two navy things do not compete |
35
- | `pills` | separate half-clear cream pills instead of one track, the current one white with a navy outline and a lift | a page's own top-level tabs (the Team page) |
36
- | `dense` | tighter sides, for a row that must fit beside the chat | a narrow column |
33
+ | Switch (default) | the well track, buttons with `aria-pressed`, or links with `aria-current` | a mode or a filter kept on the page or in the URL |
34
+ | `tabs` | a real `role="tablist"`, each item a `tab` with `aria-selected` | a pane's sections (Seth's drawer tabs) |
35
+ | `--stretch` | each item an equal share of the width, never narrower than its words (past that the track scrolls) | a switch in a narrow card or on a phone |
36
+ | `--figures` | cream cells on the well, a name at the left (13 / 18 body grey) and a figure at the right (15 / 20 semibold navy), 40 tall, 10 / 14 inside; the current cell Seth's #2C4870; a row each when the track is too narrow for their names | a report's views, each with its number |
37
+ | `--clear` | no ground, so no side halo: the first and last items sit on the column's edges, in line with the rows; with `--stretch` | Seth's filter in a list head (Review inbox) |
38
+ | `--quiet` | the current item cream (`--ws-raised`) with navy words; in dark the tray a step lighter with the card edge inside, so it still shows on the dark well | beside the page's one navy act, so two navy things do not compete |
39
+ | `--sm` | North's filter size: a 28 px track on the surface with a 0.5 px edge inside, 2 in; items 24 tall, 10 sides, 4 px corners, 12 / 16 words | a page's period filter (`FilterBar`), the theme switch |
40
+ | `--dense` | 8 px sides | a row beside the chat |
41
+ | `__item--icon` | an icon alone, square (32; 28 by 24 in `sm`) with its name in `aria-label` | a chart's type, the theme switch |
42
+
43
+ `pills` (separate pills for the Team page's own top-level tabs) is a React-only look in the first product.
37
44
 
38
45
  ## States
39
46
 
40
- - **Default:** the track at rest, the current item's thumb in place.
41
- - **Hover:** a non-current item's words turn `--color-text-heading` (no fill change).
42
- - **Focus:** the kit's focus halo on the focused item.
43
- - **Pressed:** the item scales slightly on `active:scale`; the thumb itself only moves on a real selection change.
44
- - **Selected (current):** the navy thumb (or sunk, if `quiet`) with white or heading words, `aria-selected="true"` (tabs),
45
- `aria-pressed`/`aria-current` (a switch or links).
46
- - **Pending / loading:** not applicable; switching is instant, since it is a local or URL state, not a request.
47
- - **Disabled:** not a state the component defines; an item that cannot be chosen is left out rather than shown disabled.
48
- - **Error:** not applicable.
49
- - **Empty:** a group needs at least one item to mean anything; it is never rendered with zero.
50
- - **Long label:** the item's words truncate (`.truncate`) rather than push the track wider, except where a fixed width
51
- (`stretch="always"`) is not in play, in which case the track is left to grow.
52
- - **Narrow:** `stretch` makes every item an equal share of the available width on a phone.
53
- - **Touch:** the whole track grows to 40px tall (`--ws-touch`) on a touch screen.
47
+ - **Default:** the track at rest, the current item in place.
48
+ - **Hover (a mouse only):** a non-current item takes the navy wash (`--ws-hover`); a figure cell a wash over its cream.
49
+ - **Focus:** the kit's ring, drawn inside the item (the track is a dense row). On the current item the ring takes the
50
+ fill's words colour (`--ws-on-act`), 2 px further in, so it shows on the navy (a radio group's focus always sits on its
51
+ chosen item); on `--quiet` it stays navy.
52
+ - **Pressed:** nothing moves (North).
53
+ - **Selected (current):** navy with cream words; `aria-selected="true"` (tabs), `aria-pressed="true"` (a switch),
54
+ `aria-current` (links), or a checked radio inside.
55
+ - **Pending / loading:** not applicable; switching is instant (a local or URL state).
56
+ - **Disabled:** an item that cannot be chosen is usually left out; one that is coming (a disabled button, or a disabled
57
+ radio inside) shows at 40% and takes no hover.
58
+ - **Error / empty:** not applicable; a group is never rendered with no items.
59
+ - **Long label:** items keep one line; a track too wide for its column scrolls inside with the edge fade. `figures`
60
+ cells wrap their names.
61
+ - **Narrow:** `--stretch` shares the width; `figures` cells take a row each; past four items on a phone, use a `Select`.
62
+ - **Touch:** items 40 tall, icon items 40 wide.
63
+ - **Dark:** the well, the hover wash and the act take their dark values; the figure cells' current is the act.
54
64
 
55
65
  ## Behaviour
56
66
 
57
- - Keyboard: a switch is a normal button group (Tab moves between items); `tabs` is one stop for Tab, and the arrow keys
58
- (plus Home and End) move between tabs and choose as they go, per the ARIA tabs pattern.
59
- - Pointer / touch: tapping an item chooses it; the thumb slides to it.
60
- - Motion: the thumb slides on the "snappy" spring (`motionTokens.indicator`); interrupted mid-slide it turns toward the
61
- new choice rather than jumping. Reduced motion shows the thumb already in place with no sliding.
67
+ - Keyboard: a switch is a group of buttons (Tab moves between them); `tabs` is one Tab stop and the arrow keys (plus
68
+ Home and End) move and choose, per the ARIA tabs pattern; native radios move with the arrow keys on their own.
69
+ - Pointer / touch: tapping an item chooses it.
70
+ - Motion: the navy thumb slides to each new choice (North's "Toggle pill slide", `springs.indicator` .38 / .16), plain
71
+ CSS with no script and no new markup. The chosen item is a CSS anchor; the track's `::before` is the thumb, its four
72
+ edges easing on motion's own `spring(.38, .16)` written out as `linear()` (700 ms, a 0.8% give;
73
+ `--ws-spring-indicator-duration` and `--ws-spring-indicator`). At rest the chosen item paints its own ground (the 0.4 look
74
+ and the real ground for contrast tools); while the track is pointed at or holds focus the thumb takes over that
75
+ ground, so a choice made then slides, and a choice made in mid-flight turns toward the new item from where the thumb
76
+ is. A resize or a late font, away from the pointer, lands it at once. The words turn over 250 ms
77
+ (`--ws-duration-text`). Without CSS anchor positioning the ground moves at once; under reduced motion everything is
78
+ still. `--figures` keeps its cells (each has its own ground). Try it in the preview: click any item.
62
79
 
63
80
  ## Content
64
81
 
65
82
  - Short labels, sentence case, one or two words where possible ("Cold call", "This month").
66
- - A count beside a label is read as "(8)" to assistive tech, not spoken as part of the label itself.
67
- - No em dashes in a label.
83
+ - A count is read as part of the item ("Needs a reply, 10").
84
+ - No em dashes.
68
85
 
69
86
  ## Props
70
87
 
71
88
  | Name | Type | Meaning |
72
89
  | --- | --- | --- |
73
- | `label` | `string` | the group's own name (an `aria-label` on the switch or `nav`, the `aria-label` on `tablist`) |
74
- | `items` | `SegmentedItem[]` | `key`, `label`, `href` or `onSelect`, `current`, `icon?`, `count?`, `replace?`, `ariaLabel?`, `title?`, and (`tabs`) `id`/`controls` |
75
- | `tabs` | `boolean` | renders a real tab row instead of a switch |
90
+ | `label` | `string` | the group's own name (`aria-label` on the switch, the `nav` or the `tablist`) |
91
+ | `items` | `SegmentedItem[]` | `key`, `label`, `href` or `onSelect`, `current`, `icon?`, `count?`, `figure?`, `ariaLabel?`, `title?`, and (`tabs`) `id`/`controls` |
92
+ | `tabs` | `boolean` | a real tab row instead of a switch |
76
93
  | `stretch` | `boolean \| 'always'` | fills the width on a phone, or at every width |
77
- | `dense` | `boolean` | tighter sides for a narrow column |
78
- | `quiet` | `boolean` | a sunk thumb with heading words instead of navy |
79
- | `pills` | `boolean` | separate pills instead of one track |
94
+ | `size` | `'medium' \| 'small'` | `small` is the 28 px filter size |
95
+ | `figures` | `boolean` | Seth's view tabs |
96
+ | `clear`, `quiet`, `dense` | `boolean` | the looks above |
80
97
  | `className` | `string` | layout only |
81
98
 
82
99
  ## Rules
83
100
 
84
- - Every switch and tab row on the platform is `Segmented`, so the navy thumb always slides the same way; a screen never
85
- draws its own tabs (13 Oct 2026, the owner's call).
86
- - `tabs` is a real tablist: `role="tablist"`, each a `tab` with `aria-selected`, the arrow keys, Home and End moving
87
- between them and choosing as they go; a tab's panel fades in with `CrossFade`.
88
- - `quiet` exists so a switch never competes with the page's one navy primary button.
89
- - `pills` is the one place a switch is not a single track, for the Team page's own top-level tabs (23 Oct 2026).
101
+ - Every switch and tab row of two to four items is `Segmented`, so the current item always moves the same way; a screen
102
+ never draws its own (13 Oct 2026).
103
+ - `tabs` is a real tablist: `role="tablist"`, `tab`s with `aria-selected`, arrows, Home and End.
104
+ - The track is Seth's well (D1): #EDEDED, no edge, 8 / 6 corners, 3 in, 2 apart; the 0.4.0 cream track with a hairline
105
+ is gone.
106
+ - `--quiet` exists so a switch never competes with the page's one navy act.
107
+ - More than four items on a phone become a `Select`.
90
108
 
91
109
  ## Source
92
110
 
93
- **Derived from**: the system's rule that every switch and tab row shares one sliding-thumb component, and the ARIA
94
- tabs pattern for `tabs`. **Precedent**: the first product built on the system.
111
+ **Derived from**: Seth's well switch (Grow drawer tabs 301:2069; Review inbox filter 313:2737-2743: 3 in, 2 apart, 8 / 6
112
+ corners, 32 px items, 13 / 18 words, navy current with cream words) and his view tabs (301:1658: cream cells, a name and
113
+ a figure, the #2C4870 current). North's filter size (style1.css:804-808) for `sm` and its indicator spring. The geometry
114
+ check's fixes: the stretch in a flex column, the 0 px icons, the touch height.
115
+
116
+ ## Markup
117
+
118
+ ```html
119
+ <div class="ws-segmented" role="group" aria-label="Call kind">
120
+ <button type="button" class="ws-segmented__item" aria-pressed="true">Cold call</button>
121
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Live transfer</button>
122
+ </div>
123
+
124
+ <div class="ws-segmented ws-segmented--figures" role="tablist" aria-label="Audit report">
125
+ <button type="button" role="tab" aria-selected="true" class="ws-segmented__item">Your score<span class="ws-segmented__figure">72</span></button>
126
+ <button type="button" role="tab" aria-selected="false" tabindex="-1" class="ws-segmented__item">Compared against other teams<span class="ws-segmented__figure">1 of 5</span></button>
127
+ </div>
128
+
129
+ <div class="ws-segmented" role="radiogroup" aria-label="Call length">
130
+ <label class="ws-segmented__item"><input type="radio" name="len" value="30" checked>30 min</label>
131
+ <label class="ws-segmented__item"><input type="radio" name="len" value="60">An hour</label>
132
+ </div>
133
+ ```
134
+
135
+ ## Styles
136
+
137
+ `design-system/components/Segmented/style.css`: `ws-segmented` with `--stretch`, `--figures`, `--clear`, `--quiet`,
138
+ `--sm`, `--dense`; `ws-segmented__item` (and `--icon`), `__count`, `__figure`. The edge fade is the scroll-driven
139
+ `ws-scroll-edges` (shared with `Tabs`); touch heights come from the house's touch block.
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Actions" height=344 -->
1
+ <!-- @dsCard group="Actions" height=760 -->
2
2
  <!doctype html>
3
3
  <html>
4
4
  <head>
@@ -11,48 +11,129 @@
11
11
  <div class="ws-stage ws-stage--column">
12
12
 
13
13
  <div class="ws-stack">
14
- <span class="ws-muted">A three-item switch (a team's outreach card: Cold call chosen)</span>
14
+ <span class="ws-muted">The well switch: 3 px in, 2 apart, 32 px items, navy current (Seth's drawer tabs). Click any item on this page: the thumb slides to it on North's toggle pill spring</span>
15
15
  <div class="ws-segmented" role="group" aria-label="Call kind">
16
- <button type="button" class="ws-segmented__item" aria-selected="true" aria-current="true">Cold call</button>
17
- <button type="button" class="ws-segmented__item">Live transfer</button>
18
- <button type="button" class="ws-segmented__item">Follow-up</button>
16
+ <button type="button" class="ws-segmented__item" aria-pressed="true">Cold call</button>
17
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Live transfer</button>
18
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Follow-up</button>
19
19
  </div>
20
20
  </div>
21
21
 
22
22
  <div class="ws-stack">
23
- <span class="ws-muted">A tab row (role="tablist", arrow keys move between tabs)</span>
24
- <ul role="tablist" aria-label="Sections" class="ws-segmented">
25
- <li role="presentation"><button role="tab" id="tab-pipeline" aria-controls="panel-pipeline" aria-selected="true" tabindex="0" class="ws-segmented__item">Pipeline</button></li>
26
- <li role="presentation"><button role="tab" id="tab-activity" aria-controls="panel-activity" aria-selected="false" tabindex="-1" class="ws-segmented__item">Activity</button></li>
27
- <li role="presentation"><button role="tab" id="tab-reports" aria-controls="panel-reports" aria-selected="false" tabindex="-1" class="ws-segmented__item">Reports</button></li>
23
+ <span class="ws-muted">A tab row (role="tablist") with a count in the words</span>
24
+ <ul role="tablist" aria-label="Local search" class="ws-segmented">
25
+ <li role="presentation"><button role="tab" id="tab-where" aria-controls="panel-where" aria-selected="true" tabindex="0" class="ws-segmented__item">Where we checked</button></li>
26
+ <li role="presentation"><button role="tab" id="tab-why" aria-controls="panel-why" aria-selected="false" tabindex="-1" class="ws-segmented__item">Why</button></li>
27
+ <li role="presentation"><button role="tab" id="tab-fix" aria-controls="panel-fix" aria-selected="false" tabindex="-1" class="ws-segmented__item">Fix · 2</button></li>
28
+ <li role="presentation"><button role="tab" id="tab-found" aria-controls="panel-found" aria-selected="false" tabindex="-1" class="ws-segmented__item">Found</button></li>
28
29
  </ul>
29
30
  </div>
30
31
 
32
+ <div class="ws-stack" style="width: 360px; max-width: 100%;">
33
+ <span class="ws-muted">Stretched (equal shares), and clear: Seth's filter in a list head, no ground</span>
34
+ <div class="ws-segmented ws-segmented--stretch" role="group" aria-label="Report range">
35
+ <button type="button" class="ws-segmented__item" aria-pressed="false">This week</button>
36
+ <button type="button" class="ws-segmented__item" aria-pressed="true">This month</button>
37
+ <button type="button" class="ws-segmented__item" aria-pressed="false">All time</button>
38
+ </div>
39
+ <div class="ws-segmented ws-segmented--stretch ws-segmented--clear" role="group" aria-label="Reviews">
40
+ <button type="button" class="ws-segmented__item" aria-pressed="true">Needs a reply<span class="ws-segmented__count">10</span></button>
41
+ <button type="button" class="ws-segmented__item" aria-pressed="false">All<span class="ws-segmented__count">100</span></button>
42
+ </div>
43
+ </div>
44
+
31
45
  <div class="ws-stack">
32
- <span class="ws-muted">Stretched to fill a 320px box</span>
33
- <div style="width: 320px; max-width: 100%;">
34
- <div class="ws-segmented ws-segmented--stretch" role="group" aria-label="Report range">
35
- <button type="button" class="ws-segmented__item">This week</button>
36
- <button type="button" class="ws-segmented__item" aria-selected="true" aria-current="true">This month</button>
37
- <button type="button" class="ws-segmented__item">All time</button>
46
+ <span class="ws-muted">Figures: Seth's view tabs (a name at the left, its figure at the right; a row each when narrow)</span>
47
+ <div class="ws-segmented ws-segmented--figures" role="tablist" aria-label="Audit report">
48
+ <button type="button" role="tab" aria-selected="true" class="ws-segmented__item">Your score<span class="ws-segmented__figure">72</span></button>
49
+ <button type="button" role="tab" aria-selected="false" tabindex="-1" class="ws-segmented__item">Compared against other teams<span class="ws-segmented__figure">1 of 5</span></button>
50
+ <button type="button" role="tab" aria-selected="false" tabindex="-1" class="ws-segmented__item">Which AI platforms mention you<span class="ws-segmented__figure">10 of 16</span></button>
51
+ </div>
52
+ </div>
53
+
54
+ <div class="ws-cluster ws-cluster--loose ws-cluster--start">
55
+ <div class="ws-stack">
56
+ <span class="ws-muted">Small: North's filter size (28 px track)</span>
57
+ <div class="ws-segmented ws-segmented--sm" role="group" aria-label="Period">
58
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Week</button>
59
+ <button type="button" class="ws-segmented__item" aria-pressed="true">Month</button>
60
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Quarter</button>
61
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Year</button>
62
+ </div>
63
+ </div>
64
+ <div class="ws-stack">
65
+ <span class="ws-muted">Quiet (beside the page's navy act)</span>
66
+ <div class="ws-segmented ws-segmented--quiet" role="group" aria-label="Show">
67
+ <button type="button" class="ws-segmented__item" aria-pressed="true">Open</button>
68
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Done</button>
69
+ </div>
70
+ </div>
71
+ <div class="ws-stack">
72
+ <span class="ws-muted">Dense (8 px sides), with an item that cannot be chosen yet (40%)</span>
73
+ <div class="ws-segmented ws-segmented--dense" role="group" aria-label="Reply as">
74
+ <button type="button" class="ws-segmented__item" aria-pressed="true">Text</button>
75
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Email</button>
76
+ <button type="button" class="ws-segmented__item" aria-pressed="false" disabled>Voice</button>
77
+ </div>
78
+ </div>
79
+ <div class="ws-stack">
80
+ <span class="ws-muted">With icons, and icons alone</span>
81
+ <div class="ws-cluster">
82
+ <div class="ws-segmented" role="group" aria-label="View">
83
+ <button type="button" class="ws-segmented__item" aria-pressed="true">
84
+ <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="2" y="2" width="5" height="5" rx="1"/><rect x="9" y="2" width="5" height="5" rx="1"/><rect x="2" y="9" width="5" height="5" rx="1"/><rect x="9" y="9" width="5" height="5" rx="1"/></svg>
85
+ Board
86
+ </button>
87
+ <button type="button" class="ws-segmented__item" aria-pressed="false">
88
+ <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="M2 4h12M2 8h12M2 12h12"/></svg>
89
+ List
90
+ </button>
91
+ </div>
92
+ <div class="ws-segmented" role="group" aria-label="Chart">
93
+ <button type="button" class="ws-segmented__item ws-segmented__item--icon" aria-pressed="true" aria-label="Bars" title="Bars">
94
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M4 13V8M8 13V3M12 13V6"/></svg>
95
+ </button>
96
+ <button type="button" class="ws-segmented__item ws-segmented__item--icon" aria-pressed="false" aria-label="Line" title="Line">
97
+ <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="M2 12l4-4 3 2 5-6"/></svg>
98
+ </button>
99
+ </div>
38
100
  </div>
39
101
  </div>
40
102
  </div>
41
103
 
42
104
  <div class="ws-stack">
43
- <span class="ws-muted">With icons</span>
44
- <div class="ws-segmented" role="group" aria-label="View">
45
- <button type="button" class="ws-segmented__item" aria-selected="true" aria-current="true">
46
- <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="2" y="2" width="5" height="5" rx="1"/><rect x="9" y="2" width="5" height="5" rx="1"/><rect x="2" y="9" width="5" height="5" rx="1"/><rect x="9" y="9" width="5" height="5" rx="1"/></svg>
47
- Board
48
- </button>
49
- <button type="button" class="ws-segmented__item">
50
- <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="M2 4h12M2 8h12M2 12h12"/></svg>
51
- List
52
- </button>
105
+ <span class="ws-muted">A form's choice: native radios inside the items (arrow keys move the choice)</span>
106
+ <div class="ws-segmented" role="radiogroup" aria-label="Call length">
107
+ <label class="ws-segmented__item"><input type="radio" name="len" value="15">15 min</label>
108
+ <label class="ws-segmented__item"><input type="radio" name="len" value="30" checked>30 min</label>
109
+ <label class="ws-segmented__item"><input type="radio" name="len" value="60">An hour</label>
110
+ </div>
111
+ </div>
112
+
113
+ <div class="ws-stack" style="width: 300px; max-width: 100%;">
114
+ <span class="ws-muted">Too many for its column: the track scrolls inside (on a phone, past four, use a Select)</span>
115
+ <div class="ws-segmented" role="group" aria-label="Stage">
116
+ <button type="button" class="ws-segmented__item" aria-pressed="false">New</button>
117
+ <button type="button" class="ws-segmented__item" aria-pressed="true">Quote sent</button>
118
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Signed</button>
119
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Closed won</button>
120
+ <button type="button" class="ws-segmented__item" aria-pressed="false">Closed lost</button>
53
121
  </div>
54
122
  </div>
55
123
 
56
124
  </div>
125
+ <script>
126
+ /* The demo's wiring: a click chooses the item (an app keeps the choice; the kit only draws it, and the thumb slides on
127
+ its own). The radios choose themselves. */
128
+ document.addEventListener('click', (e) => {
129
+ const item = e.target.closest('button.ws-segmented__item');
130
+ const attr = item && !item.disabled && ['aria-pressed', 'aria-selected', 'aria-current'].find((a) => item.hasAttribute(a));
131
+ if (!attr) return;
132
+ for (const i of item.closest('.ws-segmented').querySelectorAll('.ws-segmented__item')) {
133
+ i.setAttribute(attr, String(i === item));
134
+ if (attr === 'aria-selected') i.tabIndex = i === item ? 0 : -1;
135
+ }
136
+ });
137
+ </script>
57
138
  </body>
58
139
  </html>
@@ -0,0 +1,94 @@
1
+ /* ---- Segmented: Seth's well switch (0.5.0, D1; 301:2069, 313:2737): the #EDEDED well with no edge, 8 px corners, 3 px
2
+ inside, items 2 apart, 32 tall, 6 px corners, 13 / 18 medium navy words; the current item navy with cream words. It
3
+ sits at its own width (a flex column never stretches it), never wider than its column (it scrolls inside, never
4
+ clipping its inset focus ring). Restates the house's Segmented block, so that copy can go. ---- */
5
+ .ws-segmented { display: inline-flex; align-self: flex-start; max-width: 100%; overflow-x: auto; scrollbar-width: none; padding: var(--ws-halo); gap: var(--space-3xs); border-radius: var(--ws-radius-card); background: var(--ws-well); box-shadow: none; }
6
+ .ws-segmented::-webkit-scrollbar { display: none; }
7
+ /* Wider than its column, the track fades at the edge that hides items (the house ws-scroll-edges fade; nothing when it fits). */
8
+ @supports (animation-timeline: scroll()) {
9
+ .ws-segmented { mask-image: linear-gradient(90deg, transparent, currentColor var(--ws-fade-start), currentColor calc(100% - var(--ws-fade-end)), transparent); animation: ws-scroll-edges linear; animation-timeline: scroll(self inline); }
10
+ }
11
+ .ws-segmented > li { display: flex; }
12
+ .ws-segmented__item { position: relative; display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; gap: var(--space-xxs-plus); height: var(--ws-control-h); padding: 0 var(--space-sm); border: 0; border-radius: var(--ws-radius-row); background-color: transparent; color: var(--color-text-heading); font-size: var(--ws-text-control); line-height: var(--ws-leading-control); font-weight: 500; white-space: nowrap; cursor: pointer; }
13
+ .ws-segmented__item svg { flex-shrink: 0; width: var(--ws-icon); height: var(--ws-icon); }
14
+ /* A count inside an item ("Fix · 2", "Needs a reply 10"): the item's own words, 8 from the label, numerals even. */
15
+ .ws-segmented__count { margin-inline-start: var(--space-3xs); font-variant-numeric: tabular-nums; }
16
+ /* An item can hold a native radio (a form's choice, the theme switch): the label is the target, the input is hidden. */
17
+ .ws-segmented__item > input { position: absolute; width: var(--ws-line); height: var(--ws-line); margin: 0; opacity: 0; pointer-events: none; }
18
+ .ws-segmented__item:has(> input:focus-visible) { outline: var(--ws-focus-width) solid var(--ws-focus-color); outline-offset: calc(var(--ws-focus-width) * -1); }
19
+ @media (hover: hover) {
20
+ .ws-segmented__item:not(:where(:disabled, :has(> input:disabled))):hover { background-color: var(--ws-hover); color: var(--color-text-heading); }
21
+ }
22
+ /* The current item paints its own ground over the hover beat. Where the browser anchors (Motion, at the end), one thumb
23
+ under the items paints it instead and slides to each new choice. */
24
+ .ws-segmented__item[aria-selected="true"], .ws-segmented__item[aria-current]:not([aria-current="false"]), .ws-segmented__item[aria-checked="true"], .ws-segmented__item[aria-pressed="true"], .ws-segmented__item:has(> input:checked) { background-color: var(--color-text-heading); color: var(--ws-on-act); }
25
+ .ws-segmented__item:has(> input:disabled), .ws-segmented__item:disabled { opacity: 0.4; cursor: not-allowed; }
26
+ /* Focus on the current item: a navy ring on a navy fill would vanish (and a radio group's focus always sits on its
27
+ chosen item), so the ring there is the fill's own words colour, 2 px further in. */
28
+ .ws-segmented__item:is([aria-selected="true"], [aria-current]:not([aria-current="false"]), [aria-checked="true"], [aria-pressed="true"]):focus-visible, .ws-segmented__item:has(> input:checked:focus-visible) { outline-color: var(--ws-on-act); outline-offset: calc(var(--ws-focus-width) * -2); }
29
+
30
+ /* stretch: equal shares of the width, never narrower than an item's words (past that the track scrolls). clear: no
31
+ ground (Seth's filter in a list head). quiet: the current item cream (the raised ground, so it still shows on the
32
+ dark well) with navy words, beside the page's one navy act. dense: tighter sides beside the chat. */
33
+ .ws-segmented--stretch { display: flex; align-self: stretch; }
34
+ .ws-segmented--stretch > * { flex: 1 1 0; }
35
+ /* A clear track has no ground to hold its 3 px halo, so the halo keeps only its height: the first and last items sit on
36
+ the column's edges, in line with the rows and words above and below (Seth's track p 3 with no fill showed only as a
37
+ 3 px miss). */
38
+ .ws-segmented--clear { padding-inline: 0; background: transparent; }
39
+ .ws-segmented--dense .ws-segmented__item { padding: 0 var(--space-xs); }
40
+ /* In dark the raised ground is barely off the well (1.14:1), so there the chosen item takes the tray, a step lighter,
41
+ with the card edge inside it (derived: Seth draws only light). */
42
+ .ws-segmented--quiet { --ws-segmented-quiet: var(--ws-raised); --ws-segmented-quiet-edge: transparent; }
43
+ [data-theme="dark"] .ws-segmented--quiet { --ws-segmented-quiet: var(--ws-tray); --ws-segmented-quiet-edge: var(--ws-edge-card); }
44
+ @media (prefers-color-scheme: dark) { [data-theme="system"] .ws-segmented--quiet { --ws-segmented-quiet: var(--ws-tray); --ws-segmented-quiet-edge: var(--ws-edge-card); } }
45
+ .ws-segmented--quiet .ws-segmented__item:is([aria-selected="true"], [aria-current]:not([aria-current="false"]), [aria-checked="true"], [aria-pressed="true"], :has(> input:checked)) { background-color: var(--ws-segmented-quiet); box-shadow: inset 0 0 0 var(--ws-hairline) var(--ws-segmented-quiet-edge); color: var(--color-text-heading); }
46
+ .ws-segmented--quiet .ws-segmented__item:is([aria-selected="true"], [aria-current]:not([aria-current="false"]), [aria-checked="true"], [aria-pressed="true"]):focus-visible, .ws-segmented--quiet .ws-segmented__item:has(> input:checked:focus-visible) { outline-color: var(--ws-focus-color); outline-offset: calc(var(--ws-focus-width) * -1); }
47
+ /* sm: North's filter size (style1.css:804): a 28 px track on the surface with the 0.5 px edge inside, 2 in, items
48
+ 24 tall, 10 sides, 4 px corners, 12 / 16 words. */
49
+ .ws-segmented--sm { padding: var(--space-3xs); border-radius: var(--ws-radius-row); background: var(--color-surface); box-shadow: var(--ws-shadow-hairline-in); }
50
+ .ws-segmented--sm .ws-segmented__item { height: var(--space-lg); padding: 0 var(--space-xs-plus); border-radius: var(--ws-radius-control); font-size: var(--ws-text-dense); line-height: var(--space-md); }
51
+ /* An item that is an icon alone (its name in aria-label): square, 32 (28 by 24 in sm). */
52
+ .ws-segmented__item--icon { width: var(--ws-control-h); padding: 0; }
53
+ .ws-segmented--sm .ws-segmented__item--icon { width: var(--ws-control-h-sm); padding: 0; }
54
+
55
+ /* figures: Seth's view tabs (301:1658): each item a cream cell, its name at the left (13 / 18 body grey) and its figure
56
+ at the right (15 / 20 semibold navy), 40 tall, 10 / 14 inside. The current cell is Seth's #2C4870 (light; the act in
57
+ dark) with cream words. Cells wrap to a row each when the track is too narrow for three names. */
58
+ .ws-segmented--figures { display: flex; flex-wrap: wrap; align-self: stretch; overflow: visible; mask-image: none; animation: none; }
59
+ .ws-segmented--figures > * { flex: 1 1 var(--space-9xl); min-width: 0; }
60
+ .ws-segmented--figures .ws-segmented__item { justify-content: space-between; gap: var(--space-sm); height: auto; min-height: var(--space-2xl); padding: var(--space-xs-plus) var(--space-sm-plus); background-color: var(--ws-raised); color: var(--color-text-body); white-space: normal; text-align: start; }
61
+ .ws-segmented__figure { flex-shrink: 0; font-size: var(--ws-text-section); line-height: var(--ws-leading-row); font-weight: 600; color: var(--color-text-heading); font-variant-numeric: tabular-nums; white-space: nowrap; }
62
+ @media (hover: hover) {
63
+ .ws-segmented--figures .ws-segmented__item:hover { background-image: linear-gradient(var(--ws-hover), var(--ws-hover)); }
64
+ }
65
+ .ws-segmented--figures .ws-segmented__item:is([aria-selected="true"], [aria-current]:not([aria-current="false"]), [aria-checked="true"], [aria-pressed="true"], :has(> input:checked)) { background-color: var(--ws-agent-tally); background-image: none; color: var(--ws-on-act); }
66
+ .ws-segmented--figures .ws-segmented__item:is([aria-selected="true"], [aria-current]:not([aria-current="false"]), [aria-checked="true"], [aria-pressed="true"], :has(> input:checked)) .ws-segmented__figure { color: inherit; }
67
+ @media (pointer: coarse) { .ws-segmented__item--icon, .ws-segmented--sm .ws-segmented__item--icon { min-width: var(--ws-touch); } }
68
+
69
+ /* ---- Motion: North's "Toggle pill slide" (springs.indicator, .38 / .16; north-motion 3). A thumb slides to each new
70
+ choice instead of the ground jumping from item to item. The chosen item is the anchor (CSS anchor positioning) and
71
+ the track's ::before is the thumb, under the items, its four edges easing on motion's own spring(.38, .16) written
72
+ out as linear() (motion's toString: 700 ms, a 0.8% give). At rest the chosen item paints its own ground, so a resting
73
+ track is the 0.4 track pixel for pixel (and every contrast tool reads the real ground); while the track is pointed at
74
+ or holds focus the thumb takes over that ground (the same box, the same paint, at once), so a choice made then
75
+ slides. Only a real choice moves it (North: the pill moves only on a real selection); a resize or a late font, away
76
+ from the pointer, lands at once. No new markup, so a 0.4 track slides too. Without anchor positioning, or under
77
+ reduced motion, the ground moves at once. --figures keeps its cells: each has its own ground. The words turn over
78
+ 250 ms (North css:150).
79
+ The spring is the global --ws-spring-indicator over --ws-spring-indicator-duration. ---- */
80
+ @supports (anchor-name: --a) {
81
+ .ws-segmented:not(.ws-segmented--figures) { position: relative; anchor-scope: --ws-segmented-thumb; }
82
+ .ws-segmented:not(.ws-segmented--figures)::before { content: ""; position: absolute; position-anchor: --ws-segmented-thumb; inset: anchor(top) anchor(right) anchor(bottom) anchor(left); border-radius: var(--ws-radius-row); background: var(--color-text-heading); opacity: 0; pointer-events: none; }
83
+ .ws-segmented--sm:not(.ws-segmented--figures)::before { border-radius: var(--ws-radius-control); }
84
+ .ws-segmented--quiet:not(.ws-segmented--figures)::before { background: var(--ws-segmented-quiet); box-shadow: inset 0 0 0 var(--ws-hairline) var(--ws-segmented-quiet-edge); }
85
+ .ws-segmented:not(.ws-segmented--figures) .ws-segmented__item:is([aria-selected="true"], [aria-current]:not([aria-current="false"]), [aria-checked="true"], [aria-pressed="true"], :has(> input:checked)) { anchor-name: --ws-segmented-thumb; }
86
+ }
87
+ @media (prefers-reduced-motion: no-preference) {
88
+ .ws-segmented__item { transition: background-color var(--ws-duration-hover) var(--ws-ease-soft), color var(--ws-duration-text) var(--ws-ease-soft); }
89
+ @supports (anchor-name: --a) {
90
+ .ws-segmented:not(.ws-segmented--figures):is(:hover, :focus-within)::before { opacity: 1; transition: inset var(--ws-spring-indicator-duration) var(--ws-spring-indicator); }
91
+ .ws-segmented:not(.ws-segmented--figures):is(:hover, :focus-within) .ws-segmented__item:is([aria-selected="true"], [aria-current]:not([aria-current="false"]), [aria-checked="true"], [aria-pressed="true"], :has(> input:checked)) { background-color: transparent; box-shadow: none; }
92
+ .ws-segmented:not(.ws-segmented--figures) .ws-segmented__item:is([aria-selected="true"], [aria-current]:not([aria-current="false"]), [aria-checked="true"], [aria-pressed="true"], :has(> input:checked)) { transition: color var(--ws-duration-text) var(--ws-ease-soft); }
93
+ }
94
+ }
@@ -0,0 +1,64 @@
1
+ Progress split by area and by step: Seth's "1 of 6" figure, a line under it, and one bar of segments with each area named.
2
+
3
+ **Use it when**
4
+
5
+ - A checklist's progress has a few areas, each with its own steps (fixes by Website, Social, Local search), and the
6
+ page opens on how far along the whole thing is.
7
+ - The reader should see both the total ("1 of 6") and where the done steps are.
8
+
9
+ **Not for**
10
+
11
+ - One share with no areas: use `TickStrip` or `Meter`.
12
+ - Ordered steps someone walks through: use `Stepper`.
13
+ - A score: use `ScoreHero`.
14
+
15
+ **Anatomy**
16
+
17
+ - A column, 6 apart (`--space-xxs-plus`): the figure (`ws-figure ws-figure--pane`, 44/48 regular navy, proportional
18
+ numerals so its ink sits on the bar's edge), the line (14/20 `--color-text-body`), the areas.
19
+ - Areas: equal columns 12 apart, at least 96 wide, so on a narrow column they wrap onto the same columns (16 between
20
+ rows). Each area is a `TickStrip --bar` (one segment a step: 12 tall, 4 apart, 2 px corners; done teal, the rest the
21
+ track) and 8 under it its label (13/18 medium `--color-text-muted`, one line, a `title` when it can truncate).
22
+
23
+ **States**
24
+
25
+ - Default: done segments in teal.
26
+ - Draw (`--draw` on a strip, `--i` on each lit segment): segments rise in as the card's draw.
27
+ - Nothing done: every segment the track; the figure says "0 of 6".
28
+ - Long label: truncates with its `title`.
29
+ - Reduced motion: in place.
30
+ - Hover, focus: none; each area's list below the bar is where people act.
31
+
32
+ **Behaviour**
33
+
34
+ - The `<section>` carries `aria-label` with the total and each area ("1 of 6 fixes done: Website 0 of 2 ..."); the
35
+ areas are `aria-hidden`.
36
+
37
+ **Rules**
38
+
39
+ - Areas keep the order of the list below them, so the bar is a map of the page.
40
+ - Equal widths, whatever each area's count (Seth's frame holds two a group, so a width by count is unknown).
41
+ - One tone: done is teal; there is no partial tone.
42
+
43
+ **Source**
44
+
45
+ **Seth**: Fixes checklist, "Progress by area" (308:2481 to 308:2501): figure, line and bar 6 apart, areas 12 apart,
46
+ segments 4 apart and 12 tall, labels 8 under.
47
+
48
+ **Markup**
49
+
50
+ ```html
51
+ <section class="ws-segmented-progress" aria-label="1 of 6 fixes done: Website 0 of 2, Social 1 of 2, Local search 0 of 2">
52
+ <p class="ws-figure ws-figure--pane">1 of 6</p>
53
+ <p class="ws-segmented-progress__line">From your Nov 2 audit.</p>
54
+ <div class="ws-segmented-progress__areas" aria-hidden="true">
55
+ <div class="ws-segmented-progress__area">
56
+ <div class="ws-tick-strip ws-tick-strip--bar" style="--n: 2;"><span class="ws-tick-strip__tick ws-tick-strip__tick--on"></span><span class="ws-tick-strip__tick"></span></div>
57
+ <span class="ws-segmented-progress__label">Social</span>
58
+ </div>
59
+ </div>
60
+ </section>
61
+ ```
62
+
63
+ **Styles**: `SegmentedProgress/style.css` (with `TickStrip/style.css`), in `bundle.css` and `fello.css` as
64
+ `.ws-segmented-progress`. Every value is a token.