@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,114 @@
1
+ What a chart mark holds, shown on hover or focus: Seth's North chart tip, with a caret on the mark it belongs to.
2
+
3
+ ## Use it when
4
+
5
+ - A bar, a point, a tick or a square holds more than its mark can say (the week, the count, what it is made of).
6
+ - The person reads a chart by moving across it, and each mark answers as they pass.
7
+ - A short summary should sit by a mark without opening anything (a goal met on a day).
8
+
9
+ ## Not for
10
+
11
+ - A control's name: use `Tooltip`.
12
+ - Content someone acts on beyond one ask (a field, several acts): use `Popover`.
13
+ - The only place a number lives: what a hover card says must also be reachable without hovering (the chart's own
14
+ table, a list, or the card on focus and tap).
15
+ - A thing's full detail: use `Panel`.
16
+
17
+ ## Anatomy
18
+
19
+ - The card (`ws-hover-card`): `--ws-raised` ground, 8 px corners, the 0.5 px hairline and the tip drop
20
+ (`--ws-shadow-hairline`, `--ws-shadow-tip`), 12 above, 14 at the sides, 10 below. At least 168 wide; it grows with
21
+ its words up to 440, then a label wraps. 12 px body words. The rhythm is North's:
22
+ - Eyebrow 16 (`ws-hover-card__eyebrow`): an 8 px swatch with 2 px corners (`ws-hover-card__swatch`) and 11 px muted
23
+ words, 6 apart, 2 above the title.
24
+ - Title 20 (`ws-hover-card__title`): 16 / 20 semibold navy, 8 above the rows.
25
+ - Rows 22 (`ws-hover-card__row`): an 18 px line with 2 above and below; an optional swatch, the label
26
+ (`ws-hover-card__label`) taking the room, 28 clear of its value (the 8 px gap plus 20 of its own, North's row), the
27
+ value (`ws-hover-card__value`) navy semibold and tabular.
28
+ A label that wraps keeps its swatch and value on its first line; a number never wraps.
29
+ - Rule row (`ws-hover-card__row--rule`): a total or the next section, 8 above and 8 below a hairline that runs the
30
+ card's full width; its label navy medium.
31
+ - Ask foot (`ws-hover-card__foot`): a full-width strip under a hairline, 8 / 14 inside, 12 / 16 medium navy words, its
32
+ bottom corners the card's; the card drops its own bottom room. 40 tall on touch.
33
+ - Caret (on `--above` and `--below`): an 8 px square turned 45, its two outer edges drawn and only its outer half
34
+ shown, so the card's edge runs on to the point and nothing inside the card (the foot, its tint, its ring) is covered.
35
+
36
+ ## Variants and sizes
37
+
38
+ | Class | Look |
39
+ | --- | --- |
40
+ | `ws-hover-card` | The full card: eyebrow, title, rows, rules, foot |
41
+ | `ws-hover-card--compact` | North's point card: 8 / 10 inside, 6 px corners, a 12 / 16 semibold title over an 11 / 13 line (`ws-hover-card__line`), 2 apart |
42
+ | `ws-hover-card--above` | Placed on a mark: the card 8 over the point the chart sets (`left`, `top`), its caret reaching down to it |
43
+ | `ws-hover-card--below` | The same 8 under the point, caret up |
44
+ | `ws-hover-card--start`, `--end` | Near a side, the caret moves to 20% or 80% and the card with it, so it never runs off (North P3) |
45
+
46
+ ## States
47
+
48
+ - **Hidden**: not drawn; the chart renders it for the mark under the pointer or in focus.
49
+ - **Shown** (North's chart tip, js@484880): it pops out of .9 and 6 px toward its mark (`--ws-rise`), from the
50
+ caret's corner, on the pop spring (`--ws-spring-pop`, .35 / .1); its parts settle in after it, 45 ms apart
51
+ (`--ws-stagger-row`), each over `--ws-duration-settle` on `--ws-ease-soft` out of a 3 px blur (`ws-settle`).
52
+ - **Following**: as the pointer moves along a chart it glides to the next mark on the follow spring (.22 / 0, never a
53
+ bounce), never in jumps. `ws-hover-card--follow` does it in CSS (`--ws-spring-follow` on `left` and `top`) for an app
54
+ that only sets them; an app that springs it itself (`springs.follow`) leaves the class off.
55
+ - **Grace**: it stays 180 ms (`--ws-hover-grace`) after the pointer leaves its mark, so a gap between bars never
56
+ flickers it.
57
+ - **Leaving** (`data-leaving`): it fades to .94 and 4 px over `--ws-duration-exit` (120 ms), faster than it came;
58
+ remove it 120 ms later.
59
+ - **Foot**: hover tints it with the navy wash, and the caret under it with it, so the strip and its point stay one
60
+ surface; focus draws the ring inside it.
61
+ - **Long label**: wraps; the value stays on the first line.
62
+
63
+ ## Behaviour
64
+
65
+ - Keyboard: each mark that has a card is focusable (or the chart moves a focus mark with the arrow keys); the card
66
+ shows for the focused mark. Escape hides it.
67
+ - Pointer: shows on the mark, follows along the chart, stays for the grace.
68
+ - Touch: a tap on a mark shows its card; a tap elsewhere hides it. The foot is 40 tall.
69
+ - Placement: the chart sets `left` and `top` to the point inside its own positioned box; `--start` or `--end` near a
70
+ side. Inside a box that clips, portal it to the page.
71
+ - Reduced motion: it appears and goes in place; it moves to the next mark at once.
72
+ - The preview's last stack is live: point along the bars.
73
+
74
+ ## Content
75
+
76
+ - The eyebrow names the mark (the week, the person, the series), with its colour.
77
+ - The title is the mark's one figure, in words if it helps ("26 calls").
78
+ - Rows say what the figure is made of, largest first; a rule row ends with the total or the comparison.
79
+ - The foot asks one question about this mark ("Ask about this week").
80
+
81
+ ## Rules
82
+
83
+ - Every swatch is the mark's own chart colour; the words stay the word tones (AA on the raised ground).
84
+ - No more than five rows; a longer breakdown belongs in the chart's table.
85
+ - Its words are never the only place the figures live.
86
+ - A card that holds the ask foot (a button) is `role="dialog"` with an `aria-label`, never `role="tooltip"`: a tooltip
87
+ holds nothing to press. A card with only words (`--compact`) is `role="tooltip"`.
88
+
89
+ ## Source
90
+
91
+ **Derived from**: Seth's North chart tip (style1.css:208-220: min 168, 12 / 14 / 10, eyebrow 16, title 20 + 8, rows 22,
92
+ full-width rules; :561-562 the ask foot; :386-398 the point card, the caret and the 80% edge anchor; js@484880 the pop,
93
+ follow, grace and the 45 ms row stagger). **Precedent**: new in 0.5.0; the kit's `Tooltip` was a one-line label only.
94
+
95
+ ## Markup
96
+
97
+ ```html
98
+ <div style="position: relative;">
99
+ <!-- the chart's marks; the card is placed at the open mark's point -->
100
+ <div class="ws-hover-card ws-hover-card--above" role="dialog" aria-label="Week of 20 October" style="left: 58%; top: 74%;">
101
+ <span class="ws-hover-card__eyebrow"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--color-text-heading);"></span>Week of 20 October</span>
102
+ <span class="ws-hover-card__title">26 calls</span>
103
+ <span class="ws-hover-card__row"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-finished);"></span><span class="ws-hover-card__label">Answered</span><span class="ws-hover-card__value">19</span></span>
104
+ <span class="ws-hover-card__row"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-under-half);"></span><span class="ws-hover-card__label">Missed</span><span class="ws-hover-card__value">7</span></span>
105
+ <span class="ws-hover-card__row ws-hover-card__row--rule"><span class="ws-hover-card__label">Team average</span><span class="ws-hover-card__value">31</span></span>
106
+ <button type="button" class="ws-hover-card__foot">Ask about this week</button>
107
+ </div>
108
+ </div>
109
+ ```
110
+
111
+ ## Styles
112
+
113
+ `HoverCard/style.css`, built into `bundle.css` and `fello.css`. Tokens only, so it turns dark with the page; the
114
+ swatches take the chart colours through `--ws-hover-card-swatch`.
@@ -0,0 +1,107 @@
1
+ <!-- @dsCard group="Overlays" height=660 -->
2
+ <!doctype html>
3
+ <html>
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <title>HoverCard</title>
7
+ <link rel="stylesheet" href="../../tokens.css">
8
+ <link rel="stylesheet" href="../bundle.css">
9
+ </head>
10
+ <body>
11
+ <div class="ws-stage">
12
+
13
+ <div class="ws-stack" style="width: 420px;">
14
+ <span class="ws-muted">Over a bar: eyebrow, title, rows, a rule row and the ask foot; the caret on the bar's top</span>
15
+ <div role="group" aria-label="Calls by week, with the week of 20 October open" style="position: relative; height: 320px; border-bottom: var(--ws-line) solid var(--ws-edge-slot);">
16
+ <span style="position: absolute; bottom: 0; left: 8%; width: 12%; height: 30%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
17
+ <span style="position: absolute; bottom: 0; left: 30%; width: 12%; height: 40%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
18
+ <span style="position: absolute; bottom: 0; left: 52%; width: 12%; height: 26%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--color-text-heading);"></span>
19
+ <span style="position: absolute; bottom: 0; left: 74%; width: 12%; height: 34%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
20
+ <div class="ws-hover-card ws-hover-card--above" role="dialog" aria-label="Week of 20 October" style="left: 58%; top: 74%;">
21
+ <span class="ws-hover-card__eyebrow"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--color-text-heading);"></span>Week of 20 October</span>
22
+ <span class="ws-hover-card__title">26 calls</span>
23
+ <span class="ws-hover-card__row"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-finished);"></span><span class="ws-hover-card__label">Answered</span><span class="ws-hover-card__value">19</span></span>
24
+ <span class="ws-hover-card__row"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-under-half);"></span><span class="ws-hover-card__label">Missed</span><span class="ws-hover-card__value">7</span></span>
25
+ <span class="ws-hover-card__row ws-hover-card__row--rule"><span class="ws-hover-card__label">Team average</span><span class="ws-hover-card__value">31</span></span>
26
+ <button type="button" class="ws-hover-card__foot">Ask about this week</button>
27
+ </div>
28
+ </div>
29
+ </div>
30
+
31
+ <div class="ws-stack" style="width: 420px;">
32
+ <span class="ws-muted">A point card over a dot; near the right edge its caret moves to 80% so it stays inside</span>
33
+ <div role="img" aria-label="Replies by day" style="position: relative; height: 180px; border-bottom: var(--ws-line) solid var(--ws-edge-slot);">
34
+ <span style="position: absolute; left: 30%; top: 70%; width: var(--space-xs); height: var(--space-xs); border-radius: var(--radius-full); background: var(--color-text-heading); translate: -50% -50%;"></span>
35
+ <div class="ws-hover-card ws-hover-card--compact ws-hover-card--above" role="tooltip" style="left: 30%; top: calc(70% - var(--space-xxs));">
36
+ <span class="ws-hover-card__title">Tuesday</span>
37
+ <span class="ws-hover-card__line">4 replies, 2 within the hour</span>
38
+ </div>
39
+ <span style="position: absolute; left: 92%; top: 40%; width: var(--space-xs); height: var(--space-xs); border-radius: var(--radius-full); background: var(--color-text-heading); translate: -50% -50%;"></span>
40
+ <div class="ws-hover-card ws-hover-card--compact ws-hover-card--above ws-hover-card--end" role="tooltip" style="left: 92%; top: calc(40% - var(--space-xxs));">
41
+ <span class="ws-hover-card__title">Sunday</span>
42
+ <span class="ws-hover-card__line">1 reply</span>
43
+ </div>
44
+ </div>
45
+ </div>
46
+
47
+ <div class="ws-stack" style="width: 420px;">
48
+ <span class="ws-muted">Below its mark, and at rest beside a chart; a long label wraps, the number never does</span>
49
+ <div style="position: relative; height: 40px;">
50
+ <span style="position: absolute; left: 20%; top: 0; width: var(--space-xs); height: var(--space-xs); border-radius: var(--radius-full); background: var(--ws-chart-finished); translate: -50% 0;"></span>
51
+ <div class="ws-hover-card ws-hover-card--compact ws-hover-card--below ws-hover-card--start" role="tooltip" style="left: 20%; top: var(--space-xs);">
52
+ <span class="ws-hover-card__title">Goal met on 14 October</span>
53
+ </div>
54
+ </div>
55
+ <div class="ws-hover-card" style="margin-top: var(--space-xl);">
56
+ <span class="ws-hover-card__eyebrow"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-finished);"></span>October</span>
57
+ <span class="ws-hover-card__title">82%</span>
58
+ <span class="ws-hover-card__row"><span class="ws-hover-card__label">Calls answered within five minutes of the lead coming in from Zillow or the website</span><span class="ws-hover-card__value">41 of 50</span></span>
59
+ <span class="ws-hover-card__row"><span class="ws-hover-card__label">Later</span><span class="ws-hover-card__value">9</span></span>
60
+ </div>
61
+ </div>
62
+
63
+ <div class="ws-stack" style="width: 420px;" data-live>
64
+ <span class="ws-muted">Live: point along the bars. The card pops out of .9 on the pop spring, its rows settling in 45 ms apart, then glides from bar to bar on the follow spring (--follow); 180 ms after the pointer leaves it goes, over .12 s</span>
65
+ <div id="hc-live" role="group" aria-label="Calls by week" style="position: relative; height: 240px; border-bottom: var(--ws-line) solid var(--ws-edge-slot);">
66
+ <span data-week="Week of 29 September" data-calls="18" data-answered="12" style="position: absolute; bottom: 0; left: 8%; width: 12%; height: 40%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
67
+ <span data-week="Week of 6 October" data-calls="24" data-answered="17" style="position: absolute; bottom: 0; left: 30%; width: 12%; height: 54%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
68
+ <span data-week="Week of 13 October" data-calls="15" data-answered="11" style="position: absolute; bottom: 0; left: 52%; width: 12%; height: 34%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
69
+ <span data-week="Week of 20 October" data-calls="26" data-answered="19" style="position: absolute; bottom: 0; left: 74%; width: 12%; height: 60%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--color-text-heading);"></span>
70
+ </div>
71
+ </div>
72
+ <script>
73
+ (() => {
74
+ const chart = document.getElementById('hc-live');
75
+ let card = null, leave = 0;
76
+ const place = (bar) => {
77
+ const x = parseFloat(bar.style.left) + parseFloat(bar.style.width) / 2;
78
+ card.style.left = `${x}%`;
79
+ card.style.top = `${100 - parseFloat(bar.style.height)}%`;
80
+ card.classList.toggle('ws-hover-card--start', x < 25);
81
+ card.classList.toggle('ws-hover-card--end', x > 75);
82
+ card.querySelector('.ws-hover-card__title').textContent = `${bar.dataset.calls} calls`;
83
+ card.querySelector('[data-words]').textContent = bar.dataset.week;
84
+ card.querySelector('.ws-hover-card__value').textContent = bar.dataset.answered;
85
+ };
86
+ for (const bar of chart.children) bar.addEventListener('pointerenter', () => {
87
+ clearTimeout(leave);
88
+ if (!card || card.hasAttribute('data-leaving')) {
89
+ card?.remove();
90
+ card = document.createElement('div');
91
+ card.className = 'ws-hover-card ws-hover-card--above ws-hover-card--follow';
92
+ card.setAttribute('role', 'tooltip');
93
+ card.innerHTML = '<span class="ws-hover-card__eyebrow"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--color-text-heading);"></span><span data-words></span></span><span class="ws-hover-card__title"></span><span class="ws-hover-card__row"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-finished);"></span><span class="ws-hover-card__label">Answered</span><span class="ws-hover-card__value"></span></span>';
94
+ place(bar);
95
+ chart.append(card);
96
+ } else place(bar);
97
+ });
98
+ chart.addEventListener('pointerleave', () => {
99
+ clearTimeout(leave);
100
+ leave = setTimeout(() => { const c = card; c?.setAttribute('data-leaving', ''); setTimeout(() => c?.remove(), 120); }, 180);
101
+ });
102
+ })();
103
+ </script>
104
+
105
+ </div>
106
+ </body>
107
+ </html>
@@ -0,0 +1,59 @@
1
+ /* ---- HoverCard: what a chart mark holds, on hover or focus, Seth's North chart tip (N:209-220): eyebrow 16, title 20 and 8
2
+ under, rows 22, full-width rules; placed over a mark, a caret points at it ---- */
3
+ /* The card: 12 / 14 / 10 inside, at least 168 wide, 8 px corners, the hairline and the tip drop, 12 px body words. It
4
+ grows with its words up to the panel width; a label wraps, a number never does. --ws-hover-card-anchor is where the
5
+ caret sits along its edge (50%, or 20% / 80% near a side, North P3). */
6
+ .ws-hover-card { --ws-hover-card-x: var(--space-sm-plus); --ws-hover-card-anchor: 50%; position: relative; display: flex; flex-direction: column; width: max-content; min-width: calc(var(--space-8xl) + var(--space-xs)); max-width: min(var(--ws-thing-width), calc(100vw - var(--space-xl))); padding: var(--space-sm) var(--ws-hover-card-x) var(--space-xs-plus); border-radius: var(--ws-radius-card); background: var(--ws-raised); box-shadow: var(--ws-shadow-hairline), var(--ws-shadow-tip); font-size: var(--ws-text-dense); line-height: var(--ws-leading-control); color: var(--color-text-body); }
7
+ /* Eyebrow 16: 11 px muted words after an 8 px swatch, 6 apart, 2 above the title. */
8
+ .ws-hover-card__eyebrow { display: flex; align-items: center; gap: var(--space-xxs-plus); margin-bottom: var(--space-3xs); font-size: var(--ws-text-micro); line-height: var(--space-md); color: var(--color-text-muted); }
9
+ .ws-hover-card__swatch { flex-shrink: 0; width: var(--space-xs); height: var(--space-xs); border-radius: var(--ws-radius-chip); background: var(--ws-hover-card-swatch, currentColor); }
10
+ /* Title 20: 16 / 20 semibold navy, 8 above the rows. */
11
+ .ws-hover-card__title { margin-bottom: var(--space-xs); font-size: var(--font-size-md); line-height: var(--ws-leading-row); font-weight: 600; color: var(--color-text-heading); font-variant-numeric: tabular-nums; }
12
+ /* Rows 22: an 18 px line and 2 above and below; the label takes the room and keeps 20 of its own past the 8 px gap, so
13
+ it ends 28 clear of its value (navy semibold). A label that wraps keeps its swatch and value on its first line. */
14
+ .ws-hover-card__row { display: flex; align-items: flex-start; gap: var(--space-xs); padding-block: var(--space-3xs); }
15
+ .ws-hover-card__row > .ws-hover-card__swatch { margin-block: calc((var(--ws-leading-control) - var(--space-xs)) / 2); }
16
+ .ws-hover-card__label { flex: 1; min-width: 0; padding-right: var(--ws-card-inset); }
17
+ .ws-hover-card__value { flex-shrink: 0; font-weight: 600; color: var(--color-text-heading); font-variant-numeric: tabular-nums; white-space: nowrap; }
18
+ /* A rule row (a total, the next section): 8 above and 8 below a hairline that runs the card's full width. */
19
+ .ws-hover-card__row--rule { margin: var(--space-xxs-plus) calc(var(--ws-hover-card-x) * -1) 0; padding: var(--space-xs) var(--ws-hover-card-x) var(--space-3xs); border-top: var(--ws-hairline) solid var(--ws-edge-card); }
20
+ .ws-hover-card__row--rule .ws-hover-card__label { font-weight: 500; color: var(--color-text-heading); }
21
+ /* The ask foot: a full-width strip under a hairline that asks about this mark; the card drops its own bottom room. */
22
+ .ws-hover-card:has(> .ws-hover-card__foot) { padding-bottom: 0; }
23
+ .ws-hover-card__foot { display: flex; align-items: center; gap: var(--space-xxs-plus); margin: var(--space-xs) calc(var(--ws-hover-card-x) * -1) 0; padding: var(--space-xs) var(--ws-hover-card-x); border: 0; border-top: var(--ws-hairline) solid var(--ws-edge-card); border-radius: 0 0 var(--ws-radius-card) var(--ws-radius-card); background: none; font-size: var(--ws-text-dense); line-height: var(--space-md); font-weight: 500; color: var(--color-text-heading); text-align: left; cursor: pointer; transition: background-color var(--ws-duration-hover) var(--ws-ease-soft); }
24
+ .ws-hover-card__foot:focus-visible { outline-offset: calc(var(--ws-focus-width) * -1); }
25
+ @media (hover: hover) { .ws-hover-card__foot:hover { background: var(--ws-hover); } }
26
+ @media (pointer: coarse) { .ws-hover-card__foot { min-height: var(--ws-touch); } }
27
+ /* --compact: the point card (N:388): 8 / 10 inside, 6 px corners, a 12 px semibold title over an 11 px line, 2 apart. */
28
+ .ws-hover-card--compact { gap: var(--space-3xs); min-width: 0; padding: var(--space-xs) var(--space-xs-plus); border-radius: var(--ws-radius-row); }
29
+ .ws-hover-card--compact .ws-hover-card__title { margin-bottom: 0; font-size: var(--ws-text-dense); line-height: var(--space-md); }
30
+ .ws-hover-card__line { font-size: var(--ws-text-micro); line-height: var(--ws-leading-micro); color: var(--color-text-body); }
31
+ /* Placed on a mark: the chart sets left and top to the point (style), --above lifts the card 8 over it, --below drops it
32
+ 8 under; the caret (an 8 px square turned 45, its two outer edges drawn, clipped to its outer half so it never
33
+ paints over the foot, its tint or its focus ring) continues the card's edge to the point.
34
+ --start and --end move the caret to 20% / 80% near a side, so the card never runs off it. */
35
+ .ws-hover-card--above, .ws-hover-card--below { position: absolute; z-index: var(--z-dropdown); }
36
+ .ws-hover-card--above { translate: calc(var(--ws-hover-card-anchor) * -1) calc(-100% - var(--space-xs)); transform-origin: var(--ws-hover-card-anchor) 100%; }
37
+ .ws-hover-card--below { translate: calc(var(--ws-hover-card-anchor) * -1) var(--space-xs); transform-origin: var(--ws-hover-card-anchor) 0; }
38
+ .ws-hover-card--above::after, .ws-hover-card--below::after { content: ""; position: absolute; left: var(--ws-hover-card-anchor); width: var(--space-xs); height: var(--space-xs); background: var(--ws-raised); }
39
+ .ws-hover-card--above::after { top: 100%; border-right: var(--ws-hairline) solid var(--ws-edge-card); border-bottom: var(--ws-hairline) solid var(--ws-edge-card); clip-path: polygon(100% 0, 100% 100%, 0 100%); transform: translate(-50%, calc(var(--ws-nudge) * -1)) rotate(45deg); box-shadow: inset 0 0 0 var(--space-xs) transparent; transition: box-shadow var(--ws-duration-hover) var(--ws-ease-soft); }
40
+ /* Under the ask foot the caret is the foot's own end, so it takes the foot's hover wash with it. */
41
+ @media (hover: hover) { .ws-hover-card--above:has(> .ws-hover-card__foot:hover)::after { box-shadow: inset 0 0 0 var(--space-xs) var(--ws-hover); } }
42
+ .ws-hover-card--below::after { bottom: 100%; border-top: var(--ws-hairline) solid var(--ws-edge-card); border-left: var(--ws-hairline) solid var(--ws-edge-card); clip-path: polygon(0 0, 100% 0, 0 100%); transform: translate(-50%, var(--ws-nudge)) rotate(45deg); }
43
+ .ws-hover-card--start { --ws-hover-card-anchor: 20%; }
44
+ .ws-hover-card--end { --ws-hover-card-anchor: 80%; }
45
+ /* Motion (D7, North's chart tip, js@484880): it pops on the pop spring (.35 / .1, "Tooltip pop-in") from scale .9 and
46
+ 6 px toward its mark, out of the caret's corner, its parts (the foot too) settling in after it 45 ms apart, each over
47
+ .32 s soft (js@483244) where the browser counts siblings (all at once elsewhere); it leaves over .12 s to scale .94
48
+ and 4 px, faster. --follow glides it after the pointer on the follow spring (.22 / 0, "Tooltip follows cursor",
49
+ never a bounce) as the app moves its left and top; leave it off when the app springs it itself. */
50
+ .ws-hover-card { --ws-hover-card-from: var(--ws-rise); --ws-hover-card-to: var(--ws-nudge); }
51
+ .ws-hover-card--below { --ws-hover-card-from: calc(var(--ws-rise) * -1); --ws-hover-card-to: calc(var(--ws-nudge) * -1); }
52
+ @keyframes ws-hover-card-in { from { opacity: 0; transform: translateY(var(--ws-hover-card-from)) scale(0.9); } }
53
+ @keyframes ws-hover-card-out { to { opacity: 0; transform: translateY(var(--ws-hover-card-to)) scale(var(--ws-pop-scale)); } }
54
+ @media (prefers-reduced-motion: no-preference) {
55
+ .ws-hover-card { animation: ws-hover-card-in var(--ws-spring-pop-duration) var(--ws-spring-pop) backwards; }
56
+ .ws-hover-card > * { animation: ws-settle var(--ws-duration-settle) var(--ws-ease-soft) backwards; animation-delay: calc((sibling-index() - 1) * var(--ws-stagger-row)); }
57
+ .ws-hover-card[data-leaving] { animation: ws-hover-card-out var(--ws-duration-exit) var(--ws-ease-exit) forwards; pointer-events: none; }
58
+ .ws-hover-card--follow { transition: left var(--ws-spring-follow-duration) var(--ws-spring-follow), top var(--ws-spring-follow-duration) var(--ws-spring-follow); }
59
+ }
@@ -1,11 +1,13 @@
1
- A round button holding one icon and nothing else, for an act that needs no words to be understood.
1
+ A square button holding one icon and nothing else, for an act that needs no words to be understood.
2
2
 
3
3
  ## Use it when
4
4
 
5
- - The act is a single, well-known icon beside other controls (close, mute, edit, remove) where words would crowd the row.
6
- - The composer's round Send or Talk button, or a header's Mute/End.
7
- - A card's corner needs a quiet remove or dismiss (`xs`, 24px).
8
- - A toggle needs to show as a disc (a mic that is listening, a mark that is set): `selected`.
5
+ - The act is a single, well-known icon beside other controls (close, mute, edit, remove, previous, next) where words
6
+ would crowd the row.
7
+ - A pane's or a card's close (`solid`, Seth's grey square), or a review's Previous and Next.
8
+ - The composer's round Send or Talk (`round`).
9
+ - A card's corner needs a quiet remove or dismiss (`xs`, 24 px).
10
+ - A toggle needs to show it is on (a mic that is listening, a mark that is set): `selected`.
9
11
 
10
12
  ## Not for
11
13
 
@@ -15,50 +17,59 @@ A round button holding one icon and nothing else, for an act that needs no words
15
17
 
16
18
  ## Anatomy
17
19
 
18
- - A disc: `radius-full` corners, no edge by default.
19
- - Size: `xs` 24px, `small` 28px (`--ws-control-h-sm`), `medium` 32px (`--ws-control-h`, the default), `large` 36px
20
- (`--ws-control-h-md`, the composer's round Send/Talk); every size grows to 40px (`--ws-touch`) on a touch screen.
21
- - Icon: 16px (`--ws-icon`) inside `small`/`medium`/`xs`, 20px (`--ws-icon-lg`) inside `large`.
20
+ - A square: 6 px corners (`--ws-radius-row`; 4 at `xs`), no edge by default; `round` makes it a disc.
21
+ - Size: `xs` 24, `small` 28 (`--ws-control-h-sm`), `medium` 32 (`--ws-control-h`, the default), `large` 36
22
+ (`--ws-control-h-md`). On a touch screen every size is a 40 px target: medium and large grow to 40, `xs` and `small`
23
+ keep their look and gain a 40 px hit area round them.
24
+ - Icon: 16 px navy (`--ws-icon`), 20 px inside `large`.
22
25
  - `label` names the act for a screen reader and is its tooltip (never leave it out).
23
26
 
24
27
  ## Variants and sizes
25
28
 
26
29
  | Variant | Fill | Edge | Where |
27
30
  | --- | --- | --- | --- |
28
- | `ghost` | transparent, sunk cream on hover | none | the default: a row or header's quiet icon act |
29
- | `outline` | `--color-bg-page` (cream) | `--ws-shadow-hairline` | an icon act that needs to read as a control at rest |
30
- | `solid` | `--ws-surface-sunk` | none | an icon act that sits on a card without a hover-only hint |
31
- | `primary` | `--color-text-heading` (navy), solid | none | the one act of its place as an icon: Send, a shortlist pick |
31
+ | `ghost` | none, the navy wash under the pointer | none | the default: a row's or a header's quiet icon act |
32
+ | `outline` | none | 0.5 px `--ws-edge-card`, drawn inside | an icon act that must read as a control at rest |
33
+ | `solid` | the tray grey (`--ws-tray`, #EDEDED) | none | Seth's close, Previous and Next |
34
+ | `primary` | navy | none | the one act of its place as an icon: Send, a shortlist pick |
35
+ | `round` (with any) | as its variant | as its variant | the composer's voice and send discs |
32
36
 
33
- Sizes: `xs` (24px), `small` (28px), `medium` (32px, default), `large` (36px).
37
+ Sizes: `xs` (24), `small` (28), `medium` (32, default), `large` (36).
34
38
 
35
39
  ## States
36
40
 
37
41
  - **Default:** as the table above.
38
- - **Hover:** `ghost` and `outline` take the sunk cream; `solid` darkens to `--color-gray-2`; `primary` dims to 90%.
39
- - **Focus:** the kit's focus halo (`--shadow-focus-ring`).
40
- - **Pressed:** scales to 0.97 and springs back.
41
- - **Selected:** a toggle that is on (a mic that is listening, a mark that is set) wears `primary`'s navy regardless of its
42
- own variant, and carries `aria-pressed="true"`.
43
- - **Pending:** its answer is on the way. The icon itself pulses on the working beat (`ws-working`, in full colour, never
44
- greyed); the button stays focusable (`aria-disabled`) and refuses a second click (`aria-busy="true"`).
45
- - **Disabled:** 40% opacity, no pointer events.
42
+ - **Hover (a mouse only):** `ghost` takes the navy wash (`--ws-hover-strong`, North's icon button); `outline` darkens its
43
+ edge (#AAA49D), no fill; `solid` darkens its grey (`--ws-well-hover`); `primary` goes a shade brighter with the light
44
+ under the pointer.
45
+ - **Focus:** the kit's ring, 2 px navy, 2 px out.
46
+ - **Pressed:** gives to 0.97 (a round one, the voice act, to 0.94, `--ws-press-scale-round`; a send act that wears
47
+ `ws-press--send` to 0.92, `--ws-press-scale-send`) and springs back, on North's press spring (`--ws-spring-press`, the
48
+ house's press rule); still under reduced motion.
49
+ - **Selected:** a toggle that is on wears `primary`'s navy whatever its look, with `aria-pressed="true"`. Not for a
50
+ field's own toggle (a password's eye): that one changes its icon and its label instead.
51
+ - **Pending:** its answer is on the way. The icon breathes on the working beat (`ws-working` on the svg) in full colour;
52
+ the button stays focusable (`aria-disabled`) and refuses a second press (`aria-busy="true"`); under the pointer it
53
+ keeps its resting look, so nothing invites the press it refuses.
54
+ - **Pictured states (a preview or a mockup):** `is-hover`, `is-pressed` and `is-focus` draw them still.
55
+ - **Disabled:** 40%, no pointer. A `primary` one sinks instead: the sunk cream with a muted icon, at full opacity.
46
56
  - **Empty / loading:** not a state of its own; the icon is always present.
47
- - **Long label:** not applicable (no visible words); the `label` prop may still be a full sentence for the screen reader.
48
- - **Narrow:** unaffected by width; it never truncates.
49
- - **Touch:** every size grows to 40px square.
57
+ - **Long label:** not applicable (no visible words); `label` may still be a full sentence for the screen reader.
58
+ - **Narrow:** unaffected by width; it never shrinks.
59
+ - **Touch:** every size is a 40 px target.
60
+ - **Dark:** the navy icons become the light ink; the tray grey and the hover grey take their dark values.
50
61
 
51
62
  ## Behaviour
52
63
 
53
64
  - Keyboard: a normal `<button>`; Enter or Space activates it.
54
- - Pointer / touch: hover and press as above; 40px touch floor on every size.
55
- - Motion: background and transform over `--ws-duration-instant` on `--ws-ease-soft`; the pending icon pulses on `--ws-loop`
56
- (1.2s). Everything is still under `prefers-reduced-motion: reduce`.
65
+ - Pointer / touch: hover and press as above.
66
+ - Motion: colours over `--ws-duration-hover` on `--ws-ease-soft`, the press on the press spring; the pending icon
67
+ breathes on `--ws-loop` (1 s). Everything is still under reduced motion.
57
68
 
58
69
  ## Content
59
70
 
60
- - No visible words; `label` is a short, concrete verb phrase ("Mute", "Edit criteria", "Send"), read by assistive tech and
61
- shown as the title.
71
+ - No visible words; `label` is a short, concrete verb phrase ("Mute", "Close", "Previous review"), read by assistive
72
+ tech and shown as the title.
62
73
  - No em dashes in `label`.
63
74
 
64
75
  ## Props
@@ -68,21 +79,41 @@ Sizes: `xs` (24px), `small` (28px), `medium` (32px, default), `large` (36px).
68
79
  | `icon` | `IconName` | which icon it shows |
69
80
  | `label` | `string` | what it is called: `aria-label` and its tooltip |
70
81
  | `variant` | `'ghost' \| 'outline' \| 'solid' \| 'primary'` | the look, default `ghost` |
71
- | `size` | `'xs' \| 'small' \| 'medium' \| 'large'` | the disc's size, default `medium` |
82
+ | `size` | `'xs' \| 'small' \| 'medium' \| 'large'` | the size, default `medium` |
83
+ | `round` | `boolean` | a disc instead of a square (voice, send) |
72
84
  | `selected` | `boolean` | a toggle that is on: navy fill, `aria-pressed` |
73
- | `pending` | `boolean` | its answer is on the way: the icon pulses, `aria-busy`, refuses a click |
74
- | `weight` | `'regular' \| 'bold' \| 'fill'` | the icon's own weight (bold on a navy fill) |
85
+ | `pending` | `boolean` | its answer is on the way: the icon breathes, `aria-busy`, refuses a press |
75
86
  | ...rest | native `<button>` props | passed through (`onClick`, `type`, `disabled`, `aria-*`) |
76
87
 
77
88
  ## Rules
78
89
 
79
- - `pending` keeps the icon in full colour and pulses it (`ws-working`), never greys it out, so waiting never looks broken
80
- (the system's rule, 16 Oct 2026).
90
+ - `pending` keeps the icon in full colour and breathes it (`ws-working`), never greys it, so waiting never looks broken
91
+ (16 Oct 2026).
81
92
  - `label` is required: an icon alone is never the only name for an act.
82
93
  - The one act of its place as an icon (Send, a shortlist pick) is `primary`, navy, matching `Button`'s one-navy rule.
94
+ - A pane closes with a `solid` square holding an x (Seth's drawer, 301:2021).
95
+ - Square by default (Seth's Fia frames and North both draw squares); `round` only for the voice and send discs.
83
96
 
84
97
  ## Source
85
98
 
86
- - **Derived from**: the system's control sizing and pending-state rules (`ws-working`, the shared pending pattern with
87
- `Button`).
88
- - **Precedent**: the first product built on the system.
99
+ **Derived from**: Seth's Fia frames: the drawer's close (301:2021) and the review's Previous and Next (313:2941, 313:2944),
100
+ 32 px squares with 6 px corners on #EDEDED with 16 px navy icons. Seth's North (style1.css:28-30): square icon buttons
101
+ and their .06 navy hover wash; the round voice button's 0.94 press (app.js). The field's fix (Ignite controls.tsx): the
102
+ disabled navy one sinks. **Precedent**: the first product built on the system.
103
+
104
+ ## Markup
105
+
106
+ ```html
107
+ <button type="button" class="ws-icon-btn ws-icon-btn--solid" aria-label="Close" title="Close">
108
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8"/></svg>
109
+ </button>
110
+ <button type="button" class="ws-icon-btn ws-icon-btn--lg ws-icon-btn--round ws-icon-btn--primary" aria-label="Talk" title="Talk">
111
+ <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="6" y="2" width="4" height="7" rx="2"/><path d="M4 7.5a4 4 0 0 0 8 0M8 13.5V15"/></svg>
112
+ </button>
113
+ ```
114
+
115
+ ## Styles
116
+
117
+ `design-system/components/IconButton/style.css`: `ws-icon-btn` with `--xs`, `--sm`, `--lg`, `--round`, `--outline`,
118
+ `--solid`, `--primary`, and the pictured states `is-hover`, `is-pressed`, `is-focus`. The hover values (`--ws-edge-hover`, `--ws-act-hover`, `--ws-act-light`) are scoped in
119
+ `Button/style.css`; the touch targets come from the house's touch block.