@felloinnovations/brand-kit 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/AGENTS.md +198 -24
  2. package/CHANGELOG.md +197 -0
  3. package/README.md +34 -7
  4. package/design-system/01-how-claude-decides.md +26 -17
  5. package/design-system/02-principles.md +11 -6
  6. package/design-system/03-colour.md +134 -47
  7. package/design-system/04-type.md +45 -23
  8. package/design-system/05-space-and-layout.md +175 -52
  9. package/design-system/06-sizing-profiles.md +4 -4
  10. package/design-system/07-scrolling.md +66 -20
  11. package/design-system/08-choosing-components.md +50 -22
  12. package/design-system/09-charts.md +71 -28
  13. package/design-system/10-patterns.md +33 -10
  14. package/design-system/11-page-recipes.md +110 -23
  15. package/design-system/12-content.md +2 -1
  16. package/design-system/13-motion.md +330 -47
  17. package/design-system/14-accessibility.md +47 -24
  18. package/design-system/15-ai-experiences.md +11 -6
  19. package/design-system/16-creativity.md +1 -1
  20. package/design-system/17-decisions.md +357 -1
  21. package/design-system/18-checklist.md +79 -16
  22. package/design-system/19-public-pages.md +6 -4
  23. package/design-system/20-palettes.md +275 -0
  24. package/design-system/README.md +30 -17
  25. package/design-system/components/ActionList/README.md +96 -10
  26. package/design-system/components/ActionList/preview.html +52 -7
  27. package/design-system/components/ActionList/style.css +64 -0
  28. package/design-system/components/ActivityGrid/README.md +38 -2
  29. package/design-system/components/ActivityGrid/preview.html +1 -1
  30. package/design-system/components/ActivityGrid/style.css +35 -0
  31. package/design-system/components/AppShell/README.md +205 -75
  32. package/design-system/components/AppShell/preview.html +339 -58
  33. package/design-system/components/AppShell/style.css +154 -0
  34. package/design-system/components/Avatar/README.md +37 -10
  35. package/design-system/components/Avatar/preview.html +13 -4
  36. package/design-system/components/Avatar/style.css +14 -0
  37. package/design-system/components/Badge/README.md +41 -19
  38. package/design-system/components/Badge/preview.html +13 -10
  39. package/design-system/components/Badge/style.css +23 -0
  40. package/design-system/components/Banner/README.md +30 -9
  41. package/design-system/components/Banner/preview.html +1 -1
  42. package/design-system/components/Banner/style.css +19 -0
  43. package/design-system/components/Breadcrumb/README.md +58 -46
  44. package/design-system/components/Breadcrumb/preview.html +16 -16
  45. package/design-system/components/Breadcrumb/style.css +17 -0
  46. package/design-system/components/Button/README.md +113 -55
  47. package/design-system/components/Button/preview.html +98 -25
  48. package/design-system/components/Button/style.css +86 -0
  49. package/design-system/components/Card/README.md +158 -49
  50. package/design-system/components/Card/preview.html +141 -19
  51. package/design-system/components/Card/style.css +115 -0
  52. package/design-system/components/CardBoard/README.md +58 -37
  53. package/design-system/components/CardBoard/preview.html +26 -29
  54. package/design-system/components/ChatCard/README.md +115 -29
  55. package/design-system/components/ChatCard/preview.html +149 -32
  56. package/design-system/components/ChatCard/style.css +49 -0
  57. package/design-system/components/ChatShell/README.md +116 -0
  58. package/design-system/components/ChatShell/preview.html +201 -0
  59. package/design-system/components/ChatShell/style.css +86 -0
  60. package/design-system/components/ChatTurn/README.md +78 -35
  61. package/design-system/components/ChatTurn/preview.html +60 -28
  62. package/design-system/components/ChatTurn/style.css +50 -0
  63. package/design-system/components/CheckRow/README.md +141 -0
  64. package/design-system/components/CheckRow/preview.html +140 -0
  65. package/design-system/components/CheckRow/style.css +88 -0
  66. package/design-system/components/Checkbox/README.md +58 -22
  67. package/design-system/components/Checkbox/preview.html +112 -50
  68. package/design-system/components/Checkbox/style.css +45 -0
  69. package/design-system/components/Chip/README.md +78 -47
  70. package/design-system/components/Chip/preview.html +29 -4
  71. package/design-system/components/Chip/style.css +17 -0
  72. package/design-system/components/Combobox/README.md +44 -11
  73. package/design-system/components/Combobox/preview.html +35 -12
  74. package/design-system/components/Combobox/style.css +54 -0
  75. package/design-system/components/Composer/README.md +137 -35
  76. package/design-system/components/Composer/preview.html +115 -40
  77. package/design-system/components/Composer/style.css +81 -0
  78. package/design-system/components/ConfirmDialog/README.md +73 -52
  79. package/design-system/components/ConfirmDialog/preview.html +70 -26
  80. package/design-system/components/ConfirmDialog/style.css +5 -0
  81. package/design-system/components/Cover/preview.html +3 -3
  82. package/design-system/components/Cover/style.css +19 -0
  83. package/design-system/components/DateInput/README.md +77 -12
  84. package/design-system/components/DateInput/preview.html +27 -12
  85. package/design-system/components/DateInput/style.css +38 -0
  86. package/design-system/components/Dialog/README.md +112 -44
  87. package/design-system/components/Dialog/preview.html +141 -18
  88. package/design-system/components/Dialog/style.css +74 -0
  89. package/design-system/components/EmptyState/README.md +42 -12
  90. package/design-system/components/EmptyState/preview.html +11 -11
  91. package/design-system/components/EmptyState/style.css +9 -0
  92. package/design-system/components/EntryShell/README.md +73 -48
  93. package/design-system/components/EntryShell/preview.html +60 -27
  94. package/design-system/components/EntryShell/style.css +19 -0
  95. package/design-system/components/FeatureGrid/README.md +61 -39
  96. package/design-system/components/FeatureGrid/preview.html +2 -2
  97. package/design-system/components/FeatureGrid/style.css +20 -0
  98. package/design-system/components/FileUpload/README.md +33 -3
  99. package/design-system/components/FileUpload/preview.html +18 -4
  100. package/design-system/components/FileUpload/style.css +23 -0
  101. package/design-system/components/FilterBar/README.md +114 -0
  102. package/design-system/components/FilterBar/preview.html +82 -0
  103. package/design-system/components/FilterBar/style.css +22 -0
  104. package/design-system/components/Fold/README.md +84 -26
  105. package/design-system/components/Fold/preview.html +77 -34
  106. package/design-system/components/Fold/style.css +48 -0
  107. package/design-system/components/Footer/README.md +62 -39
  108. package/design-system/components/Footer/preview.html +5 -5
  109. package/design-system/components/Footer/style.css +30 -0
  110. package/design-system/components/FunnelBars/README.md +24 -3
  111. package/design-system/components/FunnelBars/preview.html +5 -5
  112. package/design-system/components/FunnelBars/style.css +13 -0
  113. package/design-system/components/GoalBars/README.md +54 -10
  114. package/design-system/components/GoalBars/preview.html +69 -28
  115. package/design-system/components/GoalBars/style.css +51 -0
  116. package/design-system/components/GoalTicks/README.md +74 -58
  117. package/design-system/components/GoalTicks/preview.html +41 -118
  118. package/design-system/components/GoalTicks/style.css +37 -0
  119. package/design-system/components/GoalTubes/README.md +29 -3
  120. package/design-system/components/GoalTubes/preview.html +6 -6
  121. package/design-system/components/GoalTubes/style.css +23 -0
  122. package/design-system/components/Heatmap/README.md +133 -0
  123. package/design-system/components/Heatmap/preview.html +168 -0
  124. package/design-system/components/Heatmap/style.css +119 -0
  125. package/design-system/components/Hero/README.md +58 -40
  126. package/design-system/components/Hero/preview.html +1 -1
  127. package/design-system/components/Hero/style.css +19 -0
  128. package/design-system/components/HoverCard/README.md +114 -0
  129. package/design-system/components/HoverCard/preview.html +107 -0
  130. package/design-system/components/HoverCard/style.css +59 -0
  131. package/design-system/components/IconButton/README.md +69 -38
  132. package/design-system/components/IconButton/preview.html +77 -43
  133. package/design-system/components/IconButton/style.css +45 -0
  134. package/design-system/components/Input/README.md +36 -11
  135. package/design-system/components/Input/preview.html +1 -1
  136. package/design-system/components/Input/style.css +23 -0
  137. package/design-system/components/KanbanBoard/README.md +93 -45
  138. package/design-system/components/KanbanBoard/preview.html +159 -43
  139. package/design-system/components/KanbanBoard/style.css +53 -0
  140. package/design-system/components/Kbd/README.md +25 -9
  141. package/design-system/components/Kbd/preview.html +6 -2
  142. package/design-system/components/Kbd/style.css +9 -0
  143. package/design-system/components/KitButton/README.md +81 -47
  144. package/design-system/components/KitButton/preview.html +35 -13
  145. package/design-system/components/KitButton/style.css +46 -0
  146. package/design-system/components/KitCard/README.md +75 -44
  147. package/design-system/components/KitCard/preview.html +18 -10
  148. package/design-system/components/KitCard/style.css +15 -0
  149. package/design-system/components/KitInput/README.md +54 -39
  150. package/design-system/components/KitInput/preview.html +7 -7
  151. package/design-system/components/KitInput/style.css +23 -0
  152. package/design-system/components/Leaderboard/README.md +76 -49
  153. package/design-system/components/Leaderboard/preview.html +61 -26
  154. package/design-system/components/Leaderboard/style.css +44 -0
  155. package/design-system/components/ListDetail/README.md +222 -0
  156. package/design-system/components/ListDetail/preview.html +213 -0
  157. package/design-system/components/ListDetail/style.css +148 -0
  158. package/design-system/components/LoadBar/README.md +79 -0
  159. package/design-system/components/LoadBar/preview.html +40 -0
  160. package/design-system/components/LoadBar/style.css +17 -0
  161. package/design-system/components/MarketingNav/README.md +76 -42
  162. package/design-system/components/MarketingNav/preview.html +37 -8
  163. package/design-system/components/MarketingNav/style.css +45 -0
  164. package/design-system/components/Matrix/README.md +129 -0
  165. package/design-system/components/Matrix/preview.html +99 -0
  166. package/design-system/components/Matrix/style.css +84 -0
  167. package/design-system/components/Menu/README.md +117 -41
  168. package/design-system/components/Menu/preview.html +85 -23
  169. package/design-system/components/Menu/style.css +61 -0
  170. package/design-system/components/Meter/README.md +39 -4
  171. package/design-system/components/Meter/preview.html +18 -1
  172. package/design-system/components/Meter/style.css +23 -0
  173. package/design-system/components/MetricTile/README.md +237 -0
  174. package/design-system/components/MetricTile/preview.html +241 -0
  175. package/design-system/components/MetricTile/style.css +129 -0
  176. package/design-system/components/Morph/README.md +106 -0
  177. package/design-system/components/Morph/preview.html +103 -0
  178. package/design-system/components/Morph/style.css +31 -0
  179. package/design-system/components/Motion/README.md +164 -0
  180. package/design-system/components/Motion/preview.html +2537 -0
  181. package/design-system/components/NumberInput/README.md +27 -8
  182. package/design-system/components/NumberInput/preview.html +21 -5
  183. package/design-system/components/NumberInput/style.css +34 -0
  184. package/design-system/components/PaceBar/README.md +75 -0
  185. package/design-system/components/PaceBar/preview.html +67 -0
  186. package/design-system/components/PaceBar/style.css +25 -0
  187. package/design-system/components/Page/README.md +57 -18
  188. package/design-system/components/Page/preview.html +15 -17
  189. package/design-system/components/Page/style.css +7 -0
  190. package/design-system/components/PageBar/README.md +90 -34
  191. package/design-system/components/PageBar/preview.html +60 -19
  192. package/design-system/components/PageBar/style.css +35 -0
  193. package/design-system/components/PageHero/README.md +87 -51
  194. package/design-system/components/PageHero/preview.html +35 -6
  195. package/design-system/components/PageHero/style.css +31 -0
  196. package/design-system/components/Pagination/README.md +70 -49
  197. package/design-system/components/Pagination/preview.html +24 -15
  198. package/design-system/components/Pagination/style.css +12 -0
  199. package/design-system/components/Panel/README.md +109 -51
  200. package/design-system/components/Panel/preview.html +118 -20
  201. package/design-system/components/Panel/style.css +51 -0
  202. package/design-system/components/PasswordInput/README.md +50 -18
  203. package/design-system/components/PasswordInput/preview.html +71 -21
  204. package/design-system/components/PasswordInput/style.css +31 -0
  205. package/design-system/components/Plate/README.md +75 -17
  206. package/design-system/components/Plate/preview.html +40 -7
  207. package/design-system/components/Plate/style.css +37 -0
  208. package/design-system/components/Popover/README.md +70 -49
  209. package/design-system/components/Popover/preview.html +44 -22
  210. package/design-system/components/Popover/style.css +41 -0
  211. package/design-system/components/PricingTable/README.md +69 -49
  212. package/design-system/components/PricingTable/preview.html +21 -21
  213. package/design-system/components/PricingTable/style.css +21 -0
  214. package/design-system/components/ProgressPetals/README.md +31 -3
  215. package/design-system/components/ProgressPetals/preview.html +14 -15
  216. package/design-system/components/ProgressPetals/style.css +27 -0
  217. package/design-system/components/README.md +151 -0
  218. package/design-system/components/Radio/README.md +40 -17
  219. package/design-system/components/Radio/preview.html +16 -1
  220. package/design-system/components/Radio/style.css +21 -0
  221. package/design-system/components/RankBar/README.md +29 -2
  222. package/design-system/components/RankBar/preview.html +14 -12
  223. package/design-system/components/RankBar/style.css +18 -0
  224. package/design-system/components/Ring/README.md +61 -11
  225. package/design-system/components/Ring/preview.html +55 -10
  226. package/design-system/components/Ring/style.css +49 -0
  227. package/design-system/components/ScoreHero/README.md +91 -0
  228. package/design-system/components/ScoreHero/preview.html +104 -0
  229. package/design-system/components/ScoreHero/style.css +32 -0
  230. package/design-system/components/Section/README.md +72 -33
  231. package/design-system/components/Section/preview.html +46 -16
  232. package/design-system/components/Section/style.css +18 -0
  233. package/design-system/components/Segmented/README.md +100 -55
  234. package/design-system/components/Segmented/preview.html +107 -26
  235. package/design-system/components/Segmented/style.css +94 -0
  236. package/design-system/components/SegmentedProgress/README.md +64 -0
  237. package/design-system/components/SegmentedProgress/preview.html +69 -0
  238. package/design-system/components/SegmentedProgress/style.css +11 -0
  239. package/design-system/components/Select/README.md +47 -12
  240. package/design-system/components/Select/preview.html +28 -2
  241. package/design-system/components/Select/style.css +22 -0
  242. package/design-system/components/ShareBar/README.md +69 -0
  243. package/design-system/components/ShareBar/preview.html +72 -0
  244. package/design-system/components/ShareBar/style.css +25 -0
  245. package/design-system/components/SideList/README.md +147 -0
  246. package/design-system/components/SideList/preview.html +139 -0
  247. package/design-system/components/SideList/style.css +94 -0
  248. package/design-system/components/Skeleton/README.md +52 -16
  249. package/design-system/components/Skeleton/preview.html +35 -23
  250. package/design-system/components/Skeleton/style.css +22 -0
  251. package/design-system/components/Slider/README.md +95 -0
  252. package/design-system/components/Slider/preview.html +49 -0
  253. package/design-system/components/Slider/style.css +13 -0
  254. package/design-system/components/Split/README.md +112 -0
  255. package/design-system/components/Split/preview.html +105 -0
  256. package/design-system/components/Split/style.css +30 -0
  257. package/design-system/components/Starter/README.md +21 -9
  258. package/design-system/components/Starter/preview.html +5 -5
  259. package/design-system/components/Stat/README.md +64 -43
  260. package/design-system/components/Stat/preview.html +3 -3
  261. package/design-system/components/Stat/style.css +15 -0
  262. package/design-system/components/StatTiles/README.md +88 -44
  263. package/design-system/components/StatTiles/preview.html +142 -71
  264. package/design-system/components/StatTiles/style.css +64 -0
  265. package/design-system/components/StatusLine/README.md +85 -0
  266. package/design-system/components/StatusLine/preview.html +49 -0
  267. package/design-system/components/StatusLine/style.css +14 -0
  268. package/design-system/components/StatusScreen/README.md +49 -35
  269. package/design-system/components/StatusScreen/preview.html +20 -5
  270. package/design-system/components/StatusScreen/style.css +9 -0
  271. package/design-system/components/StepLine/README.md +97 -0
  272. package/design-system/components/StepLine/preview.html +108 -0
  273. package/design-system/components/StepLine/style.css +62 -0
  274. package/design-system/components/Stepper/README.md +35 -13
  275. package/design-system/components/Stepper/style.css +13 -0
  276. package/design-system/components/StreakCalendar/README.md +22 -1
  277. package/design-system/components/StreakCalendar/preview.html +10 -10
  278. package/design-system/components/StreakCalendar/style.css +12 -0
  279. package/design-system/components/SuggestionChip/README.md +87 -0
  280. package/design-system/components/SuggestionChip/preview.html +42 -0
  281. package/design-system/components/SuggestionChip/style.css +20 -0
  282. package/design-system/components/Switch/README.md +44 -24
  283. package/design-system/components/Switch/preview.html +23 -8
  284. package/design-system/components/Switch/style.css +31 -0
  285. package/design-system/components/Table/README.md +129 -58
  286. package/design-system/components/Table/preview.html +106 -72
  287. package/design-system/components/Table/style.css +104 -0
  288. package/design-system/components/Tabs/README.md +71 -46
  289. package/design-system/components/Tabs/preview.html +56 -24
  290. package/design-system/components/Tabs/style.css +44 -0
  291. package/design-system/components/Testimonial/README.md +48 -32
  292. package/design-system/components/Testimonial/preview.html +14 -14
  293. package/design-system/components/Testimonial/style.css +12 -0
  294. package/design-system/components/TextArea/README.md +27 -11
  295. package/design-system/components/TextArea/preview.html +8 -2
  296. package/design-system/components/TextArea/style.css +12 -0
  297. package/design-system/components/ThemeSwitch/README.md +116 -0
  298. package/design-system/components/ThemeSwitch/preview.html +57 -0
  299. package/design-system/components/ThemeSwitch/style.css +6 -0
  300. package/design-system/components/TickRow/README.md +52 -36
  301. package/design-system/components/TickRow/preview.html +64 -41
  302. package/design-system/components/TickRow/style.css +23 -0
  303. package/design-system/components/TickStrip/README.md +95 -0
  304. package/design-system/components/TickStrip/preview.html +88 -0
  305. package/design-system/components/TickStrip/style.css +42 -0
  306. package/design-system/components/Tile/README.md +79 -18
  307. package/design-system/components/Tile/preview.html +91 -40
  308. package/design-system/components/Tile/style.css +36 -0
  309. package/design-system/components/Timeline/README.md +68 -48
  310. package/design-system/components/Timeline/preview.html +27 -15
  311. package/design-system/components/Timeline/style.css +25 -0
  312. package/design-system/components/Toast/README.md +70 -38
  313. package/design-system/components/Toast/preview.html +43 -8
  314. package/design-system/components/Toast/style.css +25 -0
  315. package/design-system/components/Tooltip/README.md +93 -35
  316. package/design-system/components/Tooltip/preview.html +69 -15
  317. package/design-system/components/Tooltip/style.css +78 -0
  318. package/design-system/components/TopBar/README.md +67 -53
  319. package/design-system/components/TopBar/preview.html +14 -27
  320. package/design-system/components/TopBar/style.css +35 -0
  321. package/design-system/components/TopicRail/README.md +108 -0
  322. package/design-system/components/TopicRail/preview.html +58 -0
  323. package/design-system/components/TopicRail/style.css +48 -0
  324. package/design-system/components/TrendBars/README.md +52 -14
  325. package/design-system/components/TrendBars/preview.html +65 -32
  326. package/design-system/components/TrendBars/style.css +25 -0
  327. package/design-system/components/TrendLine/README.md +164 -0
  328. package/design-system/components/TrendLine/preview.html +373 -0
  329. package/design-system/components/TrendLine/style.css +155 -0
  330. package/design-system/components/Well/README.md +64 -22
  331. package/design-system/components/Well/preview.html +14 -14
  332. package/design-system/components/Well/style.css +22 -0
  333. package/design-system/components/_house.css +324 -0
  334. package/design-system/components/bundle.css +4091 -744
  335. package/design-system/tokens.json +1314 -124
  336. package/dist/fello-core.css +2 -2
  337. package/dist/fello.css +6 -1369
  338. package/dist/fello.scoped.css +7 -0
  339. package/dist/index.d.ts +110 -11
  340. package/dist/index.js +781 -96
  341. package/dist/palettes.d.ts +464 -0
  342. package/dist/palettes.js +497 -0
  343. package/dist/scoped.d.ts +3 -0
  344. package/dist/scoped.js +16 -0
  345. package/dist/toast.d.ts +14 -0
  346. package/dist/toast.js +33 -29
  347. package/dist/tokens.d.ts +1686 -62
  348. package/dist/tokens.js +1668 -61
  349. package/package.json +20 -4
  350. package/scripts/check-palette.mjs +295 -0
  351. package/scripts/token-model.mjs +552 -0
  352. package/tokens/_dark.css +174 -0
  353. package/tokens/_palettes.css +46 -0
  354. package/tokens/_product.css +266 -53
  355. package/tokens/_source.hubl.css +39 -19
  356. package/tokens/design-tokens.json +319 -0
  357. package/tokens/palettes.ts +504 -0
  358. package/tokens/shadcn-compat.css +19 -19
  359. package/tokens/shadcn-compat.hsl.css +76 -0
  360. package/tokens/tokens.css +1292 -62
  361. package/tokens/tokens.md +588 -61
  362. package/tokens/tokens.root.css +1298 -62
  363. package/tokens/tokens.ts +1677 -64
@@ -0,0 +1,84 @@
1
+ /* ---- Matrix: Seth's answers grid (305:2341). A yes-or-no answer for each question (a row) and each source (a column),
2
+ in a rim: one column template shared by the head and every row (20 in, 16 out, a 200 px question column, equal
3
+ columns 2 apart), so the heads centre over their cells. Hovering or focusing a row dims every other row to 0.2 and
4
+ shows the whole question in a navy note over it. Under 40rem the question column takes the room and the source names
5
+ drop to their marks. ---- */
6
+ .ws-matrix { --ws-matrix-cols: 4; --ws-matrix-first: var(--space-9xl); --ws-matrix-cell: minmax(0, 1fr); --ws-matrix-dim: 0.2; container: ws-matrix / inline-size; display: flex; flex-direction: column; padding: var(--ws-rim); border-radius: var(--ws-radius-card); background: var(--ws-tray); }
7
+ .ws-matrix__table { display: flex; flex-direction: column; }
8
+ .ws-matrix__row { display: grid; grid-template-columns: var(--ws-matrix-first) repeat(var(--ws-matrix-cols), var(--ws-matrix-cell)); column-gap: var(--space-3xs); min-height: var(--ws-row-h); padding: var(--ws-line) var(--space-md) var(--ws-line) var(--ws-card-inset); background: var(--color-bg-page); }
9
+ /* Rows are joined by 0.5 px lines, full width, drawn inside the row's top (Seth's 48 includes its line, so a border would
10
+ add 0.5 a row); the rim's inner corners on the first and last row. */
11
+ .ws-matrix__body > .ws-matrix__row, .ws-matrix__foot { box-shadow: inset 0 var(--ws-hairline) 0 var(--ws-edge); }
12
+ .ws-matrix__head > .ws-matrix__row { border-radius: var(--ws-radius-card-inner) var(--ws-radius-card-inner) 0 0; }
13
+ .ws-matrix__table:last-child .ws-matrix__body > .ws-matrix__row:last-child, .ws-matrix__foot { border-radius: 0 0 var(--ws-radius-card-inner) var(--ws-radius-card-inner); }
14
+ /* Head: 16 above and below; "Question" in 13 / 18 medium muted; each source a 20 px mark and its name, 15 / 22 semibold,
15
+ centred over its column (the head cell carries the name as its aria-label too). */
16
+ .ws-matrix__head > .ws-matrix__row { align-items: center; padding-block: var(--space-md); }
17
+ .ws-matrix__corner { font-size: var(--ws-text-control); line-height: var(--ws-leading-control); font-weight: 500; color: var(--color-text-muted); text-align: left; }
18
+ .ws-matrix__col { display: flex; align-items: center; justify-content: center; gap: var(--space-xs); min-width: 0; font-size: var(--ws-text-section); line-height: var(--ws-leading-section); font-weight: 600; color: var(--color-text-heading); }
19
+ .ws-matrix__mark { flex-shrink: 0; width: var(--ws-icon-lg); height: var(--ws-icon-lg); }
20
+ .ws-matrix__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
21
+ /* The question: 14 / 20 medium navy with a 1 px dotted underline, the cue that the whole question shows on hover or focus. */
22
+ .ws-matrix__q-cell { display: flex; align-items: center; min-width: 0; padding-right: var(--space-md); }
23
+ .ws-matrix__q-wrap { position: relative; display: inline-flex; min-width: 0; }
24
+ .ws-matrix__q { min-width: 0; padding: 0; border: 0; background: none; font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); font-weight: 500; color: var(--color-text-heading); text-align: left; text-decoration: underline dotted var(--ws-line); text-underline-offset: var(--ws-halo); cursor: help; }
25
+ /* On touch the question's box grows to 24 without moving a thing. */
26
+ @media (pointer: coarse) { .ws-matrix__q { padding-block: var(--space-3xs); margin-block: calc(var(--space-3xs) * -1); } }
27
+ /* A cell: the row's height less its 1 px in, 2 px corners; named = the strong tone, not named = the empty track; the
28
+ source's mark centred in it (a dimmed mark on the empty track). Its words are for a screen reader. */
29
+ .ws-matrix__cell { display: flex; align-items: center; justify-content: center; min-height: calc(var(--ws-row-h) - var(--ws-line) * 2); border-radius: var(--ws-radius-chip); background: var(--ws-track); color: var(--color-text-heading); }
30
+ .ws-matrix__cell--yes { background: var(--ws-rating-strong); }
31
+ /* In dark the strong tone is a light teal, so the mark on it takes the ground's dark (navy on teal in light). */
32
+ [data-theme="dark"] .ws-matrix__cell--yes { color: var(--color-bg-page); }
33
+ @media (prefers-color-scheme: dark) { [data-theme="system"] .ws-matrix__cell--yes { color: var(--color-bg-page); } }
34
+ .ws-matrix__cell:not(.ws-matrix__cell--yes) > .ws-matrix__mark { opacity: var(--ws-dim); }
35
+ .ws-matrix__cell.ws-shimmer { background: var(--ws-shimmer); background-size: 300% 100%; }
36
+ /* The note (Seth's navy tip): the act fill, 4 px corners, 14 / 20 words that wrap at 300 (the note 324 with its 12 px
37
+ sides, as Tooltip --note), left-anchored so its words start on the question's, a 12 x 6 caret over the word, 3 above
38
+ it. No shadow. */
39
+ .ws-matrix__tip { position: absolute; z-index: 1; left: calc(var(--space-sm) * -1); bottom: calc(100% + var(--ws-halo) + var(--space-xxs-plus)); width: max-content; max-width: min(calc(var(--ws-float-width) + var(--space-sm) * 2), calc(100cqi - var(--space-lg))); padding: var(--space-xs-plus) var(--space-sm); border-radius: var(--ws-radius-control); background: var(--color-text-heading); color: var(--ws-on-act); font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); font-weight: 400; text-align: left; white-space: normal; visibility: hidden; opacity: 0; pointer-events: none; }
40
+ .ws-matrix__tip::after { content: ""; position: absolute; top: 100%; left: calc(var(--space-lg) + var(--space-xxs-plus)); width: var(--space-sm); height: var(--space-xxs-plus); background: inherit; clip-path: polygon(0 0, 100% 0, 50% 100%); }
41
+ .ws-matrix__q:focus + .ws-matrix__tip, .ws-matrix__q[aria-expanded="true"] + .ws-matrix__tip { visibility: visible; opacity: 1; }
42
+ /* Keyboard focus draws the ring 4 px round the question: the note's caret keeps its 3 px clear of the ring, not the word. */
43
+ .ws-matrix__q:focus-visible + .ws-matrix__tip { bottom: calc(100% + var(--ws-focus-offset) + var(--ws-focus-width) + var(--ws-halo) + var(--space-xxs-plus)); }
44
+ /* Focusing (or tapping) a row dims the others, as hover does. Row grounds, lines, the head and the foot stay. */
45
+ .ws-matrix__body:has(> .ws-matrix__row:focus-within) > .ws-matrix__row:not(:focus-within) > * { opacity: var(--ws-matrix-dim); }
46
+ @media (hover: hover) {
47
+ .ws-matrix__body > .ws-matrix__row:hover .ws-matrix__tip { visibility: visible; opacity: 1; }
48
+ .ws-matrix__body:has(> .ws-matrix__row:hover) > .ws-matrix__row:not(:hover) > * { opacity: var(--ws-matrix-dim); }
49
+ }
50
+ /* The note covers the row above, so Escape must hide it without moving the pointer (WCAG 1.4.13): a page script sets
51
+ data-tip="hidden" on the row and clears it when the pointer or focus leaves. */
52
+ .ws-matrix__body > .ws-matrix__row[data-tip="hidden"] .ws-matrix__tip { visibility: hidden; opacity: 0; }
53
+ /* Motion: the dim and the note fade on hover's 200 ms after a 40 ms intent; the note leaves on the 120 ms exit. */
54
+ @media (prefers-reduced-motion: no-preference) {
55
+ .ws-matrix__row > * { transition: opacity var(--ws-duration-hover) var(--ws-ease-soft); }
56
+ .ws-matrix__tip { transition: opacity var(--ws-duration-exit) var(--ws-ease-exit), visibility 0s linear var(--ws-duration-exit); }
57
+ .ws-matrix__q:focus + .ws-matrix__tip, .ws-matrix__q[aria-expanded="true"] + .ws-matrix__tip { transition: opacity var(--ws-duration-hover) var(--ws-ease-soft) var(--ws-hover-intent), visibility 0s linear var(--ws-hover-intent); }
58
+ }
59
+ @media (hover: hover) and (prefers-reduced-motion: no-preference) {
60
+ .ws-matrix__body > .ws-matrix__row:hover .ws-matrix__tip { transition: opacity var(--ws-duration-hover) var(--ws-ease-soft) var(--ws-hover-intent), visibility 0s linear var(--ws-hover-intent); }
61
+ }
62
+ /* Foot (Seth's "Behind the answers"): a folded row in the rim, 16 above and below, title, line, chevron. */
63
+ .ws-matrix__foot { background: var(--color-bg-page); }
64
+ .ws-matrix__foot > summary { display: flex; align-items: center; gap: var(--space-sm); padding: var(--space-md) var(--space-md) var(--space-md) var(--ws-card-inset); border-radius: inherit; list-style: none; cursor: pointer; }
65
+ .ws-matrix__foot > summary::-webkit-details-marker { display: none; }
66
+ .ws-matrix__foot > summary:focus-visible { outline-offset: calc(var(--ws-focus-width) * -1); }
67
+ .ws-matrix__foot-title { flex: none; font-size: var(--ws-text-section); line-height: var(--ws-leading-section); font-weight: 600; color: var(--color-text-heading); }
68
+ .ws-matrix__foot-line { flex: 1; min-width: 0; font-size: var(--ws-text-control); line-height: var(--ws-leading-control); font-weight: 500; color: var(--color-text-muted); }
69
+ .ws-matrix__foot > summary > svg { flex-shrink: 0; width: var(--ws-icon); height: var(--ws-icon); color: var(--color-text-heading); }
70
+ .ws-matrix__foot[open] > summary > svg { transform: rotate(180deg); }
71
+ .ws-matrix__foot-body { padding: 0 var(--space-md) var(--space-md) var(--ws-card-inset); }
72
+ @media (prefers-reduced-motion: no-preference) { .ws-matrix__foot > summary > svg { transition: transform var(--ws-duration-settle) var(--ws-ease-soft); } }
73
+ /* Narrow: the question column takes the room, each source column 32 wide and only its mark (the head cell's aria-label
74
+ names it, so a screen reader still hears the source); the question 8 from the cells. The foot's line drops under its
75
+ title, the chevron staying at the end of the title's line. */
76
+ @container ws-matrix (max-width: 40rem) {
77
+ .ws-matrix__row { grid-template-columns: minmax(0, 1fr) repeat(var(--ws-matrix-cols), var(--space-xl)); }
78
+ .ws-matrix__name { display: none; }
79
+ .ws-matrix__q-cell { padding-right: var(--space-xs); }
80
+ .ws-matrix__q { white-space: normal; }
81
+ .ws-matrix__foot > summary { flex-wrap: wrap; row-gap: var(--space-xxs); }
82
+ .ws-matrix__foot > summary > svg { margin-left: auto; }
83
+ .ws-matrix__foot-line { flex-basis: 100%; order: 1; }
84
+ }
@@ -1,67 +1,98 @@
1
- A small panel of rows, lifted off the page: the one menu, for an account, a page or a short list of choices.
1
+ A small panel of rows lifted off the page: the one menu, for an account, a page's "more", or a short list of choices.
2
2
 
3
3
  ## Use it when
4
4
 
5
- - A button opens a short, flat list of actions or links (the account menu, a page's "more" menu, a chat's own options).
6
- - Showing what the person can do next from one place, without leaving the screen.
7
- - Grouping a few related actions with a line between groups (an "owner only" row, a destructive action set apart).
5
+ - A button opens a short, flat list of actions or links (the account menu, a row's "more", a chat's options).
6
+ - The person picks one of a few ways to see something (sort, group), and the choice shows its tick.
7
+ - A few related actions are grouped, with a line between groups.
8
8
 
9
9
  ## Not for
10
10
 
11
- - A thing's full detail opened from the chat: use `Panel`.
12
- - A short task needing the person's full attention: use `Dialog`.
13
- - A long list of records to browse: use a list of rows (`.ws-row`) or a `Table`.
14
- - A tab switch between a few fixed views: use `Segmented`.
11
+ - A thing's full detail: use `Panel`.
12
+ - A short task that needs the person's full attention: use `Dialog`.
13
+ - A note or a one-field form: use `Popover`.
14
+ - A long list of records: use rows or a `Table`.
15
+ - A switch between a few fixed views: use `Segmented`.
15
16
 
16
17
  ## Anatomy
17
18
 
18
- - The panel (`ws-menu`): a card lifted off the page, `--ws-radius-card` (8 px) corners, the cream (`--color-bg-page`) background, `--ws-shadow-lift` (the one lift a menu is allowed), `--space-xxs` (4 px) padding, at least 200 px wide.
19
- - Each row (`ws-menu-item` / `MenuItem`): a 32 px line (40 px under a finger), growing to fit two lines of words if needed, `--ws-radius-control` (4 px) corners, 14 px medium navy words, a 16 px line icon before the words where one is given.
20
- - A hairline (`ws-menu-line`, `--ws-menu-line`) separates groups of rows.
21
- - A row is a link (`href`) when it goes somewhere, a button (`onClick`) when it does something.
19
+ - The panel (`ws-menu`): `--ws-raised` ground, 10 px corners (North's menu, `--ws-radius-menu`), the 0.5 px
20
+ hairline and the menu drop (`--ws-shadow-hairline`, `--ws-shadow-menu`), 4 px inside, at least 200 wide. Never
21
+ wider than the window less 32 or taller than it less 32; past that it scrolls on its own.
22
+ - A row (`ws-menu-item`): 8 above and below 13 / 18 medium navy words, 10 at the sides, 6 px corners
23
+ (`--ws-radius-row`), so 34 tall; 40 on touch. A 16 px muted line icon before the words when given
24
+ (`ws-menu-item__icon`), 8 apart. A row is a link when it goes somewhere, a button when it does something.
25
+ - A hint (`ws-menu-item__hint`, inside `ws-menu-item__words`): an 11 / 13 muted line under the words, 2 apart; the icon
26
+ then sits on the words' first line.
27
+ - A tick (`ws-menu-item__tick`): 16 px navy at the row's end, shown only on the chosen row of a choice.
28
+ - The line between groups (`ws-menu-line`): 1 px of `--ws-menu-line`, 4 above and below, the menu's full width.
22
29
 
23
30
  ## Variants and sizes
24
31
 
25
- | Row kind | Element | `role` |
32
+ | Row | Element | `role` |
26
33
  | --- | --- | --- |
27
- | Goes somewhere | `MenuItem href=...` | `menuitem` (as a link) |
28
- | Does something | `MenuItem onClick=...` | `menuitem` |
29
- | A toggle choice | `MenuItem role="menuitemradio" aria-checked` | `menuitemradio` |
30
- | The current item | `current` | adds the sunk background and, for a link, `aria-current="page"` |
34
+ | Goes somewhere | `<a class="ws-menu-item">` | `menuitem` |
35
+ | Does something | `<button class="ws-menu-item">` | `menuitem` |
36
+ | A choice | `<button class="ws-menu-item">` with `ws-menu-item__tick` | `menuitemradio` or `menuitemcheckbox`, `aria-checked` |
37
+ | The current item | `aria-current="page"` (or `ws-menu-item--current`) | keeps the `--ws-menu-hover` tint |
31
38
 
32
39
  ## States
33
40
 
34
- - **Default**: the cream row on the lifted panel.
35
- - **Hover**: the row tints to `--ws-surface-sunk`.
36
- - **Pressed**: a step further to `--ws-surface-press`.
37
- - **Focus**: the shadow focus ring (`--shadow-focus-ring`) on the row.
38
- - **Current**: a persistent `--ws-surface-sunk` background (not just on hover), for the item the person is already on.
39
- - **Disabled**: 40% opacity, no pointer events; used sparingly, with a short reason beside it if one is needed ("owner only").
40
- - **Leaving**: the panel fades and settles a hair smaller on the exit curve (`ws-menu-out`), taking no presses while it goes.
41
- - **Long label**: a row grows from 32 to accommodate two lines rather than truncating silently.
41
+ - **Default**: rows on the raised ground.
42
+ - **Hover**: the navy wash (`--ws-hover`, .05) over `--ws-duration-hover`; only for pointers that hover, so a tap
43
+ never leaves it behind.
44
+ - **Pressed**: the press tint (`--ws-surface-press`), at once; the current row too.
45
+ - **Focus**: the 2 px navy ring drawn inside the row.
46
+ - **Current**: a steady `--ws-menu-hover` tint.
47
+ - **Chosen**: the tick shows (`aria-checked="true"`).
48
+ - **Disabled**: 50%, no presses; say why in its own words ("Billing (owner only)").
49
+ - **Long label**: the row grows to two lines; words are never cut.
50
+ - **Opening** (North js@620042, "Messages and steps settle"): it grows out of the corner it hangs from, 4 px toward
51
+ its button and .97 (`--ws-open-scale`), on the settle spring (`--ws-spring-settle`, .32 / .1, 450 ms to rest). A
52
+ native popover does it with `@starting-style`; one the app mounts plays `ws-menu-in`.
53
+ - **Leaving** (`data-leaving`, or a native popover closing): it goes back into that corner (the same 4 px and .97,
54
+ fading) over `--ws-duration-exit` (120 ms) on `--ws-ease-exit`, faster than it came, taking no presses. A native
55
+ popover keeps its box while it leaves (`display` and `overlay` transition with `allow-discrete`), and a close
56
+ mid-entrance turns back from where it is. Wait 120 ms after `data-leaving` before removing it.
57
+ - **Opened above** (it flipped, or the app placed it there): where the browser places it by anchor the nudge rides on
58
+ the margin, which the flip fallbacks turn with it, so it still comes from its button; it scales from the top right
59
+ either way (CSS cannot tell `transform-origin` which fallback won). An app that places it (Floating UI, Radix) sets
60
+ `data-side="top"`, and the nudge and the corner both turn round.
42
61
 
43
62
  ## Behaviour
44
63
 
45
- - Keyboard: rows are real links or buttons in document order; arrow-key roving focus is used only where the menu is a true `menu`/`menuitem` set with a library behind it, never hand-rolled.
46
- - Pointer: a click on a row runs its action or follows its link at once; a click outside the menu (its dismiss handler, `useDismiss`) closes it.
47
- - Touch: rows meet 40 px when the device is coarse-pointer (`@media (pointer: coarse)` lifts the row's own controls, not the menu row itself, which is already tall enough).
48
- - Motion: the panel rises in (`ws-menu`, `--ws-duration-gentle` on `--ws-ease-soft`) and, on close, fades and shrinks slightly (`ws-menu-out`, `--ws-duration-instant` on `--ws-ease-exit`).
49
- - Reduced motion: the panel appears and disappears without the rise or shrink.
64
+ - Placement (K9): open it in the top layer with the native `popover` attribute and its button's `popovertarget`.
65
+ Nothing then cuts it (a card, a dialog, a scroller). Where the browser places by anchor, it hangs 8 under its
66
+ button, right edges flush (left edges once it flips to the other side). A tall one stays under its button, capped
67
+ to the room below less 8 and scrolling inside, so it never covers the button; it flips above only when less than
68
+ 200 px (or less than its own height) fits below, and a menu wider than either side of its button (a phone) centres
69
+ in the window under it. The button is its anchor when the button opens it (or `showPopover({ source: button })`).
70
+ In a React app, portal it (Radix, Floating UI) with
71
+ `flip` and `shift`; in a scoped app the portal root carries `class="fello"`. A native popover needs no portal: it
72
+ stays where it is in the page, so it keeps the `.fello` scope and the page's tokens.
73
+ - Keyboard: `popover="auto"` closes on Escape and on a press outside, and focus goes back to the button. Arrow keys
74
+ move between rows only where a library gives the menu roving focus; never hand-rolled.
75
+ - Pointer: a press on a row runs it, then the app closes the menu (`hidePopover()`); a link row closes it by going.
76
+ - Touch: rows are 40 tall.
77
+ - Reduced motion: it appears and goes at once. A browser without `@starting-style` or `linear()` shows and hides it
78
+ at once too; nothing else changes.
79
+ - The preview's last two stacks are live: press Sort, and Move (at the page's foot, so it opens above).
50
80
 
51
81
  ## Content
52
82
 
53
- - Each row's words are a short verb phrase or a destination name, sentence case, no em dash ("Invite your team", not "Team Invitation").
54
- - A disabled row's reason, if any, is part of its own words or a short line beside it, never a separate tooltip only.
55
- - Destructive or rare actions ("Sign out") sit last, after a hairline, so they are never the first thing pressed by habit.
83
+ - Each row is a short verb phrase or a place's name, sentence case ("Invite your team").
84
+ - A hint says what the row does in a few words, never a second label.
85
+ - A disabled row's reason is part of its own words.
86
+ - Rare or destructive rows ("Sign out") sit last, after a line.
56
87
 
57
88
  ## Props
58
89
 
59
- **`MenuItem`**
90
+ **`MenuItem`** (the reference implementation)
60
91
 
61
92
  | Name | Type | Meaning |
62
93
  | --- | --- | --- |
63
94
  | `href` | string | Makes the row a link. |
64
- | `scroll` | boolean | For a link: `false` keeps the page where it is (a menu that changes the address's query). |
95
+ | `scroll` | boolean | For a link: `false` keeps the page where it is. |
65
96
  | `current` | boolean | Marks the row the person is already on. |
66
97
  | `className` | string | Layout only. |
67
98
  | `children` | `ReactNode` | The row's icon and words. |
@@ -69,12 +100,57 @@ A small panel of rows, lifted off the page: the one menu, for an account, a page
69
100
 
70
101
  ## Rules
71
102
 
72
- - One component for every menu (16 Oct 2026: there had been seven of them): never a hand-styled dropdown panel.
73
- - A menu is lifted (`ws-shadow-lift`); it is one of the few surfaces in the system allowed a float shadow, since it genuinely sits above the page.
74
- - `useDismiss` closes the menu on an outside click or Escape; a menu never stays open once the person has clearly moved on.
103
+ - One component for every menu: never a hand-styled dropdown.
104
+ - In one menu every row has an icon or none does, so the words share one edge (an icon row's words start 24 further in).
105
+ - A menu floats, so it is one of the few things with a shadow: the menu drop, never a lift on a card.
106
+ - It closes once the person has moved on: Escape, a press outside, a row chosen.
75
107
 
76
108
  ## Source
77
109
 
78
- - **Derived from**: the system's lifted-panel and hairline rules (`ws-menu`, `ws-menu-item`, `ws-menu-line`, the
79
- `--ws-menu-line` token, `--ws-shadow-lift`).
80
- - **Precedent**: the first product built on the system.
110
+ **Derived from**: Seth's North menu (style1.css:657-660: 10 px corners, 4 inside, rows 8 / 10 with 6 px corners, 13 px
111
+ medium words over a quieter line, navy .05 hover, `0 16px 32px -16px` drop; P1, popovers 8 under, from their corner,
112
+ js@620042), Revenue OS K9 (17 of 76 menus cut at 1440), and the field fixes (gated hover, press tint, disabled 50%).
113
+ **Precedent**: the first product built on the system.
114
+
115
+ ## Markup
116
+
117
+ ```html
118
+ <button type="button" class="ws-btn ws-btn--secondary" popovertarget="account-menu">Dana Reyes</button>
119
+ <div id="account-menu" class="ws-menu" role="menu" aria-label="Account" popover>
120
+ <a href="/profile" class="ws-menu-item" role="menuitem">
121
+ <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="5.5" r="2.5" stroke="currentColor" stroke-width="1.5"/><path d="M3 13c0-2.5 2.2-4 5-4s5 1.5 5 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
122
+ Your profile
123
+ </a>
124
+ <div class="ws-menu-line" role="separator"></div>
125
+ <button type="button" class="ws-menu-item" role="menuitem">
126
+ <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><path d="M6 4H4a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2M10 11l3-3-3-3M13 8H6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
127
+ Sign out
128
+ </button>
129
+ </div>
130
+
131
+ <!-- a choice: no icons, the tick at the row's end -->
132
+ <button type="button" class="ws-btn ws-btn--secondary" popovertarget="sort-menu">Sort</button>
133
+ <div id="sort-menu" class="ws-menu" role="menu" aria-label="Sort the list" popover>
134
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="true">
135
+ <span class="ws-menu-item__words">
136
+ <span>Needs you first</span>
137
+ <span class="ws-menu-item__hint">Overdue calls, then the oldest reply</span>
138
+ </span>
139
+ <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>
140
+ </button>
141
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false">
142
+ <span class="ws-menu-item__words">
143
+ <span>Newest first</span>
144
+ <span class="ws-menu-item__hint">By when the lead came in</span>
145
+ </span>
146
+ <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>
147
+ </button>
148
+ </div>
149
+ <!-- where a browser needs the anchor said: style="anchor-name: --account" on the button,
150
+ style="position-anchor: --account" on the menu -->
151
+ ```
152
+
153
+ ## Styles
154
+
155
+ `Menu/style.css` reshapes the house `.ws-menu`, `.ws-menu-item` and `.ws-menu-line`; all are in `bundle.css` and
156
+ `fello.css`. Tokens only, so it turns dark with the page.
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Overlays" height=262 -->
1
+ <!-- @dsCard group="Overlays" height=310 -->
2
2
  <!doctype html>
3
3
  <html>
4
4
  <head>
@@ -10,34 +10,96 @@
10
10
  <body>
11
11
  <div class="ws-stage ws-stage--grey">
12
12
 
13
- <div class="ws-stack" style="width: 240px;">
14
- <span class="ws-muted">Account menu, lifted on ws-shadow-lift</span>
15
- <div class="ws-menu" role="menu" aria-label="Account">
16
- <button type="button" class="ws-menu-item" role="menuitem">
17
- <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="5.5" r="2.5" stroke="currentColor" stroke-width="1.5"/><path d="M3 13c0-2.5 2.2-4 5-4s5 1.5 5 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
18
- Your profile
19
- </button>
20
- <button type="button" class="ws-menu-item" role="menuitem">
21
- <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><path d="M8 2v2M8 12v2M3 8H1M15 8h-2M4 4l1.4 1.4M10.6 10.6L12 12M4 12l1.4-1.4M10.6 5.4L12 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="8" cy="8" r="2.5" stroke="currentColor" stroke-width="1.5"/></svg>
22
- Settings
23
- </button>
24
- <div class="ws-menu-line"></div>
25
- <button type="button" class="ws-menu-item" role="menuitem">
26
- <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><rect x="2.5" y="2.5" width="11" height="11" rx="2" stroke="currentColor" stroke-width="1.5"/><path d="M6 8h4M8 6v4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
27
- Invite your team
13
+ <div class="ws-stack" style="width: 260px;">
14
+ <span class="ws-muted">Hangs 8 under its button, right edges flush; the current row is tinted</span>
15
+ <div class="ws-stack" style="align-items: flex-end; gap: var(--space-xs);">
16
+ <button type="button" class="ws-btn ws-btn--secondary" aria-haspopup="menu" aria-expanded="true">Dana Reyes</button>
17
+ <div class="ws-menu" role="menu" aria-label="Account" style="width: 240px;">
18
+ <a href="#profile" class="ws-menu-item" role="menuitem" aria-current="page">
19
+ <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="5.5" r="2.5" stroke="currentColor" stroke-width="1.5"/><path d="M3 13c0-2.5 2.2-4 5-4s5 1.5 5 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
20
+ Your profile
21
+ </a>
22
+ <button type="button" class="ws-menu-item" role="menuitem">
23
+ <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><path d="M8 2v2M8 12v2M3 8H1M15 8h-2M4 4l1.4 1.4M10.6 10.6L12 12M4 12l1.4-1.4M10.6 5.4L12 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="8" cy="8" r="2.5" stroke="currentColor" stroke-width="1.5"/></svg>
24
+ Settings
25
+ </button>
26
+ <div class="ws-menu-line" role="separator"></div>
27
+ <button type="button" class="ws-menu-item" role="menuitem">
28
+ <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><rect x="2.5" y="2.5" width="11" height="11" rx="2" stroke="currentColor" stroke-width="1.5"/><path d="M6 8h4M8 6v4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
29
+ Invite your team
30
+ </button>
31
+ <button type="button" class="ws-menu-item" role="menuitem" aria-disabled="true">
32
+ <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><rect x="3.5" y="7" width="9" height="6" rx="1.5" stroke="currentColor" stroke-width="1.5"/><path d="M5.5 7V5a2.5 2.5 0 0 1 5 0v2" stroke="currentColor" stroke-width="1.5"/></svg>
33
+ Billing (owner only)
34
+ </button>
35
+ <div class="ws-menu-line" role="separator"></div>
36
+ <button type="button" class="ws-menu-item" role="menuitem">
37
+ <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><path d="M6 4H4a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2M10 11l3-3-3-3M13 8H6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
38
+ Sign out
39
+ </button>
40
+ </div>
41
+ </div>
42
+ </div>
43
+
44
+ <div class="ws-stack" style="width: 260px;">
45
+ <span class="ws-muted">Rows with a hint, and a choice that shows its tick</span>
46
+ <div class="ws-menu" role="menu" aria-label="Sort the list">
47
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="true">
48
+ <span class="ws-menu-item__words">
49
+ <span>Needs you first</span>
50
+ <span class="ws-menu-item__hint">Overdue calls, then the oldest reply</span>
51
+ </span>
52
+ <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>
28
53
  </button>
29
- <button type="button" class="ws-menu-item" role="menuitem" disabled aria-disabled="true">
30
- <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><rect x="3.5" y="7" width="9" height="6" rx="1.5" stroke="currentColor" stroke-width="1.5"/><path d="M5.5 7V5a2.5 2.5 0 0 1 5 0v2" stroke="currentColor" stroke-width="1.5"/></svg>
31
- Billing (owner only)
54
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false">
55
+ <span class="ws-menu-item__words">
56
+ <span>Newest first</span>
57
+ <span class="ws-menu-item__hint">By when the lead came in</span>
58
+ </span>
59
+ <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>
32
60
  </button>
33
- <div class="ws-menu-line"></div>
34
- <button type="button" class="ws-menu-item" role="menuitem">
35
- <svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><path d="M6 4H4a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2M10 11l3-3-3-3M13 8H6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
36
- Sign out
61
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false">
62
+ <span class="ws-menu-item__words">
63
+ <span>Biggest deal first</span>
64
+ <span class="ws-menu-item__hint">By the quote, then by the stage</span>
65
+ </span>
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>
37
67
  </button>
38
68
  </div>
39
69
  </div>
40
70
 
71
+ <div class="ws-stack" style="width: 260px;">
72
+ <span class="ws-muted">A long row wraps to two lines instead of cutting its words</span>
73
+ <div class="ws-menu" role="menu" aria-label="This lead">
74
+ <button type="button" class="ws-menu-item" role="menuitem">Copy the link</button>
75
+ <button type="button" class="ws-menu-item" role="menuitem">Move to the team list so someone new can try them</button>
76
+ <div class="ws-menu-line" role="separator"></div>
77
+ <button type="button" class="ws-menu-item" role="menuitem">Archive</button>
78
+ </div>
79
+ </div>
80
+
81
+ <div class="ws-stack" style="width: 260px;" data-live>
82
+ <span class="ws-muted">Live: press Sort. It grows out of its corner on the settle spring and goes back into it faster; Move, at the foot of the page, opens above when there is no room under it</span>
83
+ <div class="ws-cluster" style="justify-content: space-between;">
84
+ <button type="button" class="ws-btn ws-btn--secondary" popovertarget="menu-live" aria-haspopup="menu">Sort</button>
85
+ </div>
86
+ <div id="menu-live" class="ws-menu" popover role="menu" aria-label="Sort the list" style="width: 240px;">
87
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="true" popovertarget="menu-live" popovertargetaction="hide">Needs you first<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></button>
88
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false" popovertarget="menu-live" popovertargetaction="hide">Newest first<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></button>
89
+ <button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false" popovertarget="menu-live" popovertargetaction="hide">Biggest deal first<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></button>
90
+ </div>
91
+ </div>
92
+
93
+ <div class="ws-stack" style="width: 100%; align-items: flex-end;" data-live>
94
+ <button type="button" class="ws-btn ws-btn--secondary" popovertarget="menu-live-up" aria-haspopup="menu">Move</button>
95
+ <div id="menu-live-up" class="ws-menu" popover role="menu" aria-label="Move this lead" style="width: 240px;">
96
+ <button type="button" class="ws-menu-item" role="menuitem" popovertarget="menu-live-up" popovertargetaction="hide">To the team list</button>
97
+ <button type="button" class="ws-menu-item" role="menuitem" popovertarget="menu-live-up" popovertargetaction="hide">To Dana Reyes</button>
98
+ <div class="ws-menu-line" role="separator"></div>
99
+ <button type="button" class="ws-menu-item" role="menuitem" popovertarget="menu-live-up" popovertargetaction="hide">Archive</button>
100
+ </div>
101
+ </div>
102
+
41
103
  </div>
42
104
  </body>
43
105
  </html>
@@ -0,0 +1,61 @@
1
+ /* ---- Menu: the house .ws-menu in Seth's North shape (C43): 10 px corners on the hairline and the menu drop, 6 px rows of
2
+ 13 px words with an 11 px hint, opened in the top layer and kept on screen ---- */
3
+ /* The panel: never taller or wider than the window (K9), its own scroll past that. Its corner is where it grows from:
4
+ the top right, under the button it hangs from (North P1). */
5
+ .ws-menu { max-width: calc(100vw - var(--space-xl)); max-height: calc(100dvh - var(--space-xl)); overflow-y: auto; overscroll-behavior: contain; border: 0; border-radius: var(--ws-radius-menu); color: inherit; box-shadow: var(--ws-shadow-hairline), var(--ws-shadow-menu); transform-origin: top right; }
6
+ /* A row: 8 above and below 13 / 18 words, 10 at the sides, 6 px corners; 40 tall on touch (house K10). The hover wash is
7
+ gated to pointers that hover, so a tap never leaves it behind; a press is the press tint. */
8
+ .ws-menu-item { padding: var(--space-xs) var(--space-xs-plus); border-radius: var(--ws-radius-row); text-decoration: none; font-size: var(--ws-text-control); line-height: var(--ws-leading-control); transition: background-color var(--ws-duration-hover) var(--ws-ease-soft); }
9
+ .ws-menu-item:hover { background: none; }
10
+ @media (hover: hover) { .ws-menu-item:hover { background: var(--ws-hover); } }
11
+ /* Both ways of marking the current row weigh the same, so neither loses its tint to the hover rules above. */
12
+ .ws-menu-item[aria-current], .ws-menu-item.ws-menu-item--current { background: var(--ws-menu-hover); }
13
+ /* The press comes last, so the current row answers a press too. */
14
+ .ws-menu-item:active { background: var(--ws-surface-press); transition-duration: var(--ws-duration-instant); }
15
+ .ws-menu-item:disabled, .ws-menu-item[aria-disabled="true"] { opacity: 0.5; pointer-events: none; }
16
+ /* The line between groups runs the menu's full width, past its 4 px padding (North D1). */
17
+ .ws-menu-line { margin-inline: calc(var(--space-xxs) * -1); }
18
+ .ws-menu-item__icon { flex-shrink: 0; width: var(--ws-icon); height: var(--ws-icon); color: var(--color-text-muted); }
19
+ /* A row with a hint: the words over an 11 / 13 line, the icon and the tick centred on the first line. */
20
+ .ws-menu-item__words { display: flex; flex: 1; flex-direction: column; gap: var(--space-3xs); min-width: 0; }
21
+ .ws-menu-item__hint { font-size: var(--ws-text-micro); line-height: var(--ws-leading-micro); font-weight: 400; color: var(--color-text-muted); }
22
+ .ws-menu-item:has(.ws-menu-item__hint) { align-items: flex-start; }
23
+ .ws-menu-item:has(.ws-menu-item__hint) > :is(.ws-menu-item__icon, .ws-menu-item__tick) { margin-block: calc((var(--ws-leading-control) - var(--ws-icon)) / 2); }
24
+ /* A choice (menuitemradio, menuitemcheckbox): the tick at the row's end shows only when it is chosen. */
25
+ .ws-menu-item__tick { flex-shrink: 0; width: var(--ws-icon); height: var(--ws-icon); margin-left: auto; color: var(--color-text-heading); visibility: hidden; }
26
+ .ws-menu-item[aria-checked="true"] > .ws-menu-item__tick { visibility: visible; }
27
+ /* The top layer (K9): opened with the native popover attribute it sits above every card, dialog and scroller that would
28
+ cut it. Where the browser places it by anchor, it hangs 8 under its button, right edges flush (left edges once it
29
+ flips to the other side). A tall one keeps hanging there, capped to the room below (8 short of the window's edge)
30
+ and scrolling inside, so it never slides over its button; it flips above only when less than 200 px (or less than
31
+ its own height) fits below. Wider than either side of its button (a phone), it centres in the window under it.
32
+ Without anchor placement, the app places it (Floating UI flip and shift). */
33
+ .ws-menu[popover]:not(:popover-open) { display: none; }
34
+ @supports (position-area: block-end) {
35
+ .ws-menu[popover] { inset: auto; margin: var(--space-xs) 0; position-area: block-end span-inline-start; justify-self: end; position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline, --ws-menu-wide, --ws-menu-wide flip-block; max-height: calc(100% - var(--space-xs) * 2); min-height: calc-size(max-content, min(size, var(--space-9xl))); }
36
+ }
37
+ @position-try --ws-menu-wide { position-area: block-end span-all; justify-self: center; }
38
+ /* Motion (D7, North js@620042: from y -4 and scale .97 on "Messages and steps settle", the settle spring .32 / .1; out
39
+ the same way over .12 s): it grows out of the corner it hangs from, toward its button, and settles on the spring; it
40
+ goes back into that corner faster. --ws-menu-from is the nudge, toward the button: up under it, down over it. An app
41
+ that places it (Floating UI, Radix) says which side with data-side="top"; where the browser places it by anchor, the
42
+ nudge rides on the margin toward the button instead, which the flip fallbacks turn with it (the corner it scales
43
+ from stays the top right there: CSS cannot tell a fallback's side to transform-origin). A native popover enters and
44
+ leaves by transitions (@starting-style, display and overlay allow-discrete), so a close mid-entrance turns back from
45
+ where it is; one the app mounts plays ws-menu-in and, with data-leaving, ws-menu-out before it is removed. */
46
+ .ws-menu { --ws-menu-from: calc(var(--ws-nudge) * -1); }
47
+ .ws-menu[data-side="top"] { --ws-menu-from: var(--ws-nudge); transform-origin: bottom right; }
48
+ @keyframes ws-menu-in { from { opacity: 0; transform: translateY(var(--ws-menu-from)) scale(var(--ws-open-scale)); } }
49
+ @keyframes ws-menu-out { to { opacity: 0; transform: translateY(var(--ws-menu-from)) scale(var(--ws-open-scale)); } }
50
+ @media (prefers-reduced-motion: no-preference) {
51
+ .ws-menu:not([popover]) { animation: ws-menu-in var(--ws-spring-settle-duration) var(--ws-spring-settle) backwards; }
52
+ .ws-menu[data-leaving] { animation: ws-menu-out var(--ws-duration-exit) var(--ws-ease-exit) forwards; pointer-events: none; }
53
+ .ws-menu[popover] { transition: opacity var(--ws-spring-settle-duration) var(--ws-spring-settle), transform var(--ws-spring-settle-duration) var(--ws-spring-settle), margin-block var(--ws-spring-settle-duration) var(--ws-spring-settle), overlay var(--ws-duration-exit) allow-discrete, display var(--ws-duration-exit) allow-discrete; }
54
+ .ws-menu[popover]:not(:popover-open) { opacity: 0; transform: translateY(var(--ws-menu-from)) scale(var(--ws-open-scale)); transition-duration: var(--ws-duration-exit); transition-timing-function: var(--ws-ease-exit); }
55
+ @starting-style { .ws-menu[popover]:popover-open { opacity: 0; transform: translateY(var(--ws-menu-from)) scale(var(--ws-open-scale)); } }
56
+ @supports (position-area: block-end) {
57
+ .ws-menu[popover]:not([data-side]) { --ws-menu-from: 0px; }
58
+ .ws-menu[popover]:not([data-side]):not(:popover-open) { margin-block-start: calc(var(--space-xs) - var(--ws-nudge)); }
59
+ @starting-style { .ws-menu[popover]:not([data-side]):popover-open { margin-block-start: calc(var(--space-xs) - var(--ws-nudge)); } }
60
+ }
61
+ }
@@ -1,9 +1,10 @@
1
- A running job's progress: a thin pill track that fills to the latest count, beside the words that say what it is doing.
1
+ A count on a thin 4 px track: a running job's progress beside its words, or a share in a row with its name above it.
2
2
 
3
3
  **Use it when**
4
4
 
5
5
  - Something is running now and the backend actually counts its parts ("2 of 7"), so the bar is never a guess.
6
6
  - A card's one act needs to show it is moving without a full `Stepper` (a mission pill at the foot of the screen, a running card in the chat).
7
+ - A short list of shares, each a row with its name and value above a thin track (Seth's "Seats Felix absorbs").
7
8
 
8
9
  **Not for**
9
10
 
@@ -13,8 +14,14 @@ A running job's progress: a thin pill track that fills to the latest count, besi
13
14
 
14
15
  **Anatomy**
15
16
 
16
- - Track: `--space-xxs` (4 px) tall, `--radius-full` pill, `--color-gray-2` ground.
17
- - Fill: the same pill shape, solid `--color-brand-navy`, its width the count's share, growing to a new figure inside the fixed track rather than the track itself resizing.
17
+ - Track: 4 px tall (`--space-xxs`), 2 px corners (Seth), `--ws-track` ground.
18
+ - Fill: the same shape, solid navy (`--color-text-heading`; teal when finished), its width the count's share, growing to a
19
+ new figure inside the fixed track rather than the track itself resizing.
20
+ - `--pill`: the 12 px mission pill, round ends.
21
+ - Rows (`.ws-meter__rows`): each row 8 above and below, 14 at the sides, a 0.5 px divider between rows (none above the first). On its line the name
22
+ (13/18 medium navy, one line, a `title` when it can truncate) and the value 8 after it (12/16 semibold navy, or
23
+ `--quiet` 12/16 medium muted for "none" and "stays"); 4 under it the track; 4 under that an 11/13 muted caption.
24
+ A row with no share has no track.
18
25
  - Words beside it: `ws-muted`, tabular numerals ("2 of 7").
19
26
  - Above the bar, the running step's own line: its words, a middle dot, and the elapsed clock ("0:42", "12:05", "1:02:05"), in `--color-text-interactive` (mid blue) while it ticks.
20
27
 
@@ -26,6 +33,13 @@ A running job's progress: a thin pill track that fills to the latest count, besi
26
33
  | Without a count | Only the step and its clock show; no bar is drawn, ever, when the backend has not actually counted parts |
27
34
  | Finished | The clock stops ticking (no interval), the bar (if any) sits at its final share |
28
35
 
36
+ **Parts and modifiers**
37
+
38
+ - `.ws-meter__card`: the running card: the step and its clock, then the meter, 4 apart, the card's padding inside.
39
+ - `.ws-meter__step`: the step's words, 14/20 in `--color-text-interactive`, tabular.
40
+ - `.ws-meter__step--done`: a finished step, in muted grey.
41
+ - `.ws-meter__fill--done`: a finished run's fill, in `--color-stat-positive`.
42
+
29
43
  **States**
30
44
 
31
45
  - Running: the clock ticks once a second from when the job started; the bar's width follows each new count.
@@ -38,7 +52,7 @@ A running job's progress: a thin pill track that fills to the latest count, besi
38
52
  **Behaviour**
39
53
 
40
54
  - Decorative to a screen reader (the bar carries no `aria-*` of its own); the words beside it ("2 of 7") and the step's own text are what a screen reader reads.
41
- - Motion: the fill's width transitions over `--ws-duration-gentle` on the soft curve as each new count arrives; the clock re-renders its text once a second while running, brought up to date at once when the run started before the page caught up.
55
+ - Motion: the fill's width moves over 700 ms on the settle curve (`--ws-duration-fill`, `--ws-ease-settle`) as each new count arrives; the clock re-renders its text once a second while running, brought up to date at once when the run started before the page caught up.
42
56
  - No pointer or keyboard behaviour.
43
57
 
44
58
  **Content**
@@ -62,6 +76,27 @@ A running job's progress: a thin pill track that fills to the latest count, besi
62
76
 
63
77
  **Source**
64
78
 
79
+ - **Seth**: the 4 px track with 2 px corners and the seat rows, Tally report (319:3426 to 319:3432). His seat fill is
80
+ #2C4870 (agent/tally), the fill's `--ws-agent-tally` (the act itself in dark).
65
81
  - **Derived from**: the system's fixed-track fill rule, "a card's progress meter: its bar grows to the new figure
66
82
  inside a fixed track," and the no-invented-count rule.
67
83
  - **Precedent**: the first product built on the system.
84
+
85
+ **Markup**
86
+
87
+ ```html
88
+ <span class="ws-meter" aria-hidden="true">
89
+ <span class="ws-meter__track"><span class="ws-meter__fill" style="width: 28.6%;"></span></span>
90
+ <span class="ws-meter__words">2 of 7</span>
91
+ </span>
92
+
93
+ <ul class="ws-meter__rows" aria-label="Seats Felix absorbs">
94
+ <li class="ws-meter__row">
95
+ <span class="ws-meter__line"><span class="ws-meter__name">ISAs</span><span class="ws-meter__value">50%</span></span>
96
+ <span class="ws-meter__track" aria-hidden="true"><span class="ws-meter__fill" style="width: 50%;"></span></span>
97
+ <span class="ws-meter__caption">4, typical for your team</span>
98
+ </li>
99
+ </ul>
100
+ ```
101
+
102
+ **Styles**: `Meter/style.css`, in `bundle.css` and `fello.css` as `.ws-meter`. Every value is a token.
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Progress" height=200 -->
1
+ <!-- @dsCard group="Progress" height=420 -->
2
2
  <!doctype html>
3
3
  <html>
4
4
  <head>
@@ -55,6 +55,23 @@
55
55
  </div>
56
56
  </div>
57
57
 
58
+ <div class="ws-stack" style="width: 340px; max-width: 100%;">
59
+ <span class="ws-muted">Rows: a seat's share on the 4 px track, its caption under it, 0.5 px dividers</span>
60
+ <ul class="ws-meter__rows" aria-label="Seats Felix absorbs">
61
+ <li class="ws-meter__row">
62
+ <span class="ws-meter__line"><span class="ws-meter__name">ISAs</span><span class="ws-meter__value">50%</span></span>
63
+ <span class="ws-meter__track" aria-hidden="true"><span class="ws-meter__fill" style="width: 50%;"></span></span>
64
+ <span class="ws-meter__caption">4, typical for your team</span>
65
+ </li>
66
+ <li class="ws-meter__row">
67
+ <span class="ws-meter__line"><span class="ws-meter__name">Marketing managers</span><span class="ws-meter__value ws-meter__value--quiet">none, typical</span></span>
68
+ </li>
69
+ <li class="ws-meter__row">
70
+ <span class="ws-meter__line"><span class="ws-meter__name" title="Transaction coordinators and closing assistants">Transaction coordinators and closing assistants</span><span class="ws-meter__value ws-meter__value--quiet">stays</span></span>
71
+ </li>
72
+ </ul>
73
+ </div>
74
+
58
75
  </div>
59
76
  </body>
60
77
  </html>