@felloinnovations/brand-kit 0.4.0 → 0.5.1

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 +221 -0
  3. package/README.md +38 -9
  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 +135 -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 +367 -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 +53 -16
  249. package/design-system/components/Skeleton/preview.html +35 -23
  250. package/design-system/components/Skeleton/style.css +17 -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 +4086 -744
  335. package/design-system/tokens.json +1310 -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 +109 -10
  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 +173 -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 +1287 -62
  361. package/tokens/tokens.md +587 -61
  362. package/tokens/tokens.root.css +1293 -62
  363. package/tokens/tokens.ts +1677 -64
@@ -1,5 +1,5 @@
1
- A card that sits flat on the chat: one kind, one title, one sentence, its facts on a plate, and a footer band
2
- holding its one act.
1
+ A card the agent brings into the chat (North's chat card: at most 556 px, 20 px inside, the 80 px tray): one kind or one
2
+ chart, one title, one sentence, its facts on a plate or a breakdown, and the tray holding its one act.
3
3
 
4
4
  ## Use it when
5
5
 
@@ -11,27 +11,39 @@ holding its one act.
11
11
 
12
12
  - A simple fact already said in the words above it: say it once, in the chat's text or in the card, never both
13
13
  (the system's rule).
14
- - A drawing, a table, or a comparison of three rows or more: that is a rich card, whole in the side panel, with
15
- only a one-line summary and "Open" left in the chat (the system's rule).
14
+ - A wide table or a long comparison: the chat card holds a chart and a short breakdown (North's chat chart card);
15
+ anything wider opens in the card's own full screen or the side panel, with "Open" left in the chat.
16
16
  - A list of past suggestions: a card is for the one thing in front of the person now; Today's own list lives
17
17
  beside the chat, not repeated here.
18
18
 
19
19
  ## Anatomy
20
20
 
21
- - Shell: `ws-card`, 8 px corners (`--ws-radius-card`), a hairline edge (`--ws-edge-card`), 20 px inside
22
- (`calc(space-md + space-xxs)`), flat (no float shadow).
23
- - Head: a small disc (`--space-lg`, 24 px) with a navy glyph, or salmon-tinted (`--ws-tint-needs`,
24
- `--color-brand-salmon`) while the card waits on the person; its kind name next to it in the eyebrow style (12 px
25
- semibold uppercase, `--letter-spacing-overline`, `--color-text-muted`): "Suggestion", "Task", "Reminder".
26
- - Title: `--font-size-md` (16 px) semibold, `--ws-tracking-title`, navy.
27
- - One sentence: 14 px, `--color-text-body`.
28
- - Facts plate: `--ws-surface-sunk`, 8 px corners, 12 px inside (`--ws-card-padding`).
29
- - Band: `ws-band` across the card's foot (`--ws-chart-foot` ground, `--ws-shadow-band`), 28 px at the sides
30
- (`--ws-band-inset`); the door to what the app owns on the left ("Open in the app", a text act with an
31
- arrow-up-right mark); the buttons on the right at `large` (36 px, `--ws-control-h-md`), every secondary button
32
- first, the one navy primary last.
33
- - A needs-you reminder adds a timer chip (a small ring and its words, `--ws-surface-sunk` ground) in the head, and
34
- a cross icon button (`--ws-control-h-sm`, 28 px) in the card's top right corner for "not now".
21
+ - Shell: `ws-card ws-chat-card`, at most 556 px (`--ws-chart-card-w`), 8 px corners, 20 px inside (`--ws-card-inset`),
22
+ its parts 8 px apart, flat. On the chat's glass it keeps North's 0.5 px card edge (`--ws-edge-card`), not the page's
23
+ tray rim. It measures itself (a size container), so a narrow chat gets the narrow tray.
24
+ - Head (`ws-chat-card__head`, 24 px tall at least, its parts spread): the kind (`ws-chat-card__kind`), a 24 px disc
25
+ (`ws-disc ws-chat-card__disc`) with a navy 12 px glyph, or salmon-tinted (`--needs`: `--ws-tint-needs` behind a `--ws-chart-under-half` glyph) while the
26
+ card waits on the person, and the kind next to it in the eyebrow style ("Suggestion", "Task", "Reminder").
27
+ - Title: `ws-section` (15 / 22 semibold navy) for a kind card; `ws-title` (22 / 28) for a chart answer. One sentence
28
+ under it, 14 / 20 in `--color-text-body`.
29
+ - Facts plate (`ws-plate ws-chat-card__facts`): `Plate` (14 / 16 inside), its facts side by side, 12 px words, 16
30
+ apart and 4 between lines, each name in semibold navy (`b`).
31
+ - A chart answer's drawing (`ws-chat-card__graph`): the dotted field runs to the card's edges and sits only behind the
32
+ drawing, 16 above and 24 under it.
33
+ - A breakdown (`ws-chat-card__rows`): rows edge to edge, 44 px tall, 0.5 px rules (`--ws-edge-slot`), the label 14 / 20
34
+ medium navy on the left, the figure semibold, tabular, at the right.
35
+ - The tray (`ws-band ws-chat-card__band`): the band across the card's foot, 80 px tall, 28 px sides, the darker cream
36
+ and its inset shade; the door on the left ("Open in the app", 24 px tall), the buttons in `ws-band__acts` at the
37
+ right, at `large` (36 px), every secondary first and the one navy primary last.
38
+ - Under 470 px (a narrow chat): the tray is 64 px, 12 / 20, its second line (`ws-band__how`) hides and the title steps
39
+ to 14 / 18 (it wraps, balanced, beside the acts); the acts stay on the title's line at their own width (North keeps
40
+ the docked card on one line) and drop under it together only when they cannot fit (a door and two buttons).
41
+ - A needs-you reminder adds a timer chip in the head (`ws-chat-card__timer`: a 12 px clock and the time left, 12 px
42
+ medium tabular navy on the sunk cream, 2 px corners) and a cross (`ws-icon-btn ws-icon-btn--sm ws-chat-card__close`,
43
+ a 40 px hit area on touch) in the top right corner, 8 px in, for "not now"; the head keeps 32 px clear of it, so the
44
+ timer ends 16 px short of the cross.
45
+ - 0.4 markup's act group, `ws-chat-card__acts`, still lays its buttons out at the band's end; new markup uses
46
+ `ws-band__acts`.
35
47
 
36
48
  ## Variants and sizes
37
49
 
@@ -46,8 +58,7 @@ holding its one act.
46
58
  ## States
47
59
 
48
60
  - **Default**: the card as drawn above.
49
- - **Waits on you**: the head's disc is salmon-tinted; the card is touched once by a soft light as it arrives
50
- (`ws-shine-once`).
61
+ - **Waits on you**: the head's disc is salmon-tinted (`ws-chat-card__disc--needs`).
51
62
  - **Pending**: the pressed button keeps its colour and shows a working dot; the other buttons step out of the way
52
63
  while the tap is in flight.
53
64
  - **Done**: the band's primary becomes a quiet Undo for as long as the act can still be taken back.
@@ -55,7 +66,10 @@ holding its one act.
55
66
  - **Empty**: a card whose data does not exist is never drawn, not even as a placeholder shell.
56
67
  - **Long title**: a question's title is never clamped (the yes it leads to is in it); other kinds clamp to two
57
68
  lines.
58
- - **Narrow**: in the 440 px side panel the band's acts wrap to a second line before anything truncates.
69
+ - **Loading**: a `StatusLine` on top says what the agent is doing, the drawing is a `Skeleton` ghost, the tray holds a
70
+ `LoadBar`; the card is `aria-busy`.
71
+ - **Narrow**: under 470 px the tray goes to 64 px with its acts beside the title; nothing truncates.
72
+ - **Dark**: the edge, the tray and the dots follow the theme.
59
73
 
60
74
  ## Behaviour
61
75
 
@@ -64,10 +78,20 @@ holding its one act.
64
78
  "Not now" is the backend's own dismissal where one exists, kept in the browser otherwise, with 5 seconds to
65
79
  undo.
66
80
  - Pointer and touch: a tap on a button answers at once through the route handler, never a page navigation; the
67
- band's controls sit at the 36 px large size, which already clears the 40 px touch floor with its own padding.
81
+ band's controls sit at the 36 px large size, 40 px on touch (the house touch floor).
68
82
  No side popups: a card acts in place.
69
- - Motion: the card rises in as it arrives (`ws-rise`, `--ws-duration-settle`); a card lit by a "waiting on you"
70
- jump gets a brief mid-blue ring (`--ws-card-ring-lit`), not a float.
83
+ - Motion: a card the app marks `ws-settle` as it arrives rises 6 px out of a 3 px blur on the card spring
84
+ (`--ws-spring-card`, .5 / .08, North's "Chart card arrives"); a chart draws over `--ws-duration-draw-chat`; a card lit
85
+ by a "waiting on you" jump gets a brief ring (`--ws-card-ring-lit`), not a float.
86
+ - Full screen (`ws-chat-card--full`, North's cc-full): the card over the page, the stage inset from the window's edges,
87
+ 16 px corners and the float drop, scrolling on its own. Toggle it inside `morph(update, { as: 'full', el: card })`
88
+ (see `Morph`): it flies there and back as itself over `--ws-duration-morph` (.45 s) on `--ws-ease-morph`, 32 ms late,
89
+ its words never scaling (North's "Full screen: open / close"). morph() lifts it into the top layer while it is full,
90
+ so it covers the window from inside the chat's glass, AppShell's stage or any ancestor with a transform, filter,
91
+ `contain` or `will-change` (a bare `position: fixed` would fill only that ancestor). Its toggle lives in its head
92
+ ("Full screen", then "Back"); Escape closes it as well; focus stays inside it and comes back to the toggle.
93
+ - Reduced motion: it is simply there, and the full screen simply opens and closes.
94
+ - The preview's last stack is live: Arrive and Full screen.
71
95
 
72
96
  ## Content
73
97
 
@@ -94,8 +118,8 @@ view.
94
118
 
95
119
  ## Rules
96
120
 
97
- - **A card sits flat on the chat**: `ws-card`, the cream, the 0.5 px edge, 8 px corners, 20 px inside, as every
98
- card on the pages (26 Oct 2026); no float, a lit card gets its ring instead (the system's rule).
121
+ - **A card sits flat on the chat**: the cream, North's 0.5 px edge, 8 px corners, 20 px inside, at most 556 px; no
122
+ float, a lit card gets its ring instead.
99
123
  - **Its acts sit on the footer band, laid out as a card's band (`ws-band`, see `Card`)** (26 Oct 2026): the door on the left, the buttons on
100
124
  the right, the one primary navy and last, every other button cream with the fine edge.
101
125
  - **Each needs-you card carries a timer and a cross** that means "not now", never a delete, with 5 seconds to
@@ -106,6 +130,68 @@ view.
106
130
 
107
131
  ## Source
108
132
 
109
- **Derived from**: the system's flat card rule (the cream shell, 0.5 px edge, 8 px corners), the footer band
110
- pattern for a door plus buttons, and the needs-you timer-and-cross pattern for a reminder. **Precedent**: the
111
- first product built on the system.
133
+ **Derived from**: North's chat chart card (Figma 733:325166 "card 556 · inset 20 · tray 80"; style1.css:688-733,
134
+ :1154-1190, :2001-2004), the system's footer band for a door plus buttons, and the needs-you timer-and-cross pattern.
135
+ **Precedent**: the first product built on the system.
136
+
137
+ ## Markup
138
+
139
+ ```html
140
+ <div class="ws-card ws-chat-card">
141
+ <p class="ws-title">Calls this week, by agent</p>
142
+ <p class="ws-body">Sam is three behind the team.</p>
143
+ <div class="ws-chat-card__graph ws-dots" aria-hidden="true"><!-- the drawing --></div>
144
+ <ul class="ws-chat-card__rows" aria-label="Calls this week">
145
+ <li class="ws-chat-card__row"><span>Dana Okafor</span><b>12</b></li>
146
+ </ul>
147
+ <div class="ws-band ws-chat-card__band">
148
+ <a class="ws-chat-card__door" href="/team">Open in the app</a>
149
+ <div class="ws-band__acts">
150
+ <button type="button" class="ws-btn ws-btn--secondary ws-btn--lg">Not now</button>
151
+ <button type="button" class="ws-btn ws-btn--primary ws-btn--lg">Line them up</button>
152
+ </div>
153
+ </div>
154
+ </div>
155
+
156
+ <!-- A chart answer that opens full screen: the toggle in its head, run through morph() (see Morph) -->
157
+ <div class="ws-card ws-chat-card">
158
+ <div class="ws-chat-card__head">
159
+ <span class="ws-eyebrow">Chart</span>
160
+ <button type="button" class="ws-btn ws-btn--secondary">Full screen</button><!-- "Back" while full -->
161
+ </div>
162
+ <p class="ws-title">Calls this week, by agent</p>
163
+ <div class="ws-chat-card__graph ws-dots" aria-hidden="true"><!-- the drawing --></div>
164
+ </div>
165
+
166
+ <!-- A needs-you reminder: the cross in the corner, the kind and the timer in the head -->
167
+ <div class="ws-card ws-chat-card">
168
+ <button type="button" class="ws-icon-btn ws-icon-btn--sm ws-chat-card__close" aria-label="Not now: Call Priya back before her offer expires" title="Not now">
169
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
170
+ </button>
171
+ <div class="ws-chat-card__head">
172
+ <span class="ws-chat-card__kind">
173
+ <span class="ws-disc ws-chat-card__disc ws-chat-card__disc--needs" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none"><!-- a bell --></svg></span>
174
+ <span class="ws-eyebrow">Reminder</span>
175
+ </span>
176
+ <span class="ws-chat-card__timer" title="2 hours left">
177
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M8 5v3l2 1.2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
178
+ 2h left
179
+ </span>
180
+ </div>
181
+ <p class="ws-section">Call Priya back before her offer expires</p>
182
+ <p class="ws-body">She asked for a decision by end of day.</p>
183
+ <div class="ws-plate ws-chat-card__facts">
184
+ <span><b>Priya</b> &middot; offer on Oak Street</span>
185
+ </div>
186
+ <div class="ws-band ws-chat-card__band">
187
+ <a class="ws-chat-card__door" href="/leads/priya">Open in the app</a>
188
+ <div class="ws-band__acts"><button type="button" class="ws-btn ws-btn--primary ws-btn--lg">Mark done</button></div>
189
+ </div>
190
+ </div>
191
+ ```
192
+
193
+ ## Styles
194
+
195
+ `ChatCard/style.css`; the band and its acts are `Card`'s, the plate `Plate`'s. Tokens: `--ws-chart-card-w`,
196
+ `--ws-card-inset`, `--ws-edge-card`, `--ws-edge-card-1x`, `--ws-edge-slot`, `--ws-radius-card-inner`, `--ws-tint-needs`,
197
+ `--ws-surface-sunk`.
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Chat" height=574 -->
1
+ <!-- @dsCard group="Chat" height=1217 -->
2
2
  <!doctype html>
3
3
  <html>
4
4
  <head>
@@ -8,12 +8,11 @@
8
8
  <link rel="stylesheet" href="../bundle.css">
9
9
  </head>
10
10
  <body>
11
- <div class="ws-stage" style="justify-content: center;">
12
- <div class="ws-stack ws-stack--group" style="width: var(--ws-column-width); max-width: 100%;">
13
-
11
+ <div class="ws-stage" style="background: var(--ws-frame);">
12
+ <div class="ws-stack ws-stack--group" style="width: var(--ws-chart-card-w);">
14
13
  <div class="ws-stack">
15
14
  <span class="ws-muted">Suggestion: a door on the left, Not now then the one navy act</span>
16
- <div class="ws-card ws-chat-card ws-rise">
15
+ <div class="ws-card ws-chat-card ws-settle">
17
16
  <div class="ws-chat-card__head">
18
17
  <span class="ws-chat-card__kind">
19
18
  <span class="ws-disc ws-chat-card__disc" aria-hidden="true">
@@ -31,49 +30,167 @@
31
30
  <div class="ws-band ws-chat-card__band">
32
31
  <a class="ws-chat-card__door" href="#" onclick="return false;">
33
32
  Open in the app
34
- <svg viewBox="0 0 16 16" fill="none"><path d="M4 12l8-8M7 4h5v5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
33
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M4 12l8-8M7 4h5v5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
35
34
  </a>
36
- <span class="ws-chat-card__acts">
35
+ <div class="ws-band__acts">
37
36
  <button type="button" class="ws-btn ws-btn--secondary ws-btn--lg">Not now</button>
38
37
  <button type="button" class="ws-btn ws-btn--primary ws-btn--lg">Send the nudge</button>
39
- </span>
38
+ </div>
40
39
  </div>
41
40
  </div>
42
41
  </div>
43
42
 
44
43
  <div class="ws-stack">
45
- <span class="ws-muted">Needs-you reminder: a timer, and a cross for &ldquo;not now&rdquo; (5 s to undo)</span>
46
- <div class="ws-card ws-chat-card ws-rise" style="animation-delay: var(--ws-stagger);">
47
- <button type="button" class="ws-icon-btn ws-icon-btn--sm ws-chat-card__close" aria-label="Not now: Call Priya back before her offer expires" title="Not now">
48
- <svg viewBox="0 0 16 16" fill="none"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
49
- </button>
50
- <div class="ws-chat-card__head">
51
- <span class="ws-chat-card__kind">
52
- <span class="ws-disc ws-chat-card__disc ws-chat-card__disc--needs" aria-hidden="true">
53
- <svg viewBox="0 0 16 16" fill="none"><path d="M4.5 11.5V7.8a3.5 3.5 0 0 1 7 0v3.7l1 1.2h-9z" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/><path d="M7 14a1.2 1.2 0 0 0 2 0" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
54
- </span>
55
- <span class="ws-eyebrow">Reminder</span>
56
- </span>
57
- <span class="ws-chat-card__timer" title="2 hours left">
58
- <svg viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M8 5v3l2 1.2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
59
- 2h left
60
- </span>
44
+ <span class="ws-muted">A chart answer: the dots only behind the drawing, a breakdown edge to edge, the tray</span>
45
+ <div class="ws-card ws-chat-card">
46
+ <p class="ws-title">Calls this week, by agent</p>
47
+ <p class="ws-body">Sam is three behind the team; Dana is on pace.</p>
48
+ <div class="ws-chat-card__graph ws-dots" aria-hidden="true">
49
+ <div class="ws-card__bars">
50
+ <div class="ws-card__bar" style="height: 80%;"></div>
51
+ <div class="ws-card__bar" style="height: 55%;"></div>
52
+ <div class="ws-card__bar" style="height: 30%;"></div>
53
+ <div class="ws-card__bar" style="height: 65%;"></div>
54
+ </div>
61
55
  </div>
62
- <p class="ws-section">Call Priya back before her offer expires</p>
63
- <p class="ws-body">She asked for a decision by end of day. The last note on her file is three days old.</p>
56
+ <ul class="ws-chat-card__rows" aria-label="Calls this week">
57
+ <li class="ws-chat-card__row"><span>Dana Okafor</span><b>12</b></li>
58
+ <li class="ws-chat-card__row"><span>Priya Nair</span><b>9</b></li>
59
+ <li class="ws-chat-card__row"><span>Sam Rivera</span><b>4</b></li>
60
+ </ul>
64
61
  <div class="ws-band ws-chat-card__band">
65
- <a class="ws-chat-card__door" href="#" onclick="return false;">
66
- Open in the app
67
- <svg viewBox="0 0 16 16" fill="none"><path d="M4 12l8-8M7 4h5v5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
68
- </a>
69
- <span class="ws-chat-card__acts">
70
- <button type="button" class="ws-btn ws-btn--primary ws-btn--lg">Mark done</button>
62
+ <div class="ws-band__words">
63
+ <p class="ws-band__title">Get Sam one more call</p>
64
+ <p class="ws-band__how">Coach lines up his next three</p>
65
+ </div>
66
+ <div class="ws-band__acts"><button type="button" class="ws-btn ws-btn--primary ws-btn--lg">Line them up</button></div>
67
+ </div>
68
+ </div>
69
+ </div>
70
+
71
+ <div class="ws-stack">
72
+ <span class="ws-muted">Loading: what it is doing on top, a ghost drawing, the load bar in the tray</span>
73
+ <div class="ws-card ws-chat-card" aria-busy="true">
74
+ <p class="ws-status-line" role="status" title="Coach: building the chart, step 2 of 3">
75
+ <b class="ws-status-line__who">Coach</b>
76
+ <span class="ws-status-line__doing">Building the chart</span>
77
+ <span class="ws-status-line__step">2 of 3</span>
78
+ </p>
79
+ <div class="ws-skeleton ws-skeleton--title" style="width: 55%;" aria-hidden="true"></div>
80
+ <div class="ws-skeleton__chart" aria-hidden="true">
81
+ <i style="height: 70%;"></i><i style="height: 45%;"></i><i style="height: 25%;"></i><i style="height: 60%;"></i>
82
+ </div>
83
+ <div class="ws-band ws-chat-card__band">
84
+ <div class="ws-load-bar" style="flex: 1;">
85
+ <p class="ws-load-bar__words"><span class="ws-load-bar__dot" aria-hidden="true"></span>Reading this week&rsquo;s calls</p>
86
+ <span class="ws-load-bar__track" role="progressbar" aria-label="Reading this week's calls"><span class="ws-load-bar__fill"></span></span>
87
+ </div>
88
+ </div>
89
+ </div>
90
+ </div>
91
+ </div>
92
+
93
+ <div class="ws-stack" style="width: 400px;">
94
+ <span class="ws-muted">Needs-you reminder in a narrow chat: a timer, a cross for not now; the tray goes to 64</span>
95
+ <div class="ws-card ws-chat-card">
96
+ <button type="button" class="ws-icon-btn ws-icon-btn--sm ws-chat-card__close" aria-label="Not now: Call Priya back before her offer expires" title="Not now">
97
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
98
+ </button>
99
+ <div class="ws-chat-card__head">
100
+ <span class="ws-chat-card__kind">
101
+ <span class="ws-disc ws-chat-card__disc ws-chat-card__disc--needs" aria-hidden="true">
102
+ <svg viewBox="0 0 16 16" fill="none"><path d="M4.5 11.5V7.8a3.5 3.5 0 0 1 7 0v3.7l1 1.2h-9z" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/><path d="M7 14a1.2 1.2 0 0 0 2 0" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
71
103
  </span>
104
+ <span class="ws-eyebrow">Reminder</span>
105
+ </span>
106
+ <span class="ws-chat-card__timer" title="2 hours left">
107
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M8 5v3l2 1.2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
108
+ 2h left
109
+ </span>
110
+ </div>
111
+ <p class="ws-section">Call Priya back before her offer expires</p>
112
+ <p class="ws-body">She asked for a decision by end of day. The last note on her file is three days old.</p>
113
+ <div class="ws-band ws-chat-card__band">
114
+ <div class="ws-band__words">
115
+ <p class="ws-band__title">Call her now</p>
116
+ <p class="ws-band__how">Her number is on file</p>
72
117
  </div>
118
+ <div class="ws-band__acts"><button type="button" class="ws-btn ws-btn--primary ws-btn--lg">Mark done</button></div>
73
119
  </div>
74
120
  </div>
121
+ </div>
75
122
 
123
+ <div class="ws-stack" style="width: var(--ws-chart-card-w);" data-live>
124
+ <span class="ws-muted">Live: Arrive plays the card coming into the thread on the card spring (.5 / .08); Full screen in its head flies it to the window's full screen and back as itself on the morph curve (.45 s, Morph), lifted above the page; Back or Escape brings it home</span>
125
+ <div class="ws-cluster">
126
+ <button type="button" class="ws-btn ws-btn--secondary" id="cc-live-arrive">Arrive</button>
127
+ </div>
128
+ <div style="min-height: 260px;">
129
+ <div class="ws-card ws-chat-card ws-settle" id="cc-live">
130
+ <div class="ws-chat-card__head"><span class="ws-eyebrow">Chart</span><button type="button" class="ws-btn ws-btn--secondary" id="cc-live-full">Full screen</button></div>
131
+ <p class="ws-title">Calls this week, by agent</p>
132
+ <p class="ws-body">Sam is three behind the team; Dana is on pace.</p>
133
+ <ul class="ws-chat-card__rows" aria-label="Calls this week">
134
+ <li class="ws-chat-card__row"><span>Dana Okafor</span><b>12</b></li>
135
+ <li class="ws-chat-card__row"><span>Sam Rivera</span><b>4</b></li>
136
+ </ul>
137
+ </div>
138
+ </div>
76
139
  </div>
140
+ <script>
141
+ (() => {
142
+ // A copy of morph() from @felloinnovations/brand-kit (src/lib/motion.ts): a preview cannot import the package.
143
+ // `full` lifts the element into the top layer while it is fixed, so no ancestor (a transform, a filter, the glass,
144
+ // contain) can trap it; Escape runs the update again (a toggle) and focus comes back.
145
+ const morph = (() => {
146
+ const lifted = new WeakMap(), root = document.documentElement;
147
+ const FOCUSABLE = 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), summary, [tabindex]:not([tabindex="-1"])';
148
+ let last = 0;
149
+ const place = (el, close) => {
150
+ const was = lifted.get(el);
151
+ if (was) { lifted.delete(el); el.removeEventListener('keydown', was.onKey); if (el.matches(':popover-open')) el.hidePopover(); el.removeAttribute('popover'); delete el.dataset.wsLifted; }
152
+ if (getComputedStyle(el).position === 'fixed' && el.showPopover) {
153
+ const onKey = (e) => { if (e.key !== 'Escape' || e.defaultPrevented || el.querySelector(':popover-open, dialog[open]')) return; e.preventDefault(); morph(close, { as: 'full', el, close }); };
154
+ el.dataset.wsLifted = ''; el.popover = 'manual'; el.showPopover(); el.addEventListener('keydown', onKey);
155
+ lifted.set(el, { opener: was ? was.opener : document.activeElement, onKey });
156
+ if (!el.contains(document.activeElement)) { const to = el.querySelector('[autofocus]') || el.querySelector(FOCUSABLE) || el; if (to === el && !el.hasAttribute('tabindex')) el.tabIndex = -1; to.focus({ preventScroll: true }); }
157
+ } else if (was) { const o = was.opener, here = document.activeElement; if (o && o.isConnected && o !== here && (!here || here === document.body || el.contains(here))) o.focus({ preventScroll: true }); }
158
+ };
159
+ const morph = (update, { as = 'full', el, close } = {}) => {
160
+ const run = as === 'full' && el ? async () => { await update(); place(el, close || update); } : update;
161
+ if (!document.startViewTransition || matchMedia('(prefers-reduced-motion: reduce)').matches) return Promise.resolve(run()).then(() => {});
162
+ const id = ++last;
163
+ if (el) {
164
+ const s = getComputedStyle(el);
165
+ root.style.setProperty('--ws-morph-ground', s.backgroundColor);
166
+ root.style.setProperty('--ws-morph-radius', s.borderRadius);
167
+ root.style.setProperty('--ws-morph-backdrop', s.backdropFilter || 'none');
168
+ el.style.viewTransitionName = 'ws-morph';
169
+ }
170
+ root.dataset.wsMorph = as;
171
+ const move = document.startViewTransition(run);
172
+ move.ready.catch(() => {});
173
+ return move.finished.finally(() => {
174
+ if (el) el.style.viewTransitionName = '';
175
+ if (id !== last) return;
176
+ delete root.dataset.wsMorph;
177
+ for (const p of ['--ws-morph-ground', '--ws-morph-radius', '--ws-morph-backdrop']) root.style.removeProperty(p);
178
+ });
179
+ };
180
+ return morph;
181
+ })();
182
+ const card = document.getElementById('cc-live'), full = document.getElementById('cc-live-full');
183
+ document.getElementById('cc-live-arrive').addEventListener('click', () => {
184
+ card.classList.remove('ws-settle');
185
+ void card.offsetWidth;
186
+ card.classList.add('ws-settle');
187
+ });
188
+ full.addEventListener('click', () => morph(() => {
189
+ const on = card.classList.toggle('ws-chat-card--full');
190
+ full.textContent = on ? 'Back' : 'Full screen';
191
+ }, { as: 'full', el: card }));
192
+ })();
193
+ </script>
77
194
  </div>
78
195
  </body>
79
196
  </html>
@@ -0,0 +1,49 @@
1
+ /* ---- ChatCard: a card the agent brings into the chat (North's chat card: at most 556, 20 inside, the 80 px tray): a door on the left of its band, its acts on the right ---- */
2
+ /* North's chat card keeps the 0.5 px card edge on the chat's glass (the page's tray rim is for page cards). It
3
+ measures itself, so a narrow chat gets the narrow band. */
4
+ .ws-chat-card { position: relative; container: ws-chat-card / inline-size; display: flex; flex-direction: column; gap: var(--space-xs); max-width: var(--ws-chart-card-w); padding: var(--ws-card-inset); border: var(--ws-hairline) solid var(--ws-edge-card); }
5
+ @media (max-resolution: 1.49dppx) { .ws-chat-card { border-color: var(--ws-edge-card-1x); } }
6
+ .ws-chat-card__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-xs); min-height: var(--space-lg); }
7
+ .ws-chat-card__kind { display: flex; align-items: center; gap: var(--space-xs); min-width: 0; }
8
+ .ws-chat-card__disc { width: var(--space-lg); height: var(--space-lg); }
9
+ .ws-chat-card__disc svg { width: var(--ws-icon-sm); height: var(--ws-icon-sm); }
10
+ .ws-chat-card__disc--needs { background: var(--ws-tint-needs); color: var(--ws-chart-under-half); }
11
+ .ws-chat-card__timer { display: inline-flex; align-items: center; gap: var(--space-xxs); padding: var(--space-xxs) var(--space-xs); border-radius: var(--ws-radius-chip); background: var(--ws-surface-sunk); color: var(--color-text-heading); font-size: var(--ws-text-dense); font-weight: 500; font-variant-numeric: tabular-nums; white-space: nowrap; }
12
+ .ws-chat-card__timer svg { width: var(--ws-icon-sm); height: var(--ws-icon-sm); }
13
+ /* The close sits in the corner, 8 in; a head beside it keeps clear of it. */
14
+ .ws-chat-card > .ws-chat-card__close { position: absolute; top: var(--space-xs); right: var(--space-xs); color: var(--color-text-muted); }
15
+ .ws-chat-card:has(> .ws-chat-card__close) > .ws-chat-card__head { padding-right: var(--space-xl); }
16
+ .ws-chat-card__facts { display: flex; flex-wrap: wrap; gap: var(--space-xxs) var(--space-md); font-size: var(--ws-text-dense); color: var(--color-text-body); }
17
+ .ws-chat-card__facts b { font-weight: 600; color: var(--color-text-heading); }
18
+ /* A chart answer's drawing: the dotted field runs to the card's edges and sits only behind the drawing, 24 under it. */
19
+ .ws-chat-card__graph { margin: var(--space-xs) calc(var(--ws-card-inset) * -1) 0; padding: var(--space-md) var(--ws-card-inset) var(--space-lg); }
20
+ /* A breakdown under the answer: rows edge to edge, 44 tall, 0.5 px rules, the label left and the figure right. */
21
+ .ws-chat-card__rows { margin: 0 calc(var(--ws-card-inset) * -1); border-top: var(--ws-hairline) solid var(--ws-edge-slot); }
22
+ .ws-chat-card__row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm); min-height: calc(var(--space-2xl) + var(--space-xxs)); padding: var(--space-xxs) var(--ws-card-inset); font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); font-weight: 500; color: var(--color-text-heading); }
23
+ .ws-chat-card__row + .ws-chat-card__row { border-top: var(--ws-hairline) solid var(--ws-edge-slot); }
24
+ .ws-chat-card__row > b { flex-shrink: 0; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
25
+ /* The tray (the band) runs edge to edge under the card's words, 80 tall at least. */
26
+ .ws-chat-card__band { margin: var(--space-xs) calc(var(--ws-card-inset) * -1) calc(var(--ws-card-inset) * -1); border-radius: 0 0 var(--ws-radius-card-inner) var(--ws-radius-card-inner); }
27
+ .ws-chat-card__door { display: inline-flex; align-items: center; gap: var(--space-xxs); min-height: var(--space-lg); margin-right: auto; font-size: var(--ws-text-body); font-weight: 500; color: var(--color-text-body); text-decoration: none; }
28
+ @media (hover: hover) { .ws-chat-card__door:hover { color: var(--color-text-heading); text-decoration: underline; } }
29
+ .ws-chat-card__door svg { width: var(--ws-icon-sm); height: var(--ws-icon-sm); }
30
+ .ws-chat-card__acts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-xs); margin-left: auto; }
31
+ /* A narrow chat (the card under 470): the tray goes to 64, 12 / 20, its second line hides and the title steps to
32
+ 14 / 18. North keeps the docked card on one line, so the acts stay beside the title at their own width (the band's
33
+ share-the-line rule under 26rem made the tray 92 to 100 tall); they drop under it together only when they cannot fit. */
34
+ @container ws-chat-card (max-width: 470px) {
35
+ .ws-chat-card__band { min-height: var(--space-4xl); column-gap: var(--space-sm); padding: var(--space-sm) var(--ws-card-inset); }
36
+ .ws-chat-card__band .ws-band__how { display: none; }
37
+ .ws-chat-card__band .ws-band__words { min-width: min(100%, var(--space-7xl)); }
38
+ .ws-chat-card__band .ws-band__title { font-size: var(--ws-text-body); line-height: var(--ws-leading-control); text-wrap: balance; }
39
+ .ws-chat-card__band .ws-band__acts { width: auto; }
40
+ .ws-chat-card__band .ws-band__acts > * { flex: none; }
41
+ }
42
+ /* Full screen (North's cc-full, css:751): the card over the page, the stage inset from the window's edges, 16 px corners
43
+ (8 in the thread), the float drop; it scrolls on its own. morph() (Morph, `as: 'full'`) carries it there and back as
44
+ itself and lifts it into the top layer while it is full, so no ancestor with a transform, a filter, a backdrop-filter
45
+ (the glass stage, the chat's glass), contain or will-change can make "full screen" fill only that ancestor. */
46
+ .ws-chat-card--full { position: fixed; inset: var(--ws-stage-inset); z-index: var(--z-modal); width: auto; height: auto; max-width: none; margin: 0; overflow-y: auto; overscroll-behavior: contain; border-radius: var(--ws-radius-panel); box-shadow: var(--ws-shadow-float); }
47
+ /* Motion (D7, North's "Chart card arrives", the card spring .5 / .08): a card the app marks ws-settle as it arrives rises
48
+ 6 px out of a 3 px blur on that spring. Reduced motion: it is simply there. */
49
+ @media (prefers-reduced-motion: no-preference) { .ws-chat-card.ws-settle { animation: ws-settle var(--ws-spring-card-duration) var(--ws-spring-card) backwards; animation-delay: calc(var(--ws-i, 0) * var(--ws-stagger-detail)); } }
@@ -0,0 +1,116 @@
1
+ The chat's frame in three modes: a bar (only the field, over a veiled page), a column docked beside the page, and the
2
+ full screen with one centred reading column.
3
+
4
+ ## Use it when
5
+
6
+ - An app has a chat with its agent that a person opens over, beside or instead of the page they are on.
7
+ - The chat should keep its place: the same thread moves between the bar, the docked column and the full screen.
8
+
9
+ ## Not for
10
+
11
+ - A dialog that asks one thing: use `Dialog`.
12
+ - A side pane of detail: use `Panel`.
13
+ - A page's own ask field that opens the chat: that is a `Composer` on the page; it opens this.
14
+
15
+ ## Anatomy
16
+
17
+ - The shell (`ws-chat-shell`): North's glass (`--ws-glass`, white at 59 % blurred 28 px, `--ws-glass-blur-chat`), a
18
+ 1 px stage edge (`--ws-edge-stage`), 16 px corners; a column. It is not clipped (its parts are inset), so a menu
19
+ inside still shows.
20
+ - The head (`ws-chat-shell__head`): 52 px tall, 20 px in on the left and 12 on the right, 8 px apart: the title
21
+ (`ws-section`), where the chat is (`ws-muted`, cut with a title), then the mode buttons (`IconButton` small, 2 px
22
+ apart; 12 apart on touch, so their 40 px hit areas never overlap) at the end; a 0.5 px navy rule under it (navy at 8 %).
23
+ - The thread (`ws-chat-shell__thread`): the one scroller, 20 px down and 20 px in, the turns (`ChatTurn`) and topic
24
+ heads (`TopicRail`) in it, 64 px of room under the last item so it scrolls clear of the composer.
25
+ - The composer area (`ws-chat-shell__compose`): 8 px above, 12 px at the sides and under, round a `Composer`.
26
+ - The empty chat (`ws-chat-shell__empty`): low in the thread, a 26 / 32 semibold title (`ws-chat-shell__empty-title`),
27
+ one 14 / 20 line 8 px under it,
28
+ the starters (`SuggestionChip`, chat pills) 16 px under that.
29
+
30
+ ## Variants and sizes
31
+
32
+ | Mode | Class | Look |
33
+ | --- | --- | --- |
34
+ | Docked | `ws-chat-shell--dock` in a `ws-chat-dock` | A column 420 px wide (dragged between 340 and 560), no shadow, 12 px beside the page; a resize handle in the gap; AppShell's nav folded to its rail before it |
35
+ | Full screen | `ws-chat-shell--full` | The page card's frame, white at 94 %; the thread and the composer in one centred column at most 760 px, 28 px in at the least; items 24 px apart, 120 px of room under the last |
36
+ | Bar | `ws-chat-shell--bar` | No shell: the field 60 px tall with 8 px corners and the chat bar's drop (`--ws-shadow-bar`; a live call adds the composer's ring), the page starters 14 px under it, over a veil (`ws-chat-veil`) that blurs the page |
37
+
38
+ The resize handle (`ws-chat-shell__resize`): the 12 px gap at the column's right edge, a 3 x 40 grip (navy at 18 %, 36 % under the pointer and while dragged) at
39
+ its middle, a col-resize pointer; a `role="separator"` with its value, moved by the arrow keys in the app, which sets
40
+ `--ws-chat-dock-w` on the shell.
41
+
42
+ ## States
43
+
44
+ - **Open** (North's chat, js@647700): the shell grows in from its mode's side (the bar from its top, the docked column
45
+ from its left edge, the full screen from 40 % down) out of .97 (`--ws-open-scale`) on the panel spring
46
+ (`--ws-spring-panel`, .42 / .12, "Opens / moves / docks"), fading in over `--ws-duration-hover` (.2 s) and out of an
47
+ 8 px blur (`--ws-blur-panel`) over .24 s; its head fades in over `--ws-duration-text` (.25 s), .12 s after it.
48
+ - **Change of mode** (North's "Chat moves between full screen, dock and pop-out", .55 s on the shift curve): the app
49
+ swaps the mode class inside `morph(update, { as: 'shift', el: shell })` from the package (see `Morph`), so the shell
50
+ moves to its new place and size as itself over `--ws-duration-shift` on `--ws-ease-shift`: its words ride in its
51
+ corner at their own size, then the new mode's words fade in from 55 % of the way. The docked width shifts on the
52
+ same curve, never while the handle is dragged (`ws-chat-shell--resizing`). Without view transitions, or with
53
+ reduced motion, the mode simply changes.
54
+ - **Closing** (`data-leaving`): it goes to .97 into a 6 px blur, fading, over .16 s (js@674822), faster than it came;
55
+ remove it 160 ms later.
56
+ - **Empty**: the empty chat with its starters.
57
+ - **Busy**: the answer at work shows a `StatusLine`; nothing else in the shell changes.
58
+ - **Narrow** (a window under 60rem, North's 960): the docked chat takes the whole width and the page waits behind it;
59
+ the handle goes.
60
+ - **Reduced motion**: every mode is simply there.
61
+ - The preview's last stack is live: Full screen and Dock change the mode, Close and Open play the exit and the entrance.
62
+ - **Dark**: the glass, the edge, the veil and the rules follow the theme.
63
+
64
+ ## Behaviour
65
+
66
+ - Keyboard: the head's mode buttons are real buttons with labels; Escape closes the bar; focus moves to the field when
67
+ the chat opens and back to what opened it when it closes.
68
+ - Screen reader: the shell is a labelled region (`aside aria-label="Chat with Coach"`), the thread a labelled list.
69
+ - Pointer: the docked column is resized by its handle; the full screen keeps one reading column at any width.
70
+ - Touch: the head's buttons have 40 px hit areas.
71
+
72
+ ## Content
73
+
74
+ - The title is the agent's name; where it is says which page it reads from ("On Pipeline").
75
+ - The empty title asks what to work on, in the agent's voice, no em dash.
76
+
77
+ ## Rules
78
+
79
+ - One thread, three modes: changing mode never reloads or reorders the chat.
80
+ - The page steps aside for a docked chat; it is never covered by it.
81
+ - In the full screen the reading column stays at most 760 px; a chart answer may break out wider.
82
+
83
+ ## Source
84
+
85
+ **Derived from**: North's chat (style1.css:505-533, :584-591, :786-788, :1296-1300, :1362-1408, :1553-1560;
86
+ js@647700-675000: the glass shell, the 52 px head, 20 / 22 thread inset, 28 between items, the 8 / 12 / 12 composer
87
+ area, the bar's 60 px field and veil, the 420 docked column with its 3 x 40 grip, the 760 full-screen column, the
88
+ open, re-form and shift motions). The thread's sides are 20 here, on the head's edge, where North has 22 against an
89
+ 18 px head (one content edge, D3).
90
+
91
+ ## Markup
92
+
93
+ ```html
94
+ <div class="ws-chat-dock">
95
+ <nav class="ws-app-shell__rail" aria-label="Main"><!-- AppShell's rail --></nav>
96
+ <aside class="ws-chat-shell ws-chat-shell--dock" aria-label="Chat with Coach">
97
+ <header class="ws-chat-shell__head">
98
+ <h2 class="ws-section">Coach</h2>
99
+ <span class="ws-muted ws-chat-shell__where" title="On Pipeline">On Pipeline</span>
100
+ <span class="ws-chat-shell__tools"><!-- small IconButtons: full screen, close --></span>
101
+ </header>
102
+ <ol class="ws-chat-shell__thread" aria-label="Messages"><!-- ChatTurn and topic heads --></ol>
103
+ <div class="ws-chat-shell__compose"><!-- a Composer --></div>
104
+ <button type="button" class="ws-chat-shell__resize" role="separator" aria-orientation="vertical" aria-label="Resize the chat" aria-valuemin="340" aria-valuemax="560" aria-valuenow="420"></button>
105
+ </aside>
106
+ <main><!-- the page --></main>
107
+ </div>
108
+ ```
109
+
110
+ ## Styles
111
+
112
+ `ChatShell/style.css` (its keyframes `ws-chat-open` and `ws-chat-veil` live there). Tokens: `--ws-glass`,
113
+ `--ws-glass-blur-chat`, `--ws-edge-stage`, `--ws-radius-panel`, `--ws-ink`, `--ws-shade`, `--ws-float-rim`,
114
+ `--ws-page`, `--ws-blur-panel`, `--color-surface`, `--ws-hover`, `--ws-duration-calm`, `--ws-duration-shift`,
115
+ `--ws-ease-settle`, `--ws-ease-shift`. The 760 column and the 420 width are component properties (`--ws-chat-col`,
116
+ `--ws-chat-dock-w`).