@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
@@ -9,13 +9,13 @@
9
9
  </head>
10
10
  <body>
11
11
  <div class="ws-stage ws-stage--grey">
12
- <div style="display: grid; grid-template-columns: repeat(2, minmax(220px, 1fr)); gap: var(--ws-gap-component); width: 100%;">
12
+ <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr)); gap: var(--ws-gap-component); width: 100%;">
13
13
 
14
14
  <div class="ws-combobox">
15
15
  <span class="ws-muted">Closed, with a value</span>
16
16
  <label class="ws-label" for="cb-closed">Lead source</label>
17
- <span class="ws-combobox__field" id="cb-closed">
18
- <input type="text" value="Referral" readonly role="combobox" aria-expanded="false">
17
+ <span class="ws-combobox__field">
18
+ <input id="cb-closed" type="text" value="Referral" readonly role="combobox" aria-expanded="false">
19
19
  <svg class="ws-combobox__chevron" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg>
20
20
  </span>
21
21
  </div>
@@ -23,27 +23,28 @@
23
23
  <div class="ws-combobox">
24
24
  <span class="ws-muted">Open, with matches (typed part navy medium, rest body grey)</span>
25
25
  <label class="ws-label" for="cb-open">Street address</label>
26
- <span class="ws-combobox__field ws-combobox__field--focus" id="cb-open">
27
- <input type="text" value="pine" role="combobox" aria-expanded="true" aria-controls="cb-list" aria-activedescendant="cb-opt-1">
26
+ <span class="ws-combobox__field ws-combobox__field--focus">
27
+ <input id="cb-open" type="text" value="pine" role="combobox" aria-expanded="true" aria-controls="cb-list" aria-activedescendant="cb-opt-1">
28
28
  <svg class="ws-combobox__chevron" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg>
29
29
  </span>
30
30
  <div class="ws-menu ws-combobox__panel" role="listbox" id="cb-list">
31
31
  <div class="ws-combobox__option" role="option" id="cb-opt-0"><span class="ws-combobox__match">Pine</span><span class="ws-combobox__rest">wood Drive</span></div>
32
32
  <div class="ws-combobox__option ws-combobox__option--active" role="option" id="cb-opt-1" aria-selected="true"><span class="ws-combobox__match">Pine</span><span class="ws-combobox__rest"> Street</span></div>
33
33
  <div class="ws-combobox__option" role="option" id="cb-opt-2"><span class="ws-combobox__match">Pine</span><span class="ws-combobox__rest"> Hollow Court</span></div>
34
+ <div class="ws-combobox__option" role="option" id="cb-opt-3"><span class="ws-combobox__match">Pine</span><span class="ws-combobox__rest"> Hollow Court, Building 4, Unit 1207, Lakeview Estates North</span></div>
34
35
  </div>
35
36
  </div>
36
37
 
37
38
  <div class="ws-combobox">
38
39
  <span class="ws-muted">No matches, with a create act</span>
39
40
  <label class="ws-label" for="cb-empty">Street address</label>
40
- <span class="ws-combobox__field ws-combobox__field--focus" id="cb-empty">
41
- <input type="text" value="cedar harbor" role="combobox" aria-expanded="true">
41
+ <span class="ws-combobox__field ws-combobox__field--focus">
42
+ <input id="cb-empty" type="text" value="cedar harbor" role="combobox" aria-expanded="true" aria-controls="cb-list-empty">
42
43
  <svg class="ws-combobox__chevron" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg>
43
44
  </span>
44
- <div class="ws-menu ws-combobox__panel">
45
- <div class="ws-combobox__empty">No matches</div>
46
- <div class="ws-combobox__create">
45
+ <div class="ws-menu ws-combobox__panel" role="listbox" id="cb-list-empty">
46
+ <div class="ws-combobox__empty" aria-hidden="true">No matches</div>
47
+ <div class="ws-combobox__create" role="option" id="cb-create">
47
48
  <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3v10M3 8h10"/></svg>
48
49
  Create "Cedar Harbor"
49
50
  </div>
@@ -53,10 +54,32 @@
53
54
  <div class="ws-combobox">
54
55
  <span class="ws-muted">Multi-select: chosen values as chips (TagInput behaviour)</span>
55
56
  <label class="ws-label" for="cb-multi">Call kinds</label>
56
- <span class="ws-combobox__field" id="cb-multi">
57
+ <span class="ws-combobox__field">
57
58
  <span class="ws-combobox__chip">Cold calls<button type="button" aria-label="Remove Cold calls"><svg viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M2 2l6 6M8 2l-6 6"/></svg></button></span>
58
59
  <span class="ws-combobox__chip">Live transfers<button type="button" aria-label="Remove Live transfers"><svg viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M2 2l6 6M8 2l-6 6"/></svg></button></span>
59
- <input type="text" placeholder="Add another" role="combobox" aria-expanded="false">
60
+ <input id="cb-multi" type="text" placeholder="Add another" role="combobox" aria-expanded="false">
61
+ <svg class="ws-combobox__chevron" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg>
62
+ </span>
63
+ </div>
64
+
65
+ <div class="ws-combobox">
66
+ <span class="ws-muted">Error: nothing chosen, with what to do</span>
67
+ <label class="ws-label" for="cb-error">Listing</label>
68
+ <span class="ws-combobox__field">
69
+ <input id="cb-error" type="text" placeholder="Search your listings" role="combobox" aria-expanded="false" aria-invalid="true" aria-describedby="cb-error-msg">
70
+ <svg class="ws-combobox__chevron" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg>
71
+ </span>
72
+ <p class="ws-field-msg ws-field-msg--error" id="cb-error-msg">
73
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 2.3 14.6 13.5H1.4L8 2.3Z"/><path d="M8 6.4v3"/><path d="M8 11.5v.05"/></svg>
74
+ Choose the listing this showing is for
75
+ </p>
76
+ </div>
77
+
78
+ <div class="ws-combobox">
79
+ <span class="ws-muted">Disabled, with a long chosen value (it is cut inside the field)</span>
80
+ <label class="ws-label" for="cb-disabled">Street address</label>
81
+ <span class="ws-combobox__field">
82
+ <input id="cb-disabled" type="text" value="Pine Hollow Court, Building 4, Unit 1207, Lakeview Estates North" role="combobox" aria-expanded="false" disabled>
60
83
  <svg class="ws-combobox__chevron" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg>
61
84
  </span>
62
85
  </div>
@@ -0,0 +1,54 @@
1
+ /* ---- Combobox: a field you type in with a menu of matches under it; chosen values as chips when several. The field
2
+ is Input's (edge inside, darker under the pointer, the focus ring while typing, since its own input draws none). ---- */
3
+ .ws-combobox { position: relative; display: flex; min-width: 0; flex-direction: column; gap: var(--space-xxs); }
4
+ .ws-combobox__field { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-xxs); min-height: var(--ws-control-h); padding: var(--space-3xs) var(--space-xl) var(--space-3xs) var(--space-sm); border: 0; border-radius: var(--ws-radius-control); background: var(--ws-field); box-shadow: var(--ws-shadow-hairline-in); font-size: var(--ws-text-body); color: var(--ws-field-ink); transition: box-shadow var(--ws-duration-hover) var(--ws-ease-soft); }
5
+ @media (hover: hover) { .ws-combobox__field:hover { box-shadow: inset 0 0 0 var(--ws-hairline) var(--ws-edge-hover); } }
6
+ .ws-combobox__field:has(input:focus-visible), .ws-combobox__field--focus { outline: var(--ws-focus-width) solid var(--ws-focus-color); outline-offset: var(--ws-focus-offset); }
7
+ .ws-combobox__field:has(input[aria-invalid="true"]) { box-shadow: inset 0 0 0 var(--ws-line) var(--ws-word-needs); }
8
+ .ws-combobox__chevron { position: absolute; right: var(--space-xs); top: 50%; width: var(--ws-icon); height: var(--ws-icon); transform: translateY(-50%); color: var(--ws-field-mark, var(--color-text-heading)); pointer-events: none; }
9
+ .ws-combobox__field input { flex: 1; min-width: calc(var(--space-4xl) - var(--space-xxs)); height: calc(var(--ws-control-h) - var(--space-xxs)); padding: 0; border: 0; outline: none; background: transparent; font: inherit; line-height: calc(var(--space-md) + var(--space-xxs)); color: inherit; }
10
+ .ws-combobox__field input::placeholder { color: var(--color-text-placeholder); }
11
+ /* The menu of matches: the menu, 8 options tall before it scrolls (and never taller than the window, as every menu),
12
+ growing from its top left, under the field's left edge; the option under the keyboard on the sunk cream. Written on
13
+ .ws-menu so it outweighs Menu's own height and corner. */
14
+ .ws-menu.ws-combobox__panel { --ws-combobox-row: var(--ws-control-h); margin-top: var(--space-xxs); max-height: min(calc(var(--ws-combobox-row) * 8 + var(--space-xxs) * 2), calc(100dvh - var(--space-xl))); overflow-y: auto; transform-origin: top left; }
15
+ /* An option is one run of text, so the typed part and the rest flow as one line and a long one wraps inside the panel
16
+ (never cut, never scrolled sideways); one line is 32 tall. */
17
+ .ws-combobox__option { display: block; padding: calc((var(--ws-combobox-row, var(--ws-control-h)) - var(--space-md) - var(--space-xxs)) / 2) var(--space-sm); border-radius: var(--ws-radius-row); font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); cursor: pointer; }
18
+ @media (hover: hover) { .ws-combobox__option:hover { background: var(--ws-hover); } }
19
+ .ws-combobox__option--active, .ws-combobox__option[aria-selected="true"] { background: var(--ws-surface-sunk); }
20
+ .ws-combobox__match { font-weight: 500; color: var(--color-text-heading); }
21
+ /* pre-wrap keeps the rest's leading space (" Street") and still wraps a long one. */
22
+ .ws-combobox__rest { color: var(--color-text-body); white-space: pre-wrap; }
23
+ .ws-combobox__empty { display: flex; align-items: center; min-height: var(--ws-control-h); padding: 0 var(--space-sm); color: var(--color-text-muted); font-size: var(--ws-text-body); }
24
+ .ws-combobox__create { display: flex; align-items: center; gap: var(--space-xxs-plus); width: 100%; min-height: var(--ws-control-h); padding: 0 var(--space-sm); border: 0; border-radius: var(--ws-radius-row); background: none; font-size: var(--ws-text-body); font-weight: 500; color: var(--color-text-heading); text-align: start; cursor: pointer; }
25
+ @media (hover: hover) { .ws-combobox__create:hover { background: var(--ws-hover); } }
26
+ .ws-combobox__create svg { width: var(--ws-icon-sm); height: var(--ws-icon-sm); }
27
+ /* A chosen value: Chip's tag on the sunk cream, its remove x a 24 px target (a hit area round the 12 px mark; 40 on
28
+ touch, below). */
29
+ /* On the navy ground the field stays white, so a chip there takes the light grey tag and the field's own ink (the
30
+ ground's dark sunk tag read inverted on the white field). */
31
+ .ws-combobox { --ws-combobox-chip: var(--ws-surface-sunk); --ws-combobox-chip-ink: var(--color-text-body); --ws-combobox-chip-hover: var(--ws-hover-strong); }
32
+ [data-theme="dark"][data-ground="navy"] .ws-combobox { --ws-combobox-chip: var(--color-gray-2); --ws-combobox-chip-ink: var(--ws-field-ink); --ws-combobox-chip-hover: color-mix(in srgb, var(--ws-field-ink) 8%, transparent); }
33
+ @media (prefers-color-scheme: dark) { [data-theme="system"][data-ground="navy"] .ws-combobox { --ws-combobox-chip: var(--color-gray-2); --ws-combobox-chip-ink: var(--ws-field-ink); --ws-combobox-chip-hover: color-mix(in srgb, var(--ws-field-ink) 8%, transparent); } }
34
+ .ws-combobox__chip { display: inline-flex; align-items: center; gap: var(--space-xxs); max-width: 100%; height: var(--space-lg); padding: 0 var(--space-xxs) 0 var(--space-xs); border-radius: var(--ws-radius-control); background: var(--ws-combobox-chip); color: var(--ws-combobox-chip-ink); font-size: var(--ws-text-control); line-height: var(--ws-leading-control); font-weight: 500; white-space: nowrap; }
35
+ .ws-combobox__chip button { position: relative; display: inline-flex; align-items: center; justify-content: center; width: var(--space-md); height: var(--space-md); padding: 0; border: 0; border-radius: var(--ws-radius-control); background: none; color: var(--ws-field-mark, var(--color-text-heading)); cursor: pointer; }
36
+ .ws-combobox__chip button::after { content: ""; position: absolute; inset: calc((var(--space-md) - var(--space-lg)) / 2); }
37
+ .ws-combobox__chip button:focus-visible { outline-color: var(--ws-field-mark, var(--ws-focus-color)); outline-offset: 0; }
38
+ @media (hover: hover) { .ws-combobox__chip button:hover { background: var(--ws-combobox-chip-hover); } }
39
+ .ws-combobox__chip svg { width: var(--ws-icon-sm); height: var(--ws-icon-sm); }
40
+ /* Disabled: Input's sunk ground and muted words, no pointer. */
41
+ .ws-combobox__field:has(input:disabled) { background: var(--ws-surface-sunk); color: var(--color-text-muted); cursor: not-allowed; }
42
+ .ws-combobox__field:has(input:disabled) .ws-combobox__chevron { color: var(--color-text-muted); }
43
+ /* Touch: the field is Input's 40 (its words 16, so a phone does not zoom into it), and every row of the menu, the
44
+ create act and the empty line with it, is 40 too (so the panel's 8 rows are 40s). A chip's remove x keeps its 16 px
45
+ mark and gets the 40 px hit area an icon act asks (14-accessibility.md); chips sit 8 apart so that area never reaches
46
+ the next chip. */
47
+ @media (pointer: coarse) {
48
+ .ws-combobox__field { column-gap: var(--space-xs); min-height: var(--ws-touch); font-size: var(--ws-text-value); }
49
+ .ws-combobox__field input { height: calc(var(--ws-touch) - var(--space-xxs)); }
50
+ .ws-menu.ws-combobox__panel { --ws-combobox-row: var(--ws-touch); }
51
+ .ws-combobox__create, .ws-combobox__empty { min-height: var(--ws-touch); }
52
+ .ws-combobox__chip button { min-height: 0; }
53
+ .ws-combobox__chip button::after { inset: calc((var(--space-md) - var(--ws-touch)) / 2); }
54
+ }
@@ -1,10 +1,12 @@
1
- The one chat box, drawn once for the home screen and every chat: one line that grows upward with what is typed, the app
2
- it goes to at its left, and the round action at its right.
1
+ The one chat box (North's), drawn once for the home screen and every chat: a square-cornered field that grows upward
2
+ with what is typed, its tools on the bottom line at the right, and what the question is about riding on top as a tab.
3
3
 
4
4
  ## Use it when
5
5
 
6
6
  - A person writes to an app's assistant or agent from a home screen or a chat.
7
7
  - The same box must also become a live call's: the words field turns into the call's line without changing shape.
8
+ - A question is about something on screen (a chart, a person): the context tab says so above the field.
9
+ - A pane needs its own small ask line (Seth's "Ask Grow about Local search"): the `field` look.
8
10
 
9
11
  ## Not for
10
12
 
@@ -14,50 +16,74 @@ it goes to at its left, and the round action at its right.
14
16
 
15
17
  ## Anatomy
16
18
 
17
- - Box: 52px tall (`--ws-composer-h`), `--ws-radius-control` (4px, the code's own `--ws-radius-input` names the same 4px
18
- step) corners, white ground (`--ws-field`), the fine hairline edge (`--ws-edge-card`).
19
- - Lead (left): a 20px `ws-disc` (`--ws-icon-lg`) holding a generic line icon, and the app or agent's short name at 14px
20
- medium navy next to it, then a 1px rule (`--color-gray-2`) before the words.
21
- - Words: 16px (`--font-size-md`), navy, growing from one line up to a maximum height, then scrolling.
22
- - Trail (right): a plus (attach) and a mic (voice) icon button as the designed trail, then the one round 36px navy
23
- button (Send once there are words, Talk while the box is empty). A product draws only the controls it supports: one
24
- without file attachments or voice leaves those icon buttons out rather than disabling them.
25
- - During a call the same box carries a moving ring instead of its flat edge, and the words field shows what is heard.
19
+ - The area round it, in a chat (`ChatShell`): 8 px above, 12 px at the sides and under (North's 8 / 12 / 12).
20
+ - The field: white (`--ws-field`), the 0.5 px card edge drawn inside (an inset hairline, so nothing clips it), 4 px
21
+ corners (`--ws-radius-control`), 52 px tall at least (`--ws-composer-h`), 8 px inside and 16 px on the left of the
22
+ words. It grows with the words; the tools stay on the bottom line.
23
+ - The tools' line is 36 px (40 on touch); the words, the lead and the rule all centre on it.
24
+ - Words (`ws-composer__words`, a `textarea` that sizes to its content, or an `input`): 16 / 24 in `--ws-field-ink`,
25
+ growing to six lines and then scrolling; the placeholder in `--color-text-muted`.
26
+ - Tools (`ws-composer__trail`, 2 px apart): plus and mic as 36 px square tools (4 px corners, navy 16 px icons, the
27
+ navy 6 % wash under the pointer; a tool that is on, `aria-pressed`, turns into the navy round), then the one round
28
+ navy act: Talk while the box is empty, Send once there are words. A product draws only the tools it supports.
29
+ - The context tab (`ws-composer__context`): what the question is about, riding on the field: 6 / 6 / 6 / 12 inside, the
30
+ field's edge on its top and sides, 4 px top corners, navy at 5 % over white, 13 / 18 words in `--color-text-body` cut
31
+ with a title, a 16 px navy mark and a 24 px close. The field gives up its top corners; tabs stack, split by a 0.5 px
32
+ line.
33
+ - The lead (`ws-composer__lead`, the home screen): the app's 20 px face (`ws-disc ws-composer__face`, a 12 px glyph)
34
+ and short name (`ws-composer__name`, 14 px medium navy), then a 1 px rule (`ws-composer__rule`) 12 px either side,
35
+ before the words.
36
+ - During a call the same box takes the selected ring and the words show what is heard, one line: the lead holds the
37
+ working dot (`ws-dot ws-working ws-composer__dot`), the name and the timer, and the words are a status line
38
+ (`ws-composer__words--empty`, muted, "Listening…") until something is heard.
39
+ - The field look (`--field`): the agent's own 20 px face as a bare `svg.ws-composer__face` (no disc: the face is the
40
+ mark), the words an `input` whose placeholder and value are cut with an ellipsis, never mid-letter, and a plain
41
+ send arrow.
26
42
 
27
43
  ## Variants and sizes
28
44
 
29
45
  | Variant | What it looks like | Where |
30
46
  | --- | --- | --- |
31
- | Default | the app's face and name at the left | the home screen and every app's own chat |
32
- | No lead | the words start flush left, no face or rule | a single assistant's own chat, which has nobody else to address |
33
- | Live | the flat edge becomes a ring (`--ws-ring-selected` stands in for the designer's moving ring), the words field shows "Listening…" or what was heard | a live voice call, the same box, the same chat |
34
-
35
- There is one size: 52px, fixed regardless of how many lines the words expand to (only the inner field grows).
47
+ | Default | The words flush left, the tools at the right | every chat (North's) |
48
+ | With a context tab | A tab on top naming the chart, card or person asked about | a question about something on screen |
49
+ | Lead | The app's face and name at the left, a rule, then the words | the home screen, which addresses one of several apps |
50
+ | Live (`--live`) | The selected ring, the call's timer in the lead, what is heard in the words | a live voice call |
51
+ | Field (`--field`) | 40 px, the tray grey, 8 px corners, 12 px inside, 10 between, the agent's bare 20 px face, 14 / 20 words cut with an ellipsis, a plain send arrow | a pane's own ask line |
36
52
 
37
53
  ## States
38
54
 
39
- - **Empty:** the placeholder ("Message your assistant") shows in `--color-text-muted`; the round button is Talk (a
40
- mic-shaped icon), unless voice is not set up here, in which case there is no Talk at all rather than a button that
41
- only says so.
42
- - **With words:** the round button becomes Send (an upward arrow), enabled only once there is a non-empty, trimmed value.
43
- - **Live (talking):** the round button keeps its navy fill and pulses (`ws-working`, the one working beat, 1.2s) to show
44
- it is listening; a small timer and the call's state sit at the left in place of the app's name.
45
- - **Focus:** the box's edge turns to `--color-border-hairline` while the words field has focus (not the mid-blue ring
46
- other fields use, since the composer is one continuous box, not a boxed field).
47
- - **Pressed:** the trail's buttons press as any `IconButton` does (0.97 scale).
48
- - **Disabled:** not a state of the box itself; offline, the words stay and Send is refused silently rather than greyed.
49
- - **Error:** none of its own; a queued or offline message is a line above the box, not a state on the box.
50
- - **Narrow:** on a phone the box is the full width of the screen; the face and name still fit at the left.
51
- - **Touch:** the trail's icon buttons expand to 40px tall on a touch screen, as every `IconButton` does.
55
+ - **Empty**: the placeholder names who it reaches ("Message Coach"); the round act is Talk, unless voice is not set
56
+ up, in which case there is no Talk at all.
57
+ - **With words**: the round act becomes Send (an upward arrow), enabled once there is a trimmed value.
58
+ - **Focus**: the kit's 2 px navy ring on the box's own edge, drawn inside it, while the words have focus (North draws
59
+ none; the kit needs a visible one, D8). Its tools take their own ring.
60
+ - **Tool on** (dictating): the tool turns into the navy round with its icon in `--ws-on-act`.
61
+ - **Live (talking)**: the ring, the timer at the left; what is heard is one line, cut at the end.
62
+ - **Disabled**: not a state of the box; offline, the words stay and Send is refused, not greyed.
63
+ - **Long words**: the box grows up to six lines, then scrolls inside; nothing is cut off.
64
+ - **Narrow**: on a phone the box is the full width; the tools keep their size.
65
+ - **Touch**: the tools' line is 40 px, so every tool is 40 px; the field look's words go to 16 px, so iOS never zooms in.
66
+ - **Dark**: the field, the edge, the tab and the tools follow the theme. On the navy ground the field stays white, so
67
+ its words, tools, washes, edges and focus ring take the field's navy ink (`--ws-field-ink`), the muted words the
68
+ placeholder grey; the pane field (`--field`) sits on the tray and keeps the ground's own words.
52
69
 
53
70
  ## Behaviour
54
71
 
55
72
  - Keyboard: Enter sends (unless Shift is held, which inserts a new line); Alt+T starts Talk from the keyboard.
56
73
  - Pointer / touch: tapping the box focuses the words field; the box grows upward as more is typed, up to its cap, then
57
74
  scrolls.
58
- - Motion: the box's edge and background transition over `--ws-duration-instant`; the live ring and the pulsing round
59
- button use `ws-working`'s 1.2s beat; nothing pulses under `prefers-reduced-motion: reduce` (the beat is still, the
60
- state is said in words instead).
75
+ - Motion: the tools' wash eases over `--ws-duration-hover`; the live round act pulses on the working beat (`ws-working`,
76
+ 1 s). Focus glow (North's "Focus glow", the glow spring .3 / 0, css:2120): while something in the box has focus a
77
+ soft drop gathers under it (0 4 16, the shade at 7 %) on `--ws-spring-glow`; its edge stays its own and the keyboard
78
+ ring is still the kit's (D8). The pane field, a live call and the chat bar keep their own look.
79
+ - Placeholder roll (North's "Placeholder roll", the roll spring .45 / .05): put the words and a `ws-composer__roll` of a
80
+ few questions in a `ws-composer__slot`, keep the first question as the words' `placeholder` (what a screen reader
81
+ reads; the roll paints it clear), and run `rollPlaceholder(roll)` from the package (it returns a stop, a React
82
+ effect's cleanup). Every 3.4 s the next question rolls up out of 12 px (`--ws-drop`) and a 3 px blur
83
+ (`--ws-blur-arrive`) on `--ws-spring-roll`, the last rolling on up into the blur; the roll goes once there are words.
84
+ Without the script, without `:has()`, or with reduced motion, the first question holds. The main field only.
85
+ Under reduced motion nothing pulses or rolls and the glow simply appears; the state is said in words.
86
+ - The preview's last stack is live: watch the placeholder roll, then click in.
61
87
 
62
88
  ## Content
63
89
 
@@ -77,7 +103,8 @@ There is one size: 52px, fixed regardless of how many lines the words expand to
77
103
 
78
104
  ## Rules
79
105
 
80
- - One chat box, drawn once, for the home screen and every chat, never redrawn per screen.
106
+ - One chat box, drawn once, for the home screen and every chat, never redrawn per screen; a pane's ask line is its
107
+ `field` look, not a new box.
81
108
  - The placeholder always names who it reaches ("Message your assistant"); the header already names the app or agent,
82
109
  so the box itself never repeats that name a second time.
83
110
  - The plus and mic are the designed trail; a product shows only the controls it actually supports (no file upload, no
@@ -86,5 +113,80 @@ There is one size: 52px, fixed regardless of how many lines the words expand to
86
113
 
87
114
  ## Source
88
115
 
89
- **Derived from**: the system's one chat-box pattern, one line that expands upward with the app's lead at the left
90
- and the round action at the right. **Precedent**: the first product built on the system.
116
+ **Derived from**: North's composer (style1.css:1376-1392, :1553-1560: 8 / 12 / 12 round a 52 px square-cornered field
117
+ that grows, + · mic · voice on the right, the context tab riding on top) and Seth's pane field (Grow 301:2104-2105).
118
+ The focus ring is the kit's own (D8). **Precedent**: the first product built on the system.
119
+
120
+ ## Markup
121
+
122
+ ```html
123
+ <div class="ws-composer__context" title="Calls this week, by agent">
124
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><!-- a 16 px mark --></svg>
125
+ <span>Calls this week, by agent</span>
126
+ <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Remove the chart from your question"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M5 5l6 6M11 5l-6 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></button>
127
+ </div>
128
+ <div class="ws-composer">
129
+ <label class="ws-sr" for="ask">Message Coach</label>
130
+ <textarea id="ask" class="ws-composer__words" rows="1" placeholder="Message Coach"></textarea>
131
+ <div class="ws-composer__trail">
132
+ <button type="button" class="ws-icon-btn ws-icon-btn--lg" aria-label="Add a file"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><!-- plus --></svg></button>
133
+ <button type="button" class="ws-icon-btn ws-icon-btn--lg" aria-label="Dictate"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><!-- mic --></svg></button>
134
+ <button type="button" class="ws-icon-btn ws-icon-btn--primary ws-icon-btn--lg" aria-label="Talk with Coach"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><!-- voice --></svg></button>
135
+ </div>
136
+ </div>
137
+
138
+ <!-- With a lead (the home screen) -->
139
+ <div class="ws-composer">
140
+ <div class="ws-composer__lead">
141
+ <span class="ws-disc ws-composer__face" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><!-- the app's mark --></svg></span>
142
+ <span class="ws-composer__name">Coach</span>
143
+ </div>
144
+ <span class="ws-composer__rule" aria-hidden="true"></span>
145
+ <label class="ws-sr" for="ask-home">Message Coach</label>
146
+ <input id="ask-home" class="ws-composer__words" type="text" placeholder="Message Coach">
147
+ <div class="ws-composer__trail"><!-- Talk, the round navy act --></div>
148
+ </div>
149
+
150
+ <!-- Live: a call with Coach -->
151
+ <div class="ws-composer ws-composer--live">
152
+ <div class="ws-composer__lead">
153
+ <span class="ws-dot ws-working ws-composer__dot" aria-hidden="true"></span>
154
+ <span class="ws-composer__name">Coach</span>
155
+ <span class="ws-muted ws-tnum">0:42</span>
156
+ </div>
157
+ <span class="ws-composer__rule" aria-hidden="true"></span>
158
+ <div class="ws-composer__words ws-composer__words--empty" role="status" title="Listening">Listening&hellip;</div>
159
+ <div class="ws-composer__trail"><!-- Mute, then End as the round navy act --></div>
160
+ </div>
161
+
162
+ <!-- The field look, in a pane -->
163
+ <div class="ws-composer ws-composer--field">
164
+ <svg class="ws-composer__face" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 16.5V9l6.5-5.5L16.5 9v7.5Z"/><path d="M8 16.5v-4h4v4"/></svg>
165
+ <label class="ws-sr" for="ask-pane">Ask Grow about Local search</label>
166
+ <input id="ask-pane" class="ws-composer__words" type="text" placeholder="Ask Grow about Local search">
167
+ <div class="ws-composer__trail">
168
+ <button type="button" class="ws-icon-btn" aria-label="Send"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><!-- send arrow --></svg></button>
169
+ </div>
170
+ </div>
171
+
172
+ <!-- The rolling placeholder: the words and the roll share a slot; rollPlaceholder(roll) moves it on every 3.4 s -->
173
+ <div class="ws-composer">
174
+ <label class="ws-sr" for="ask-roll">Message Coach</label>
175
+ <span class="ws-composer__slot">
176
+ <textarea id="ask-roll" class="ws-composer__words" rows="1" placeholder="Who should I call first?"></textarea>
177
+ <span class="ws-composer__roll" aria-hidden="true"><span>Who should I call first?</span><span>Why did calls drop?</span><span>Who needs a nudge?</span></span>
178
+ </span>
179
+ <div class="ws-composer__trail"><!-- Talk, the round navy act --></div>
180
+ </div>
181
+ ```
182
+
183
+ ```ts
184
+ import { rollPlaceholder } from '@felloinnovations/brand-kit';
185
+ useEffect(() => rollPlaceholder(rollRef.current!), []); // returns the stop
186
+ ```
187
+
188
+ ## Styles
189
+
190
+ `Composer/style.css`; the tools are `IconButton`s reshaped inside the trail. Tokens: `--ws-composer-h`, `--ws-field`,
191
+ `--ws-field-ink`, `--ws-edge-card`, `--ws-hairline`, `--ws-radius-control`, `--ws-control-h-md`, `--ws-touch`,
192
+ `--ws-leading-message`, `--ws-hover`, `--ws-hover-strong`, `--ws-on-act`, `--ws-tray`, `--ws-focus-*`.
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Chat" height=324 -->
1
+ <!-- @dsCard group="Chat" height=648 -->
2
2
  <!doctype html>
3
3
  <html>
4
4
  <head>
@@ -8,80 +8,155 @@
8
8
  <link rel="stylesheet" href="../bundle.css">
9
9
  </head>
10
10
  <body>
11
- <div class="ws-stage ws-stage--column">
12
-
13
- <div class="ws-stack">
14
- <span class="ws-muted">Empty: the app or agent chip, the placeholder, plus and mic, Talk</span>
11
+ <div class="ws-stage ws-stage--column" style="background: var(--ws-frame);">
12
+ <div class="ws-stack" style="max-width: 440px;">
13
+ <span class="ws-muted">Empty: the words flush left, plus and mic as square tools, Talk as the round navy act</span>
15
14
  <div class="ws-composer">
16
- <div class="ws-composer__lead">
17
- <span class="ws-disc ws-composer__face" aria-hidden="true">
18
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 4.5h10a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H7l-2.5 2v-2H3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z"/></svg>
19
- </span>
20
- <span class="ws-composer__name">Assistant</span>
21
- </div>
22
- <span class="ws-composer__rule" aria-hidden="true"></span>
23
- <label class="ws-sr" for="composer-empty">Message your assistant</label>
24
- <input id="composer-empty" class="ws-composer__words" type="text" placeholder="Message your assistant">
15
+ <label class="ws-sr" for="composer-empty">Message Coach</label>
16
+ <textarea id="composer-empty" class="ws-composer__words" rows="1" placeholder="Message Coach"></textarea>
25
17
  <div class="ws-composer__trail">
26
- <button class="ws-icon-btn" aria-label="Add a file" title="Add a file">
27
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3v10M3 8h10"/></svg>
18
+ <button type="button" class="ws-icon-btn ws-icon-btn--lg" aria-label="Add a file" title="Add a file">
19
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3v10M3 8h10"/></svg>
28
20
  </button>
29
- <button class="ws-icon-btn" aria-label="Talk with your assistant, by voice" title="Talk">
30
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="2" width="4" height="7" rx="2"/><path d="M4 7.5a4 4 0 0 0 8 0M8 13.5V15M6 15h4"/></svg>
21
+ <button type="button" class="ws-icon-btn ws-icon-btn--lg" aria-label="Dictate" title="Dictate">
22
+ <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.5V15M6 15h4"/></svg>
31
23
  </button>
32
- <button class="ws-icon-btn ws-icon-btn--primary ws-icon-btn--lg" aria-label="Talk with your assistant" title="Talk (Alt+T)">
33
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="2" width="4" height="7" rx="2"/><path d="M4 7.5a4 4 0 0 0 8 0M8 13.5V15M6 15h4"/></svg>
24
+ <button type="button" class="ws-icon-btn ws-icon-btn--primary ws-icon-btn--lg" aria-label="Talk with Coach" title="Talk (Alt+T)">
25
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><path d="M3 6.5v3M5.5 4.5v7M8 2.5v11M10.5 4.5v7M13 6.5v3"/></svg>
34
26
  </button>
35
27
  </div>
36
28
  </div>
37
29
  </div>
38
30
 
39
- <div class="ws-stack">
40
- <span class="ws-muted">With words: Send replaces Talk once there is something to send</span>
31
+ <div class="ws-stack" style="max-width: 440px;">
32
+ <span class="ws-muted">With words and a context tab: what the question is about rides on top; Send replaces Talk</span>
33
+ <div>
34
+ <div class="ws-composer__context" title="Calls this week, by agent">
35
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M2 13.5h12M4 11V7.5M8 11V4M12 11V8.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
36
+ <span>Calls this week, by agent</span>
37
+ <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Remove the chart from your question">
38
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M5 5l6 6M11 5l-6 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
39
+ </button>
40
+ </div>
41
+ <div class="ws-composer__context" title="Sam Rivera">
42
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><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>
43
+ <span>Sam Rivera</span>
44
+ <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Remove Sam Rivera from your question">
45
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M5 5l6 6M11 5l-6 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
46
+ </button>
47
+ </div>
48
+ <div class="ws-composer">
49
+ <label class="ws-sr" for="composer-words">Message Coach</label>
50
+ <textarea id="composer-words" class="ws-composer__words" rows="1">Why is Sam so far behind this week, and what would get him one more cold call before Friday?</textarea>
51
+ <div class="ws-composer__trail">
52
+ <button type="button" class="ws-icon-btn ws-icon-btn--lg" aria-label="Add a file" title="Add a file">
53
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3v10M3 8h10"/></svg>
54
+ </button>
55
+ <button type="button" class="ws-icon-btn ws-icon-btn--lg" aria-label="Dictate" aria-pressed="true" title="Dictating">
56
+ <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.5V15M6 15h4"/></svg>
57
+ </button>
58
+ <button type="button" class="ws-icon-btn ws-icon-btn--primary ws-icon-btn--lg" aria-label="Send" title="Send">
59
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 13V3M4 7l4-4 4 4"/></svg>
60
+ </button>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ </div>
65
+
66
+ <div class="ws-stack" style="max-width: 440px;">
67
+ <span class="ws-muted">With a lead (the home screen): the app's face and name, a rule, then the words</span>
41
68
  <div class="ws-composer">
42
69
  <div class="ws-composer__lead">
43
70
  <span class="ws-disc ws-composer__face" aria-hidden="true">
44
71
  <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 4.5h10a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H7l-2.5 2v-2H3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z"/></svg>
45
72
  </span>
46
- <span class="ws-composer__name">Assistant</span>
73
+ <span class="ws-composer__name">Coach</span>
47
74
  </div>
48
75
  <span class="ws-composer__rule" aria-hidden="true"></span>
49
- <div class="ws-composer__words">Nudge the team to get a cold call in this week</div>
76
+ <label class="ws-sr" for="composer-lead">Message Coach</label>
77
+ <input id="composer-lead" class="ws-composer__words" type="text" placeholder="Message Coach">
50
78
  <div class="ws-composer__trail">
51
- <button class="ws-icon-btn" aria-label="Add a file" title="Add a file">
52
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3v10M3 8h10"/></svg>
53
- </button>
54
- <button class="ws-icon-btn" aria-label="Talk with your assistant, by voice" title="Talk">
55
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="2" width="4" height="7" rx="2"/><path d="M4 7.5a4 4 0 0 0 8 0M8 13.5V15M6 15h4"/></svg>
56
- </button>
57
- <button class="ws-icon-btn ws-icon-btn--primary ws-icon-btn--lg" aria-label="Send" title="Send">
58
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M8 13V3M4 7l4-4 4 4"/></svg>
79
+ <button type="button" class="ws-icon-btn ws-icon-btn--primary ws-icon-btn--lg" aria-label="Talk with Coach" title="Talk (Alt+T)">
80
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><path d="M3 6.5v3M5.5 4.5v7M8 2.5v11M10.5 4.5v7M13 6.5v3"/></svg>
59
81
  </button>
60
82
  </div>
61
83
  </div>
62
84
  </div>
63
85
 
64
- <div class="ws-stack">
65
- <span class="ws-muted">Live: talking with the assistant, the round button pulsing on the working beat</span>
86
+ <div class="ws-stack" style="max-width: 440px;">
87
+ <span class="ws-muted">Live: talking with Coach, the same box ringed, what is heard in the words</span>
66
88
  <div class="ws-composer ws-composer--live">
67
89
  <div class="ws-composer__lead">
68
90
  <span class="ws-dot ws-working ws-composer__dot" aria-hidden="true"></span>
69
- <span class="ws-composer__name">Assistant</span>
91
+ <span class="ws-composer__name">Coach</span>
70
92
  <span class="ws-muted ws-tnum">0:42</span>
71
93
  </div>
72
94
  <span class="ws-composer__rule" aria-hidden="true"></span>
73
- <div class="ws-composer__words ws-composer__words--empty" role="status">Listening…</div>
95
+ <div class="ws-composer__words ws-composer__words--empty" role="status" title="Listening">Listening&hellip;</div>
74
96
  <div class="ws-composer__trail">
75
- <button class="ws-icon-btn" aria-label="Mute" aria-pressed="true" title="Mute">
76
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3l10 10M9.8 9.9A4 4 0 0 1 4 7.5m4-5.2a2 2 0 0 1 2 2V8M6 6V4.3a2 2 0 0 1 .3-1M8 13.5V15M6 15h4"/></svg>
97
+ <button type="button" class="ws-icon-btn ws-icon-btn--lg" aria-label="Mute" title="Mute">
98
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3l10 10M9.8 9.9A4 4 0 0 1 4 7.5m4-5.2a2 2 0 0 1 2 2V8M6 6V4.3a2 2 0 0 1 .3-1M8 13.5V15M6 15h4"/></svg>
77
99
  </button>
78
- <button class="ws-icon-btn ws-icon-btn--primary ws-icon-btn--lg" aria-label="End the call with your assistant" aria-busy="true" title="Talking">
79
- <svg class="ws-working" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="2" width="4" height="7" rx="2"/><path d="M4 7.5a4 4 0 0 0 8 0M8 13.5V15M6 15h4"/></svg>
100
+ <button type="button" class="ws-icon-btn ws-icon-btn--primary ws-icon-btn--lg" aria-label="End the call with Coach" title="End the call">
101
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8"/></svg>
102
+ </button>
103
+ </div>
104
+ </div>
105
+ </div>
106
+
107
+ <div class="ws-stack" style="max-width: 440px;">
108
+ <span class="ws-muted">Field look, in a pane: the tray grey, 40 tall, the agent's face and a send arrow</span>
109
+ <div class="ws-composer ws-composer--field">
110
+ <svg class="ws-composer__face" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 16.5V9l6.5-5.5L16.5 9v7.5Z"/><path d="M8 16.5v-4h4v4"/></svg>
111
+ <label class="ws-sr" for="composer-field">Ask Grow about Local search</label>
112
+ <input id="composer-field" class="ws-composer__words" type="text" placeholder="Ask Grow about Local search">
113
+ <div class="ws-composer__trail">
114
+ <button type="button" class="ws-icon-btn" aria-label="Send" title="Send">
115
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 13V3M4 7l4-4 4 4"/></svg>
80
116
  </button>
81
117
  </div>
82
118
  </div>
83
119
  </div>
84
120
 
121
+ <div class="ws-stack" style="max-width: 440px;" data-live>
122
+ <span class="ws-muted">Live: the placeholder rolls to the next question every 3.4 s on the roll spring, up out of 12 px and a 3 px blur (rollPlaceholder); click in and the focus glow gathers under the box on the glow spring</span>
123
+ <div class="ws-composer">
124
+ <label class="ws-sr" for="composer-live">Message Coach</label>
125
+ <span class="ws-composer__slot">
126
+ <textarea id="composer-live" class="ws-composer__words" rows="1" placeholder="Who should I call first?"></textarea>
127
+ <span class="ws-composer__roll" aria-hidden="true" id="composer-live-roll">
128
+ <span>Who should I call first?</span>
129
+ <span>Why did calls drop?</span>
130
+ <span>Who needs a nudge?</span>
131
+ </span>
132
+ </span>
133
+ <div class="ws-composer__trail">
134
+ <button type="button" class="ws-icon-btn ws-icon-btn--primary ws-icon-btn--lg" aria-label="Talk with Coach" title="Talk (Alt+T)">
135
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><path d="M3 6.5v3M5.5 4.5v7M8 2.5v11M10.5 4.5v7M13 6.5v3"/></svg>
136
+ </button>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ <script>
141
+ (() => {
142
+ // A copy of rollPlaceholder() from @felloinnovations/brand-kit (src/lib/motion.ts): a preview cannot import the package.
143
+ const roll = document.getElementById('composer-live-roll'), lines = [...roll.children];
144
+ let at = 0;
145
+ lines[0].setAttribute('data-on', '');
146
+ if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;
147
+ setInterval(() => {
148
+ const was = lines[at];
149
+ at = (at + 1) % lines.length;
150
+ const next = lines[at];
151
+ for (const l of lines) l.removeAttribute('data-off');
152
+ next.removeAttribute('data-on');
153
+ void next.offsetWidth;
154
+ was.removeAttribute('data-on');
155
+ was.setAttribute('data-off', '');
156
+ next.setAttribute('data-on', '');
157
+ }, 3400);
158
+ })();
159
+ </script>
85
160
  </div>
86
161
  </body>
87
162
  </html>