@felloinnovations/brand-kit 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/AGENTS.md +198 -24
  2. package/CHANGELOG.md +197 -0
  3. package/README.md +34 -7
  4. package/design-system/01-how-claude-decides.md +26 -17
  5. package/design-system/02-principles.md +11 -6
  6. package/design-system/03-colour.md +134 -47
  7. package/design-system/04-type.md +45 -23
  8. package/design-system/05-space-and-layout.md +175 -52
  9. package/design-system/06-sizing-profiles.md +4 -4
  10. package/design-system/07-scrolling.md +66 -20
  11. package/design-system/08-choosing-components.md +50 -22
  12. package/design-system/09-charts.md +71 -28
  13. package/design-system/10-patterns.md +33 -10
  14. package/design-system/11-page-recipes.md +110 -23
  15. package/design-system/12-content.md +2 -1
  16. package/design-system/13-motion.md +330 -47
  17. package/design-system/14-accessibility.md +47 -24
  18. package/design-system/15-ai-experiences.md +11 -6
  19. package/design-system/16-creativity.md +1 -1
  20. package/design-system/17-decisions.md +357 -1
  21. package/design-system/18-checklist.md +79 -16
  22. package/design-system/19-public-pages.md +6 -4
  23. package/design-system/20-palettes.md +275 -0
  24. package/design-system/README.md +30 -17
  25. package/design-system/components/ActionList/README.md +96 -10
  26. package/design-system/components/ActionList/preview.html +52 -7
  27. package/design-system/components/ActionList/style.css +64 -0
  28. package/design-system/components/ActivityGrid/README.md +38 -2
  29. package/design-system/components/ActivityGrid/preview.html +1 -1
  30. package/design-system/components/ActivityGrid/style.css +35 -0
  31. package/design-system/components/AppShell/README.md +205 -75
  32. package/design-system/components/AppShell/preview.html +339 -58
  33. package/design-system/components/AppShell/style.css +154 -0
  34. package/design-system/components/Avatar/README.md +37 -10
  35. package/design-system/components/Avatar/preview.html +13 -4
  36. package/design-system/components/Avatar/style.css +14 -0
  37. package/design-system/components/Badge/README.md +41 -19
  38. package/design-system/components/Badge/preview.html +13 -10
  39. package/design-system/components/Badge/style.css +23 -0
  40. package/design-system/components/Banner/README.md +30 -9
  41. package/design-system/components/Banner/preview.html +1 -1
  42. package/design-system/components/Banner/style.css +19 -0
  43. package/design-system/components/Breadcrumb/README.md +58 -46
  44. package/design-system/components/Breadcrumb/preview.html +16 -16
  45. package/design-system/components/Breadcrumb/style.css +17 -0
  46. package/design-system/components/Button/README.md +113 -55
  47. package/design-system/components/Button/preview.html +98 -25
  48. package/design-system/components/Button/style.css +86 -0
  49. package/design-system/components/Card/README.md +158 -49
  50. package/design-system/components/Card/preview.html +141 -19
  51. package/design-system/components/Card/style.css +115 -0
  52. package/design-system/components/CardBoard/README.md +58 -37
  53. package/design-system/components/CardBoard/preview.html +26 -29
  54. package/design-system/components/ChatCard/README.md +115 -29
  55. package/design-system/components/ChatCard/preview.html +149 -32
  56. package/design-system/components/ChatCard/style.css +49 -0
  57. package/design-system/components/ChatShell/README.md +116 -0
  58. package/design-system/components/ChatShell/preview.html +201 -0
  59. package/design-system/components/ChatShell/style.css +86 -0
  60. package/design-system/components/ChatTurn/README.md +78 -35
  61. package/design-system/components/ChatTurn/preview.html +60 -28
  62. package/design-system/components/ChatTurn/style.css +50 -0
  63. package/design-system/components/CheckRow/README.md +141 -0
  64. package/design-system/components/CheckRow/preview.html +140 -0
  65. package/design-system/components/CheckRow/style.css +88 -0
  66. package/design-system/components/Checkbox/README.md +58 -22
  67. package/design-system/components/Checkbox/preview.html +112 -50
  68. package/design-system/components/Checkbox/style.css +45 -0
  69. package/design-system/components/Chip/README.md +78 -47
  70. package/design-system/components/Chip/preview.html +29 -4
  71. package/design-system/components/Chip/style.css +17 -0
  72. package/design-system/components/Combobox/README.md +44 -11
  73. package/design-system/components/Combobox/preview.html +35 -12
  74. package/design-system/components/Combobox/style.css +54 -0
  75. package/design-system/components/Composer/README.md +137 -35
  76. package/design-system/components/Composer/preview.html +115 -40
  77. package/design-system/components/Composer/style.css +81 -0
  78. package/design-system/components/ConfirmDialog/README.md +73 -52
  79. package/design-system/components/ConfirmDialog/preview.html +70 -26
  80. package/design-system/components/ConfirmDialog/style.css +5 -0
  81. package/design-system/components/Cover/preview.html +3 -3
  82. package/design-system/components/Cover/style.css +19 -0
  83. package/design-system/components/DateInput/README.md +77 -12
  84. package/design-system/components/DateInput/preview.html +27 -12
  85. package/design-system/components/DateInput/style.css +38 -0
  86. package/design-system/components/Dialog/README.md +112 -44
  87. package/design-system/components/Dialog/preview.html +141 -18
  88. package/design-system/components/Dialog/style.css +74 -0
  89. package/design-system/components/EmptyState/README.md +42 -12
  90. package/design-system/components/EmptyState/preview.html +11 -11
  91. package/design-system/components/EmptyState/style.css +9 -0
  92. package/design-system/components/EntryShell/README.md +73 -48
  93. package/design-system/components/EntryShell/preview.html +60 -27
  94. package/design-system/components/EntryShell/style.css +19 -0
  95. package/design-system/components/FeatureGrid/README.md +61 -39
  96. package/design-system/components/FeatureGrid/preview.html +2 -2
  97. package/design-system/components/FeatureGrid/style.css +20 -0
  98. package/design-system/components/FileUpload/README.md +33 -3
  99. package/design-system/components/FileUpload/preview.html +18 -4
  100. package/design-system/components/FileUpload/style.css +23 -0
  101. package/design-system/components/FilterBar/README.md +114 -0
  102. package/design-system/components/FilterBar/preview.html +82 -0
  103. package/design-system/components/FilterBar/style.css +22 -0
  104. package/design-system/components/Fold/README.md +84 -26
  105. package/design-system/components/Fold/preview.html +77 -34
  106. package/design-system/components/Fold/style.css +48 -0
  107. package/design-system/components/Footer/README.md +62 -39
  108. package/design-system/components/Footer/preview.html +5 -5
  109. package/design-system/components/Footer/style.css +30 -0
  110. package/design-system/components/FunnelBars/README.md +24 -3
  111. package/design-system/components/FunnelBars/preview.html +5 -5
  112. package/design-system/components/FunnelBars/style.css +13 -0
  113. package/design-system/components/GoalBars/README.md +54 -10
  114. package/design-system/components/GoalBars/preview.html +69 -28
  115. package/design-system/components/GoalBars/style.css +51 -0
  116. package/design-system/components/GoalTicks/README.md +74 -58
  117. package/design-system/components/GoalTicks/preview.html +41 -118
  118. package/design-system/components/GoalTicks/style.css +37 -0
  119. package/design-system/components/GoalTubes/README.md +29 -3
  120. package/design-system/components/GoalTubes/preview.html +6 -6
  121. package/design-system/components/GoalTubes/style.css +23 -0
  122. package/design-system/components/Heatmap/README.md +133 -0
  123. package/design-system/components/Heatmap/preview.html +168 -0
  124. package/design-system/components/Heatmap/style.css +119 -0
  125. package/design-system/components/Hero/README.md +58 -40
  126. package/design-system/components/Hero/preview.html +1 -1
  127. package/design-system/components/Hero/style.css +19 -0
  128. package/design-system/components/HoverCard/README.md +114 -0
  129. package/design-system/components/HoverCard/preview.html +107 -0
  130. package/design-system/components/HoverCard/style.css +59 -0
  131. package/design-system/components/IconButton/README.md +69 -38
  132. package/design-system/components/IconButton/preview.html +77 -43
  133. package/design-system/components/IconButton/style.css +45 -0
  134. package/design-system/components/Input/README.md +36 -11
  135. package/design-system/components/Input/preview.html +1 -1
  136. package/design-system/components/Input/style.css +23 -0
  137. package/design-system/components/KanbanBoard/README.md +93 -45
  138. package/design-system/components/KanbanBoard/preview.html +159 -43
  139. package/design-system/components/KanbanBoard/style.css +53 -0
  140. package/design-system/components/Kbd/README.md +25 -9
  141. package/design-system/components/Kbd/preview.html +6 -2
  142. package/design-system/components/Kbd/style.css +9 -0
  143. package/design-system/components/KitButton/README.md +81 -47
  144. package/design-system/components/KitButton/preview.html +35 -13
  145. package/design-system/components/KitButton/style.css +46 -0
  146. package/design-system/components/KitCard/README.md +75 -44
  147. package/design-system/components/KitCard/preview.html +18 -10
  148. package/design-system/components/KitCard/style.css +15 -0
  149. package/design-system/components/KitInput/README.md +54 -39
  150. package/design-system/components/KitInput/preview.html +7 -7
  151. package/design-system/components/KitInput/style.css +23 -0
  152. package/design-system/components/Leaderboard/README.md +76 -49
  153. package/design-system/components/Leaderboard/preview.html +61 -26
  154. package/design-system/components/Leaderboard/style.css +44 -0
  155. package/design-system/components/ListDetail/README.md +222 -0
  156. package/design-system/components/ListDetail/preview.html +213 -0
  157. package/design-system/components/ListDetail/style.css +148 -0
  158. package/design-system/components/LoadBar/README.md +79 -0
  159. package/design-system/components/LoadBar/preview.html +40 -0
  160. package/design-system/components/LoadBar/style.css +17 -0
  161. package/design-system/components/MarketingNav/README.md +76 -42
  162. package/design-system/components/MarketingNav/preview.html +37 -8
  163. package/design-system/components/MarketingNav/style.css +45 -0
  164. package/design-system/components/Matrix/README.md +129 -0
  165. package/design-system/components/Matrix/preview.html +99 -0
  166. package/design-system/components/Matrix/style.css +84 -0
  167. package/design-system/components/Menu/README.md +117 -41
  168. package/design-system/components/Menu/preview.html +85 -23
  169. package/design-system/components/Menu/style.css +61 -0
  170. package/design-system/components/Meter/README.md +39 -4
  171. package/design-system/components/Meter/preview.html +18 -1
  172. package/design-system/components/Meter/style.css +23 -0
  173. package/design-system/components/MetricTile/README.md +237 -0
  174. package/design-system/components/MetricTile/preview.html +241 -0
  175. package/design-system/components/MetricTile/style.css +129 -0
  176. package/design-system/components/Morph/README.md +106 -0
  177. package/design-system/components/Morph/preview.html +103 -0
  178. package/design-system/components/Morph/style.css +31 -0
  179. package/design-system/components/Motion/README.md +164 -0
  180. package/design-system/components/Motion/preview.html +2537 -0
  181. package/design-system/components/NumberInput/README.md +27 -8
  182. package/design-system/components/NumberInput/preview.html +21 -5
  183. package/design-system/components/NumberInput/style.css +34 -0
  184. package/design-system/components/PaceBar/README.md +75 -0
  185. package/design-system/components/PaceBar/preview.html +67 -0
  186. package/design-system/components/PaceBar/style.css +25 -0
  187. package/design-system/components/Page/README.md +57 -18
  188. package/design-system/components/Page/preview.html +15 -17
  189. package/design-system/components/Page/style.css +7 -0
  190. package/design-system/components/PageBar/README.md +90 -34
  191. package/design-system/components/PageBar/preview.html +60 -19
  192. package/design-system/components/PageBar/style.css +35 -0
  193. package/design-system/components/PageHero/README.md +87 -51
  194. package/design-system/components/PageHero/preview.html +35 -6
  195. package/design-system/components/PageHero/style.css +31 -0
  196. package/design-system/components/Pagination/README.md +70 -49
  197. package/design-system/components/Pagination/preview.html +24 -15
  198. package/design-system/components/Pagination/style.css +12 -0
  199. package/design-system/components/Panel/README.md +109 -51
  200. package/design-system/components/Panel/preview.html +118 -20
  201. package/design-system/components/Panel/style.css +51 -0
  202. package/design-system/components/PasswordInput/README.md +50 -18
  203. package/design-system/components/PasswordInput/preview.html +71 -21
  204. package/design-system/components/PasswordInput/style.css +31 -0
  205. package/design-system/components/Plate/README.md +75 -17
  206. package/design-system/components/Plate/preview.html +40 -7
  207. package/design-system/components/Plate/style.css +37 -0
  208. package/design-system/components/Popover/README.md +70 -49
  209. package/design-system/components/Popover/preview.html +44 -22
  210. package/design-system/components/Popover/style.css +41 -0
  211. package/design-system/components/PricingTable/README.md +69 -49
  212. package/design-system/components/PricingTable/preview.html +21 -21
  213. package/design-system/components/PricingTable/style.css +21 -0
  214. package/design-system/components/ProgressPetals/README.md +31 -3
  215. package/design-system/components/ProgressPetals/preview.html +14 -15
  216. package/design-system/components/ProgressPetals/style.css +27 -0
  217. package/design-system/components/README.md +151 -0
  218. package/design-system/components/Radio/README.md +40 -17
  219. package/design-system/components/Radio/preview.html +16 -1
  220. package/design-system/components/Radio/style.css +21 -0
  221. package/design-system/components/RankBar/README.md +29 -2
  222. package/design-system/components/RankBar/preview.html +14 -12
  223. package/design-system/components/RankBar/style.css +18 -0
  224. package/design-system/components/Ring/README.md +61 -11
  225. package/design-system/components/Ring/preview.html +55 -10
  226. package/design-system/components/Ring/style.css +49 -0
  227. package/design-system/components/ScoreHero/README.md +91 -0
  228. package/design-system/components/ScoreHero/preview.html +104 -0
  229. package/design-system/components/ScoreHero/style.css +32 -0
  230. package/design-system/components/Section/README.md +72 -33
  231. package/design-system/components/Section/preview.html +46 -16
  232. package/design-system/components/Section/style.css +18 -0
  233. package/design-system/components/Segmented/README.md +100 -55
  234. package/design-system/components/Segmented/preview.html +107 -26
  235. package/design-system/components/Segmented/style.css +94 -0
  236. package/design-system/components/SegmentedProgress/README.md +64 -0
  237. package/design-system/components/SegmentedProgress/preview.html +69 -0
  238. package/design-system/components/SegmentedProgress/style.css +11 -0
  239. package/design-system/components/Select/README.md +47 -12
  240. package/design-system/components/Select/preview.html +28 -2
  241. package/design-system/components/Select/style.css +22 -0
  242. package/design-system/components/ShareBar/README.md +69 -0
  243. package/design-system/components/ShareBar/preview.html +72 -0
  244. package/design-system/components/ShareBar/style.css +25 -0
  245. package/design-system/components/SideList/README.md +147 -0
  246. package/design-system/components/SideList/preview.html +139 -0
  247. package/design-system/components/SideList/style.css +94 -0
  248. package/design-system/components/Skeleton/README.md +52 -16
  249. package/design-system/components/Skeleton/preview.html +35 -23
  250. package/design-system/components/Skeleton/style.css +22 -0
  251. package/design-system/components/Slider/README.md +95 -0
  252. package/design-system/components/Slider/preview.html +49 -0
  253. package/design-system/components/Slider/style.css +13 -0
  254. package/design-system/components/Split/README.md +112 -0
  255. package/design-system/components/Split/preview.html +105 -0
  256. package/design-system/components/Split/style.css +30 -0
  257. package/design-system/components/Starter/README.md +21 -9
  258. package/design-system/components/Starter/preview.html +5 -5
  259. package/design-system/components/Stat/README.md +64 -43
  260. package/design-system/components/Stat/preview.html +3 -3
  261. package/design-system/components/Stat/style.css +15 -0
  262. package/design-system/components/StatTiles/README.md +88 -44
  263. package/design-system/components/StatTiles/preview.html +142 -71
  264. package/design-system/components/StatTiles/style.css +64 -0
  265. package/design-system/components/StatusLine/README.md +85 -0
  266. package/design-system/components/StatusLine/preview.html +49 -0
  267. package/design-system/components/StatusLine/style.css +14 -0
  268. package/design-system/components/StatusScreen/README.md +49 -35
  269. package/design-system/components/StatusScreen/preview.html +20 -5
  270. package/design-system/components/StatusScreen/style.css +9 -0
  271. package/design-system/components/StepLine/README.md +97 -0
  272. package/design-system/components/StepLine/preview.html +108 -0
  273. package/design-system/components/StepLine/style.css +62 -0
  274. package/design-system/components/Stepper/README.md +35 -13
  275. package/design-system/components/Stepper/style.css +13 -0
  276. package/design-system/components/StreakCalendar/README.md +22 -1
  277. package/design-system/components/StreakCalendar/preview.html +10 -10
  278. package/design-system/components/StreakCalendar/style.css +12 -0
  279. package/design-system/components/SuggestionChip/README.md +87 -0
  280. package/design-system/components/SuggestionChip/preview.html +42 -0
  281. package/design-system/components/SuggestionChip/style.css +20 -0
  282. package/design-system/components/Switch/README.md +44 -24
  283. package/design-system/components/Switch/preview.html +23 -8
  284. package/design-system/components/Switch/style.css +31 -0
  285. package/design-system/components/Table/README.md +129 -58
  286. package/design-system/components/Table/preview.html +106 -72
  287. package/design-system/components/Table/style.css +104 -0
  288. package/design-system/components/Tabs/README.md +71 -46
  289. package/design-system/components/Tabs/preview.html +56 -24
  290. package/design-system/components/Tabs/style.css +44 -0
  291. package/design-system/components/Testimonial/README.md +48 -32
  292. package/design-system/components/Testimonial/preview.html +14 -14
  293. package/design-system/components/Testimonial/style.css +12 -0
  294. package/design-system/components/TextArea/README.md +27 -11
  295. package/design-system/components/TextArea/preview.html +8 -2
  296. package/design-system/components/TextArea/style.css +12 -0
  297. package/design-system/components/ThemeSwitch/README.md +116 -0
  298. package/design-system/components/ThemeSwitch/preview.html +57 -0
  299. package/design-system/components/ThemeSwitch/style.css +6 -0
  300. package/design-system/components/TickRow/README.md +52 -36
  301. package/design-system/components/TickRow/preview.html +64 -41
  302. package/design-system/components/TickRow/style.css +23 -0
  303. package/design-system/components/TickStrip/README.md +95 -0
  304. package/design-system/components/TickStrip/preview.html +88 -0
  305. package/design-system/components/TickStrip/style.css +42 -0
  306. package/design-system/components/Tile/README.md +79 -18
  307. package/design-system/components/Tile/preview.html +91 -40
  308. package/design-system/components/Tile/style.css +36 -0
  309. package/design-system/components/Timeline/README.md +68 -48
  310. package/design-system/components/Timeline/preview.html +27 -15
  311. package/design-system/components/Timeline/style.css +25 -0
  312. package/design-system/components/Toast/README.md +70 -38
  313. package/design-system/components/Toast/preview.html +43 -8
  314. package/design-system/components/Toast/style.css +25 -0
  315. package/design-system/components/Tooltip/README.md +93 -35
  316. package/design-system/components/Tooltip/preview.html +69 -15
  317. package/design-system/components/Tooltip/style.css +78 -0
  318. package/design-system/components/TopBar/README.md +67 -53
  319. package/design-system/components/TopBar/preview.html +14 -27
  320. package/design-system/components/TopBar/style.css +35 -0
  321. package/design-system/components/TopicRail/README.md +108 -0
  322. package/design-system/components/TopicRail/preview.html +58 -0
  323. package/design-system/components/TopicRail/style.css +48 -0
  324. package/design-system/components/TrendBars/README.md +52 -14
  325. package/design-system/components/TrendBars/preview.html +65 -32
  326. package/design-system/components/TrendBars/style.css +25 -0
  327. package/design-system/components/TrendLine/README.md +164 -0
  328. package/design-system/components/TrendLine/preview.html +373 -0
  329. package/design-system/components/TrendLine/style.css +155 -0
  330. package/design-system/components/Well/README.md +64 -22
  331. package/design-system/components/Well/preview.html +14 -14
  332. package/design-system/components/Well/style.css +22 -0
  333. package/design-system/components/_house.css +324 -0
  334. package/design-system/components/bundle.css +4091 -744
  335. package/design-system/tokens.json +1314 -124
  336. package/dist/fello-core.css +2 -2
  337. package/dist/fello.css +6 -1369
  338. package/dist/fello.scoped.css +7 -0
  339. package/dist/index.d.ts +110 -11
  340. package/dist/index.js +781 -96
  341. package/dist/palettes.d.ts +464 -0
  342. package/dist/palettes.js +497 -0
  343. package/dist/scoped.d.ts +3 -0
  344. package/dist/scoped.js +16 -0
  345. package/dist/toast.d.ts +14 -0
  346. package/dist/toast.js +33 -29
  347. package/dist/tokens.d.ts +1686 -62
  348. package/dist/tokens.js +1668 -61
  349. package/package.json +20 -4
  350. package/scripts/check-palette.mjs +295 -0
  351. package/scripts/token-model.mjs +552 -0
  352. package/tokens/_dark.css +174 -0
  353. package/tokens/_palettes.css +46 -0
  354. package/tokens/_product.css +266 -53
  355. package/tokens/_source.hubl.css +39 -19
  356. package/tokens/design-tokens.json +319 -0
  357. package/tokens/palettes.ts +504 -0
  358. package/tokens/shadcn-compat.css +19 -19
  359. package/tokens/shadcn-compat.hsl.css +76 -0
  360. package/tokens/tokens.css +1292 -62
  361. package/tokens/tokens.md +588 -61
  362. package/tokens/tokens.root.css +1298 -62
  363. package/tokens/tokens.ts +1677 -64
@@ -0,0 +1,81 @@
1
+ /* ---- Composer: the one chat box (North's): a square-cornered field 52 tall that grows with the words, its tools on the bottom line, a context tab riding on top ---- */
2
+ /* The field: white, the 0.5 px card edge, 4 px corners, 52 at least, 8 inside (16 on the left of the words). It grows
3
+ with the words and its tools stay on the bottom line. Focus draws the kit's 2 px navy ring on the box's own edge
4
+ (inside it, so the composer area never has to make room for it). */
5
+ .ws-composer { --ws-composer-line: var(--ws-control-h-md); display: flex; align-items: flex-end; gap: var(--space-3xs); min-height: var(--ws-composer-h); padding: var(--space-xs) var(--space-xs) var(--space-xs) var(--space-md); border-radius: var(--ws-radius-control); background: var(--ws-field); box-shadow: inset 0 0 0 var(--ws-hairline) var(--ws-edge-card); color: var(--ws-field-ink); }
6
+ .ws-composer:has(.ws-composer__words:focus-visible) { outline: var(--ws-focus-width) solid var(--ws-focus-color); outline-offset: calc(var(--ws-focus-width) * -1); }
7
+ .ws-composer__words:focus-visible { outline: none; }
8
+ .ws-composer--live { box-shadow: inset 0 0 0 var(--ws-hairline) var(--ws-edge-card), var(--ws-ring-selected); }
9
+ /* The lead (the home screen's address line): the app's 20 px face and short name, then a 1 px rule, on the tools' line. */
10
+ .ws-composer__lead { display: flex; flex-shrink: 0; align-items: center; gap: var(--space-xs); height: var(--ws-composer-line); }
11
+ .ws-composer__face { flex-shrink: 0; width: var(--ws-icon-lg); height: var(--ws-icon-lg); }
12
+ .ws-composer__face svg { width: var(--ws-icon-sm); height: var(--ws-icon-sm); }
13
+ .ws-composer__name { font-size: var(--ws-text-body); font-weight: 500; color: var(--color-text-heading); white-space: nowrap; }
14
+ .ws-composer__rule { flex-shrink: 0; align-self: flex-end; width: var(--ws-line); height: var(--ws-icon-lg); margin: 0 var(--space-sm) calc((var(--ws-composer-line) - var(--ws-icon-lg)) / 2); background: var(--ws-track); }
15
+ /* The words: 16 / 24, one line 36 tall (6 above and under, centred on the tools' line), growing to 6 lines then scrolling. */
16
+ .ws-composer__words { flex: 1; min-width: 0; min-height: var(--ws-composer-line); max-height: var(--space-8xl); margin: 0; padding: calc((var(--ws-composer-line) - var(--ws-leading-message)) / 2) var(--space-3xs) calc((var(--ws-composer-line) - var(--ws-leading-message)) / 2) 0; border: 0; background: transparent; font-size: var(--ws-text-value); line-height: var(--ws-leading-message); color: var(--ws-field-ink); resize: none; field-sizing: content; overflow-wrap: anywhere; }
17
+ textarea.ws-composer__words { overflow-y: auto; }
18
+ /* A one-line field (an input) cuts its words and its placeholder with an ellipsis, never mid-letter. */
19
+ input.ws-composer__words { text-overflow: ellipsis; }
20
+ .ws-composer__words::placeholder, .ws-composer__words--empty { color: var(--color-text-muted); }
21
+ /* The tools on the right, 2 apart: plus and mic as 36 square tools (a tool that is on turns into the navy round), then
22
+ the one round navy act, Talk or Send. */
23
+ .ws-composer__trail { display: flex; flex-shrink: 0; align-items: center; gap: var(--space-3xs); }
24
+ .ws-composer__trail > .ws-icon-btn { width: var(--ws-composer-line); height: var(--ws-composer-line); color: var(--color-text-heading); }
25
+ .ws-composer__trail > .ws-icon-btn:not(.ws-icon-btn--primary, [aria-pressed="true"]) { border-radius: var(--ws-radius-control); }
26
+ .ws-composer__trail > .ws-icon-btn:is(.ws-icon-btn--primary, [aria-pressed="true"]) { border-radius: var(--radius-full); color: var(--ws-on-act); }
27
+ .ws-composer__trail > .ws-icon-btn svg { width: var(--ws-icon); height: var(--ws-icon); }
28
+ @media (hover: hover) { .ws-composer__trail > .ws-icon-btn:not(.ws-icon-btn--primary, [aria-pressed="true"]):hover { background: var(--ws-hover-strong); } }
29
+ /* Touch: the tools' line is 40, and the words, the lead and the rule centre on it. */
30
+ @media (pointer: coarse) { .ws-composer { --ws-composer-line: var(--ws-touch); } }
31
+ /* Live: what is heard is one line, cut at the end (give it a title). */
32
+ .ws-composer--live .ws-composer__words { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
33
+ .ws-composer__dot { margin-right: var(--space-xxs); }
34
+ /* The context tab: what the question is about, riding on the field (padding 6 / 6 / 6 / 12, the field's edge on its
35
+ top and sides only, 4 px top corners, a faint navy tint); the field gives up its top corners. Tabs stack, split by a
36
+ 0.5 px line. */
37
+ .ws-composer__context { display: flex; align-items: center; gap: var(--space-xs); padding: var(--space-xxs-plus) var(--space-xxs-plus) var(--space-xxs-plus) var(--space-sm); border-radius: var(--ws-radius-control) var(--ws-radius-control) 0 0; box-shadow: inset 0 var(--ws-hairline) 0 var(--ws-edge-card), inset var(--ws-hairline) 0 0 var(--ws-edge-card), inset calc(var(--ws-hairline) * -1) 0 0 var(--ws-edge-card); background: linear-gradient(var(--ws-hover), var(--ws-hover)) var(--ws-field); font-size: var(--ws-text-control); line-height: var(--ws-leading-control); color: var(--color-text-body); }
38
+ .ws-composer__context > svg { flex-shrink: 0; width: var(--ws-icon); height: var(--ws-icon); color: var(--color-text-heading); }
39
+ .ws-composer__context > span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
40
+ .ws-composer__context + .ws-composer__context { border-radius: 0; box-shadow: inset 0 var(--ws-hairline) 0 var(--ws-edge-slot), inset var(--ws-hairline) 0 0 var(--ws-edge-card), inset calc(var(--ws-hairline) * -1) 0 0 var(--ws-edge-card); }
41
+ .ws-composer__context + .ws-composer { border-top-left-radius: 0; border-top-right-radius: 0; }
42
+ /* The field look, for a pane (Seth's "Ask Grow"): 40 tall, the tray grey, 8 px corners, 12 inside and 10 between its
43
+ parts, a 20 px face, 14 / 20 words and a 16 px send arrow. */
44
+ .ws-composer--field { align-items: center; gap: var(--space-xs-plus); min-height: var(--space-2xl); padding: 0 var(--space-xxs) 0 var(--space-sm); border-radius: var(--ws-radius-card); background: var(--ws-tray); box-shadow: none; }
45
+ .ws-composer--field .ws-composer__words { min-height: 0; padding: var(--space-xs-plus) 0; font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); }
46
+ .ws-composer--field { --ws-composer-line: var(--ws-control-h); }
47
+ .ws-composer--field .ws-composer__trail > .ws-icon-btn { background: none; color: var(--color-text-heading); }
48
+ /* Touch: 40 tall and 16 px words (under 16 iOS zooms the page in when the field takes focus), on the same 20 line. */
49
+ @media (pointer: coarse) { .ws-composer--field { --ws-composer-line: var(--ws-touch); } .ws-composer--field .ws-composer__words { font-size: var(--ws-text-value); } }
50
+ /* The navy ground keeps the field white (--ws-field), so on it the words, the tools, the washes, the edges and the
51
+ focus ring take the field's own navy ink and nothing turns white on white. The pane field sits on the tray, not the
52
+ white, so its words take the ground's heading. */
53
+ [data-theme="dark"][data-ground="navy"] :is(.ws-composer:not(.ws-composer--field), .ws-composer__context) { --color-text-heading: var(--ws-field-ink); --color-text-body: var(--ws-field-ink); --color-text-muted: var(--color-text-placeholder); --ws-on-act: var(--ws-field); --ws-focus-color: var(--ws-field-ink); --ws-hover: color-mix(in srgb, var(--ws-field-ink) 5%, transparent); --ws-hover-strong: color-mix(in srgb, var(--ws-field-ink) 6%, transparent); --ws-edge-card: color-mix(in srgb, var(--ws-field-ink) 18%, transparent); --ws-edge-slot: var(--ws-edge-card); --ws-track: var(--ws-edge-card); --ws-surface-sunk: color-mix(in srgb, var(--ws-field) 92%, var(--ws-field-ink)); --ws-act-hover: color-mix(in srgb, var(--color-text-heading) 92%, var(--ws-on-act)); --ws-edge-hover: var(--color-text-muted); --ws-shadow-hairline-in: inset 0 0 0 var(--ws-hairline) var(--ws-edge-card); }
54
+ [data-theme="dark"][data-ground="navy"] .ws-composer--field { --ws-field-ink: var(--color-text-heading); }
55
+ @media (prefers-color-scheme: dark) {
56
+ [data-theme="system"][data-ground="navy"] :is(.ws-composer:not(.ws-composer--field), .ws-composer__context) { --color-text-heading: var(--ws-field-ink); --color-text-body: var(--ws-field-ink); --color-text-muted: var(--color-text-placeholder); --ws-on-act: var(--ws-field); --ws-focus-color: var(--ws-field-ink); --ws-hover: color-mix(in srgb, var(--ws-field-ink) 5%, transparent); --ws-hover-strong: color-mix(in srgb, var(--ws-field-ink) 6%, transparent); --ws-edge-card: color-mix(in srgb, var(--ws-field-ink) 18%, transparent); --ws-edge-slot: var(--ws-edge-card); --ws-track: var(--ws-edge-card); --ws-surface-sunk: color-mix(in srgb, var(--ws-field) 92%, var(--ws-field-ink)); --ws-act-hover: color-mix(in srgb, var(--color-text-heading) 92%, var(--ws-on-act)); --ws-edge-hover: var(--color-text-muted); --ws-shadow-hairline-in: inset 0 0 0 var(--ws-hairline) var(--ws-edge-card); }
57
+ [data-theme="system"][data-ground="navy"] .ws-composer--field { --ws-field-ink: var(--color-text-heading); }
58
+ }
59
+ /* Focus glow (North's "Focus glow", the glow spring .3 / 0, css:2120): while something in the box has focus, from a
60
+ pointer or a key, a soft drop gathers under it (0 4 16, the shade at 7 %); its edge stays its own and the keyboard
61
+ ring is still the kit's (D8). The pane field, a live call and the chat bar keep their own look. */
62
+ :where(.ws-composer:not(.ws-composer--field, .ws-composer--live)):focus-within { box-shadow: inset 0 0 0 var(--ws-hairline) var(--ws-edge-card), 0 var(--space-xxs) var(--space-md) color-mix(in srgb, var(--ws-shade) 7%, transparent); }
63
+ /* The rolling placeholder (North's "Placeholder roll", the roll spring .45 / .05, js@784180): a few questions in a
64
+ ws-composer__roll laid over the words' first line, the words and the roll sharing one cell (ws-composer__slot). The
65
+ shown one (data-on, moved on every 3.4 s by rollPlaceholder() from the package) rolls up out of 12 px and a 3 px blur;
66
+ the one before it rolls on up 12 px into the blur. The words keep the first question as their real placeholder (what
67
+ a screen reader reads), painted clear; the roll goes once there are words. Without the script, or with reduced motion,
68
+ the first question holds. The main field only: the pane field keeps its plain placeholder. */
69
+ .ws-composer__slot { display: grid; flex: 1; min-width: 0; }
70
+ .ws-composer__slot > * { grid-area: 1 / 1; }
71
+ .ws-composer__slot > .ws-composer__words { width: 100%; }
72
+ .ws-composer__roll { display: grid; align-self: start; min-width: 0; padding: calc((var(--ws-composer-line) - var(--ws-leading-message)) / 2) var(--space-3xs) 0 0; font-size: var(--ws-text-value); line-height: var(--ws-leading-message); color: var(--color-text-muted); pointer-events: none; }
73
+ .ws-composer__roll > * { grid-area: 1 / 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; opacity: 0; visibility: hidden; translate: 0 var(--ws-drop); filter: blur(var(--ws-blur-arrive)); }
74
+ .ws-composer__roll > [data-off] { translate: 0 calc(var(--ws-drop) * -1); }
75
+ .ws-composer__roll > [data-on], .ws-composer__roll:not(:has(> [data-on])) > :first-child { opacity: 1; visibility: visible; translate: none; filter: none; }
76
+ .ws-composer__slot:has(> .ws-composer__roll) > .ws-composer__words::placeholder { color: transparent; }
77
+ .ws-composer__words:not(:placeholder-shown) ~ .ws-composer__roll { display: none; }
78
+ @media (prefers-reduced-motion: no-preference) {
79
+ :where(.ws-composer:not(.ws-composer--field, .ws-composer--live)) { transition: box-shadow var(--ws-spring-glow-duration) var(--ws-spring-glow); }
80
+ .ws-composer__roll > :is([data-on], [data-off]) { transition: opacity var(--ws-spring-roll-duration) var(--ws-spring-roll), translate var(--ws-spring-roll-duration) var(--ws-spring-roll), filter var(--ws-spring-roll-duration) var(--ws-spring-roll), visibility var(--ws-spring-roll-duration) var(--ws-spring-roll); }
81
+ }
@@ -3,87 +3,108 @@ The `Dialog` recipe for the one moment something cannot be undone: name the thin
3
3
  ## Use it when
4
4
 
5
5
  - An action removes something, or removes someone's access to it, and cannot be reversed.
6
- - An action affects another person, not just the one pressing the button (removing a teammate, deleting a shared
7
- draft).
8
- - The cost of getting it wrong is high enough that a plain button press is not enough on its own.
6
+ - An action affects another person, not just the one pressing the button (removing a teammate, deleting a shared draft).
7
+ - Getting it wrong costs enough that a plain button press is not enough on its own.
9
8
 
10
9
  ## Not for
11
10
 
12
- - Anything reversible: use the undo alternative (an `Undo` act in a toast, five seconds) instead of a confirm dialog;
13
- "undo beats confirm."
14
- - A short blocking task that is not destructive (assigning something, naming something): use plain `Dialog`.
15
- - An error: that is a field message or a `Banner`, not a confirmation.
11
+ - Anything reversible: offer Undo in a `Toast` instead; undo beats confirm.
12
+ - A short blocking task that is not destructive (assigning, naming): use plain `Dialog`.
13
+ - An error: that is a field message or a `Banner`.
16
14
 
17
15
  ## Anatomy
18
16
 
19
- Built directly on `Dialog`'s own anatomy: the native `<dialog>` card, `DialogHead` (a 22 px title, one 14 px sentence),
20
- `DialogFoot` (the `ws-band` footer, buttons right-aligned, 36 px large), a 35% navy scrim behind it. The one addition is
21
- a words-only modifier on the destructive button: it keeps the secondary button's cream shell and fine edge, with its
22
- words recoloured to `--ws-word-needs` instead of navy.
17
+ Built on `Dialog`: the pane in its tray rim, 12 px corners, 28 px sides, the compact head and the foot band, over the
18
+ 35% navy scrim. Its `role` is `alertdialog`.
23
19
 
24
- - Title: names the thing and the consequence in one sentence ("Remove Priya Nair from the team?"), stricter than plain
25
- `Dialog`'s own examples, which may be more general ("Assign this call").
26
- - Line: one sentence saying what happens ("Her scores and progress go with her. This cannot be undone.").
27
- - Foot: two secondary, large (36 px) buttons. The first keeps the thing ("Keep her," context-specific rather than a
28
- bare "Cancel"); the second is the destructive act ("Remove"), same cream shell, `--ws-word-needs` words.
20
+ - Title: names the thing and the consequence as a question ("Remove Priya Nair from the team?"), 22 / 28.
21
+ - Line: one sentence saying what happens ("Her scores and progress go with her. This cannot be undone."), 14 / 20,
22
+ 4 under the title, 20 above the foot. Point `aria-describedby` at it.
23
+ - Close: Dialog's 32 px tray square, centred on the title's first line; it stays top right at any width.
24
+ - Foot: two secondary, large acts in `ws-dialog__acts`, 8 apart, on the right. The first keeps the thing ("Keep her");
25
+ the second is the destructive act ("Remove"), the same cream shell with its words in `--ws-word-needs`
26
+ (`ws-confirm-dialog__destructive`). On a phone they fill the width in equal halves, stacked full width
27
+ (keep on top) where a half would be under 160 or a label would break.
29
28
 
30
29
  ## Variants and sizes
31
30
 
32
31
  | Variant | Look |
33
32
  | --- | --- |
34
- | Confirm (centre only) | the one form this takes; there is no drawer version, since a confirm is always a short, centred question |
33
+ | Confirm (centre only) | The one form. There is no drawer version: a confirm is always a short question in the centre |
35
34
 
36
35
  ## States
37
36
 
38
- - **Open:** over its scrim, title, line and both foot buttons visible.
39
- - **Focus:** trapped inside the dialog; Tab cycles the two buttons.
40
- - **Closing:** as `Dialog`'s own closing state, frozen for `--ws-duration-instant` while it leaves.
41
- - **Pending:** the destructive button may show a working dot while the removal runs, refusing a second press, exactly
42
- as `Button`'s own pending state.
37
+ - **Open**: over its scrim; title, line and both acts visible.
38
+ - **Focus**: trapped inside; Tab moves between the close and the two acts. Focus starts on the act that keeps the thing.
39
+ - **Hover**: the destructive act keeps its needs-you words; only its ground tints.
40
+ - **Pending**: the destructive act shows the working dot and its present-tense verb ("Deleting"), with `aria-busy` and
41
+ `aria-disabled`. It stops answering the pointer (no hover tint, no second press); it stays focusable, so the app
42
+ ignores Enter on it until the work is done.
43
+ - **Closing**: as `Dialog`, it fades and drops 8 px over `--ws-duration-exit`.
43
44
 
44
45
  ## Behaviour
45
46
 
46
- - Keyboard: Escape closes it and returns focus to what opened it, exactly as `Dialog`.
47
- - Pointer: a click on the scrim closes it, exactly as `Dialog`.
48
- - Motion: rises 6 px and grows from 98% on `--ws-duration-settle` on `--ws-ease-soft`, exactly as `Dialog`; leaves faster
49
- on `--ws-duration-instant`.
50
- - Reduced motion: opens and closes with a cross-fade instead of rising and scaling up.
47
+ - Keyboard: Escape closes it and returns focus to what opened it, as `Dialog`. Escape and the close both mean "keep".
48
+ - Pointer: a click on the scrim closes it and keeps the thing (`closedby="any"`), as `Dialog`.
49
+ - Motion: as `Dialog` (it is one): it grows 14 px up out of .98 on the settle spring (`--ws-spring-settle`) as the
50
+ scrim fades in, its head and foot settling in after it; it leaves faster, over `--ws-duration-exit`.
51
+ - Reduced motion: it appears and goes at once.
52
+ - The preview's last stack is live: press Remove Priya Nair.
51
53
 
52
54
  ## Content
53
55
 
54
- - The title always names the specific thing and its consequence, never a generic "Are you sure?"
55
- - The cancel button names what staying means in this case ("Keep her"), not a bare "Cancel," though "Cancel" or "Not
56
- now" remain fine when nothing warmer fits.
57
- - The destructive act is a short, plain verb ("Remove," "Delete").
58
- - No em dashes, sentence case.
56
+ - The title names the specific thing and its consequence, never "Are you sure?".
57
+ - The keep act says what staying means here ("Keep her", "Keep the draft"); "Cancel" is fine when nothing warmer fits.
58
+ - The destructive act is a short, plain verb ("Remove", "Delete"); pending, its present tense ("Deleting").
59
59
 
60
60
  ## Props
61
61
 
62
62
  | Name | Type | Meaning |
63
63
  | --- | --- | --- |
64
- | `open` | boolean | drives whether it is open |
65
- | `onClose` | `() => void` | fires on Escape, the scrim, or choosing "keep" |
66
- | `title` | string | names the thing and the consequence |
67
- | `line` | string | says what happens |
68
- | `keepLabel` | string | the cancel button's words, context-specific |
69
- | `removeLabel` | string | the destructive button's words |
70
- | `onConfirm` | `() => void` | fires when the destructive act is pressed |
71
- | `pending` | boolean | shows the working dot on the destructive act |
64
+ | `open` | boolean | Drives whether it is open. |
65
+ | `onClose` | `() => void` | Fires on Escape, the scrim, the close or the keep act. |
66
+ | `title` | string | Names the thing and the consequence. |
67
+ | `line` | string | Says what happens. |
68
+ | `keepLabel` | string | The keep act's words, specific to the case. |
69
+ | `removeLabel` | string | The destructive act's words. |
70
+ | `onConfirm` | `() => void` | Fires when the destructive act is pressed. |
71
+ | `pending` | boolean | Shows the working dot on the destructive act and refuses a second press. |
72
72
 
73
73
  ## Rules
74
74
 
75
- - 10-patterns.md's "Confirmation and undo" section: "Confirm only what cannot be undone or affects other people; then
76
- name the thing and the consequence in the dialog's title and line, and make the destructive act secondary with
77
- needs-you words." Every part of this component follows that line directly.
78
- - Plain `Dialog`'s own rule is "one navy primary button per dialog... every other act is secondary or a text action."
79
- `ConfirmDialog` has no primary button at all: both acts are secondary, and the one that destroys something is marked
80
- only by its word colour, never by a navy fill, since a destructive act must never read as the screen's one recommended
81
- action.
82
- - Never a red fill: the destructive act's shell stays the same cream secondary button as "keep," only its words change
83
- colour.
75
+ - Confirm only what cannot be undone or affects other people (10-patterns.md, "Confirmation and undo").
76
+ - No navy primary act here: both acts are secondary, and the one that destroys is marked only by its word colour, so a
77
+ destructive act never reads as the screen's one recommended act.
78
+ - Never a red fill.
84
79
 
85
80
  ## Source
86
81
 
87
- **Derived from**: `Dialog`'s own anatomy (title, line, footer band) applied directly to the "Confirmation and undo"
88
- pattern, with the destructive act marked only by its word colour, never a fill; the undo alternative shown alongside
89
- it is the kit's own `Toast`, not a generic lifted cream card. **Precedent**: the first product built on the system.
82
+ **Derived from**: `Dialog` applied to the "Confirmation and undo" pattern; the undo alternative beside it is the kit's
83
+ own `Toast`. **Precedent**: the first product built on the system.
84
+
85
+ ## Markup
86
+
87
+ ```html
88
+ <dialog class="ws-dialog" role="alertdialog" aria-labelledby="remove-title" aria-describedby="remove-line" closedby="any">
89
+ <header class="ws-head">
90
+ <div>
91
+ <h2 id="remove-title" class="ws-title">Remove Priya Nair from the team?</h2>
92
+ <p id="remove-line" class="ws-body">Her scores and progress go with her. This cannot be undone.</p>
93
+ </div>
94
+ <button type="button" class="ws-icon-btn ws-dialog__close" aria-label="Close">
95
+ <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>
96
+ </button>
97
+ </header>
98
+ <footer class="ws-band">
99
+ <div class="ws-dialog__acts">
100
+ <button type="button" class="ws-btn ws-btn--secondary ws-btn--lg" autofocus>Keep her</button>
101
+ <button type="button" class="ws-btn ws-btn--secondary ws-btn--lg ws-confirm-dialog__destructive">Remove</button>
102
+ </div>
103
+ </footer>
104
+ </dialog>
105
+ ```
106
+
107
+ ## Styles
108
+
109
+ `ConfirmDialog/style.css` holds one rule, the destructive act's words; the rest is `Dialog/style.css`. Both are in
110
+ `bundle.css` and `fello.css`. Tokens only, so it turns dark with the page.
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Overlays" height=352 -->
1
+ <!-- @dsCard group="Overlays" height=450 -->
2
2
  <!doctype html>
3
3
  <html>
4
4
  <head>
@@ -9,42 +9,86 @@
9
9
  </head>
10
10
  <body>
11
11
  <div class="ws-stage ws-stage--grey">
12
- <div class="ws-cluster ws-cluster--start" style="gap: var(--space-xl);">
13
12
 
14
- <div class="ws-stack">
15
- <span class="ws-muted">Confirm: cannot be undone, no navy primary, the destructive act in needs-you words</span>
16
- <div style="display: grid; place-items: center; width: 360px; height: 280px; overflow: hidden; border-radius: var(--ws-radius-panel); background: linear-gradient(var(--ws-scrim), var(--ws-scrim)), var(--ws-page);">
17
- <div style="display: grid; width: 352px; max-width: 100%; justify-items: center;"><div class="ws-dialog" role="dialog" aria-modal="true" aria-labelledby="cd-title">
18
- <header class="ws-head">
19
- <div>
20
- <h2 id="cd-title" class="ws-title">Remove Priya Nair from the team?</h2>
21
- <p class="ws-body" style="margin-top: var(--space-xxs);">Her scores and progress go with her. This cannot be undone.</p>
22
- </div>
23
- <button type="button" class="ws-icon-btn" aria-label="Close">
24
- <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>
25
- </button>
26
- </header>
27
- <footer class="ws-band">
13
+ <div class="ws-stack" style="width: 440px;">
14
+ <span class="ws-muted">Confirm: names the thing and what happens; no navy act, the destructive one in needs-you words</span>
15
+ <div style="display: grid; place-items: center; padding: var(--space-xl) 0; border-radius: var(--ws-radius-panel); background: linear-gradient(var(--ws-scrim), var(--ws-scrim)), var(--ws-page);">
16
+ <div class="ws-dialog" role="alertdialog" aria-modal="true" aria-labelledby="cd-title" aria-describedby="cd-line" style="max-width: 384px;">
17
+ <header class="ws-head">
18
+ <div>
19
+ <h2 id="cd-title" class="ws-title">Remove Priya Nair from the team?</h2>
20
+ <p id="cd-line" class="ws-body">Her scores and progress go with her. This cannot be undone.</p>
21
+ </div>
22
+ <button type="button" class="ws-icon-btn ws-dialog__close" aria-label="Close">
23
+ <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>
24
+ </button>
25
+ </header>
26
+ <footer class="ws-band">
27
+ <div class="ws-dialog__acts">
28
28
  <button type="button" class="ws-btn ws-btn--secondary ws-btn--lg">Keep her</button>
29
29
  <button type="button" class="ws-btn ws-btn--secondary ws-btn--lg ws-confirm-dialog__destructive">Remove</button>
30
- </footer>
31
- </div></div>
30
+ </div>
31
+ </footer>
32
32
  </div>
33
33
  </div>
34
+ </div>
34
35
 
35
- <div class="ws-stack">
36
- <span class="ws-muted">Undo beats confirm: the reversible alternative as a toast, Toast's own real look</span>
37
- <div style="width: 300px; max-width: 100%;">
38
- <div class="ws-toast" role="status">
39
- <div class="ws-toast__body">
40
- <p class="ws-toast__title">Removed Priya Nair from the team</p>
36
+ <div class="ws-stack" style="width: 440px;">
37
+ <span class="ws-muted">Pending: the destructive act shows the working dot and takes no second press</span>
38
+ <div style="display: grid; place-items: center; padding: var(--space-xl) 0; border-radius: var(--ws-radius-panel); background: linear-gradient(var(--ws-scrim), var(--ws-scrim)), var(--ws-page);">
39
+ <div class="ws-dialog" role="alertdialog" aria-modal="true" aria-labelledby="cd-title-2" aria-describedby="cd-line-2" style="max-width: 384px;">
40
+ <header class="ws-head">
41
+ <div>
42
+ <h2 id="cd-title-2" class="ws-title">Delete the draft to the Whitfield family?</h2>
43
+ <p id="cd-line-2" class="ws-body">Dana wrote it with you yesterday. Nobody can get it back.</p>
41
44
  </div>
42
- <button type="button" class="ws-toast__action">Undo</button>
43
- </div>
45
+ <button type="button" class="ws-icon-btn ws-dialog__close" aria-label="Close">
46
+ <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>
47
+ </button>
48
+ </header>
49
+ <footer class="ws-band">
50
+ <div class="ws-dialog__acts">
51
+ <button type="button" class="ws-btn ws-btn--secondary ws-btn--lg">Keep the draft</button>
52
+ <button type="button" class="ws-btn ws-btn--secondary ws-btn--lg ws-confirm-dialog__destructive" aria-busy="true" aria-disabled="true"><span class="ws-dot ws-working" aria-hidden="true"></span>Deleting</button>
53
+ </div>
54
+ </footer>
44
55
  </div>
45
56
  </div>
57
+ </div>
46
58
 
59
+ <div class="ws-stack" style="width: 320px;">
60
+ <span class="ws-muted">Undo beats confirm: the reversible case is a toast with Undo</span>
61
+ <div class="ws-toast" role="status">
62
+ <svg class="ws-toast__icon" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
63
+ <div class="ws-toast__body">
64
+ <p class="ws-toast__title">Removed Priya Nair from the team</p>
65
+ </div>
66
+ <button type="button" class="ws-toast__action">Undo</button>
67
+ </div>
68
+ </div>
69
+
70
+ <div class="ws-stack" style="width: 320px;" data-live>
71
+ <span class="ws-muted">Live: press Remove. It moves as every Dialog does: up out of .98 on the settle spring, its parts settling in after it; Escape or either act sends it off faster</span>
72
+ <button type="button" class="ws-btn ws-btn--secondary ws-confirm-dialog__destructive" style="align-self: flex-start;" onclick="document.getElementById('cd-live').showModal()">Remove Priya Nair</button>
73
+ <dialog id="cd-live" class="ws-dialog" role="alertdialog" aria-labelledby="cd-live-title" aria-describedby="cd-live-line" closedby="any" style="max-width: 384px;">
74
+ <header class="ws-head">
75
+ <div>
76
+ <h2 id="cd-live-title" class="ws-title">Remove Priya Nair from the team?</h2>
77
+ <p id="cd-live-line" class="ws-body">Her scores and progress go with her. This cannot be undone.</p>
78
+ </div>
79
+ <button type="button" class="ws-icon-btn ws-dialog__close" aria-label="Close" onclick="this.closest('dialog').close()">
80
+ <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>
81
+ </button>
82
+ </header>
83
+ <footer class="ws-band">
84
+ <div class="ws-dialog__acts">
85
+ <button type="button" class="ws-btn ws-btn--secondary ws-btn--lg" onclick="this.closest('dialog').close()">Keep her</button>
86
+ <button type="button" class="ws-btn ws-btn--secondary ws-btn--lg ws-confirm-dialog__destructive" onclick="this.closest('dialog').close()">Remove</button>
87
+ </div>
88
+ </footer>
89
+ </dialog>
47
90
  </div>
91
+
48
92
  </div>
49
93
  </body>
50
94
  </html>
@@ -0,0 +1,5 @@
1
+ /* ---- ConfirmDialog: a Dialog that asks before something that cannot be undone; the act in needs-you words ---- */
2
+ /* The words keep their colour on hover and while pending, whatever the secondary button's own hover does. */
3
+ .ws-confirm-dialog__destructive, .ws-confirm-dialog__destructive:hover { color: var(--ws-word-needs); }
4
+ /* Pending (aria-disabled): no hover tint and no second press from a pointer; the app ignores Enter while it is busy. */
5
+ .ws-confirm-dialog__destructive[aria-disabled="true"] { pointer-events: none; }
@@ -11,11 +11,11 @@
11
11
  <div class="ws-cover">
12
12
  <!--
13
13
  blocks: brand-navy 360 x 112 (space-9xl + space-8xl), brand-salmon 240 x 112 (space-9xl + space-2xl), ws-chart-past-half 200 x 112 (space-9xl), ws-chart-finished 160 x 112 (space-8xl); a strip of unequal bands across the top, flush, square (the goal strip's order: navy, then salmon to purple to teal).
14
- arrangement: the top-band skeleton (the name is wider than 440 px at 64 px), the band 112 px tall, the name a step (space-lg) under it.
14
+ arrangement: the top-band skeleton (the name is wider than 440 px at 64 px), the band 112 px tall at 960 and scaled with the width below it, the name a step (space-xl) under it and flowing, so a phone keeps every tone and reads every word.
15
15
  pattern: the goal strip's ticks: "counts out of a whole are tick rows" and "0.5 px edges, 2 px chips" say precise and modular; forty ticks space-xs wide and space-2xl tall at a space-lg pitch, radius-xs corners, in the ground colour cut out of the blocks, rising from the band's foot.
16
16
  scales: widths from space-9xl, space-8xl, space-2xl; tick width space-xs, height space-2xl, pitch space-lg, corners radius-xs; the gap under the band space-lg; the text inset space-2xl.
17
17
  -->
18
- <svg class="ws-cover__art" viewBox="0 0 960 288" aria-hidden="true">
18
+ <svg class="ws-cover__art" viewBox="0 0 960 120" aria-hidden="true">
19
19
  <rect class="ws-cover__navy" x="0" y="0" width="360" height="112"/>
20
20
  <rect class="ws-cover__salmon" x="360" y="0" width="240" height="112"/>
21
21
  <rect class="ws-cover__purple" x="600" y="0" width="200" height="112"/>
@@ -24,7 +24,7 @@
24
24
  <rect class="ws-cover__tick" x="8" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="32" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="56" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="80" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="104" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="128" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="152" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="176" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="200" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="224" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="248" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="272" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="296" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="320" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="344" y="64" width="8" height="40"/>
25
25
  <rect class="ws-cover__tick" x="368" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="392" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="416" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="440" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="464" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="488" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="512" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="536" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="560" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="584" y="64" width="8" height="40"/>
26
26
  <rect class="ws-cover__tick" x="608" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="632" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="656" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="680" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="704" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="728" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="752" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="776" y="64" width="8" height="40"/>
27
- <rect class="ws-cover__tick" x="808" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="832" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="856" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="880" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="904" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="928" y="64" width="8" height="40"/>
27
+ <rect class="ws-cover__tick" x="800" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="824" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="848" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="872" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="896" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="920" y="64" width="8" height="40"/><rect class="ws-cover__tick" x="944" y="64" width="8" height="40"/>
28
28
  </g>
29
29
  <rect class="ws-cover__tint" x="0" y="112" width="960" height="8"/>
30
30
  </svg>
@@ -0,0 +1,19 @@
1
+ /* ---- Cover: the system's own cover, 960 by 288: the goal strip's four tones cut by ticks, the name a step under it ---- */
2
+ /* The art is a picture: it scales with the cover's width (the band is the SVG's whole viewBox), so a phone sees all four
3
+ tones. The words flow under it at their own sizes instead of being pinned to 960 px coordinates. */
4
+ .ws-cover { max-width: calc(var(--space-9xl) * 4 + var(--space-8xl)); padding-bottom: var(--space-sm); background: var(--color-bg-page); }
5
+ .ws-cover__art { display: block; width: 100%; height: auto; }
6
+ .ws-cover__navy { fill: var(--color-brand-navy); }
7
+ .ws-cover__salmon { fill: var(--color-brand-salmon); }
8
+ .ws-cover__purple { fill: var(--ws-chart-past-half); }
9
+ .ws-cover__teal { fill: var(--ws-chart-finished); }
10
+ .ws-cover__tint { fill: var(--ws-surface-sunk); }
11
+ .ws-cover__ground { fill: var(--color-bg-page); }
12
+ .ws-cover__tick { rx: var(--ws-radius-chip); }
13
+ .ws-cover__name { margin: var(--space-xl) var(--space-2xl) 0; font-size: var(--font-size-6xl); line-height: 0.95; font-weight: 600; letter-spacing: var(--ws-tracking-title); color: var(--color-text-heading); text-wrap: balance; }
14
+ .ws-cover__line { margin: var(--space-lg) var(--space-2xl) 0; max-width: var(--ws-thing-width); font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); color: var(--color-text-muted); }
15
+ /* A phone: the 16 px margin and the name a step down (64 to 40), as Hero does. */
16
+ @media (max-width: 40rem) {
17
+ .ws-cover__name { margin: var(--space-lg) var(--space-md) 0; font-size: var(--font-size-3xl); line-height: var(--space-3xl); }
18
+ .ws-cover__line { margin: var(--space-xs) var(--space-md) 0; }
19
+ }
@@ -14,8 +14,8 @@ A date field that works on its own, with a popover month grid for picking a day
14
14
 
15
15
  ## Anatomy
16
16
 
17
- - Field: `Input`'s exact shell (32 px, `--ws-radius-control`, white `--ws-field`, `--ws-shadow-hairline`, mid-blue focus
18
- edge), a native `<input type="date">`, with a 16 px calendar line icon at the right, `--color-text-muted`, decorative,
17
+ - Field: `Input`'s exact shell (32 px, `--ws-radius-control`, white `--ws-field`, the inside edge, the kit's focus
18
+ ring), a native `<input type="date">`, with a 16 px navy calendar line icon at the right, decorative,
19
19
  positioned the way `Select`'s own chevron sits.
20
20
  - Picker: a `ws-menu` card (cream, `--ws-radius-card`, `--ws-shadow-lift`) holding a month grid.
21
21
  - Header: 32 px row (`--ws-control-h`), the month name 14 px medium navy, two `xs` ghost `IconButton`s (24 px) at the
@@ -24,12 +24,19 @@ A date field that works on its own, with a popover month grid for picking a day
24
24
  - Day cells: 32 px (`--ws-control-h`), `--ws-radius-control` (4 px) corners. This is a squarer cell than
25
25
  `StreakCalendar`'s pill-shaped day cells, because a picker is a month grid for choosing one day, not a strip
26
26
  showing a history of days; the two share colour and letter conventions, not cell shape.
27
- - Today: a single `--ws-hairline` ring in `--color-brand-salmon`, cream fill, navy numeral, a thinner mark than
28
- `StreakCalendar`'s own 3x-hairline today ring, since this spec asks for "a hairline," literally.
29
- - Chosen day: solid `--color-text-heading` fill, white numeral, the same `--ws-radius-control` corners.
30
- - Range: `--ws-surface-sunk` fill across the cells between two navy, chosen end days.
27
+ - Today: a 1 px ring in the salmon's AA step (`--ws-word-needs`; the salmon at 0.5 px was 2.6:1, under the 3:1 a
28
+ mark asks), navy numeral.
29
+ - Chosen day: solid `--color-text-heading` fill, `--ws-on-act` numeral, the same `--ws-radius-control` corners;
30
+ `aria-pressed="true"` (today carries `aria-current="date"`).
31
+ - Range: `--ws-surface-sunk` fill across the cells between two navy, chosen end days; days abut across a row (2 px
32
+ between weeks), so a range reads as one band.
33
+ - Numerals: 13 / 18, even.
34
+ - On touch the grid fills its column (up to 320) and loses its insets, so a day is 40 tall and, from a 280 px column,
35
+ 40 wide; the header is 40 tall and its month buttons are 40 px boxes on the outer days' edges, so their target
36
+ never spills out of the picker (it never drags sideways).
31
37
  - Outside the month: muted numerals, no fill.
32
- - Past-disabled: 40% opacity, matching `Button`'s and `IconButton`'s own disabled value.
38
+ - Past-disabled: 40% opacity, matching `Button`'s and `IconButton`'s own disabled value, and `aria-disabled="true"`
39
+ so a screen reader says it cannot be chosen.
33
40
 
34
41
  ## Variants and sizes
35
42
 
@@ -45,8 +52,12 @@ There is one size; the field expands to 40 px on a touch screen, where the platf
45
52
  - **Field alone:** the native input and its calendar icon, no picker open.
46
53
  - **Open picker:** the month grid, including today's ring, a muted out-of-month day and a past-disabled day.
47
54
  - **A range:** two navy ends with the sunk fill between them.
48
- - **Focus:** the field's edge turns mid blue with the focus halo, exactly as `Input`.
49
- - **Error:** the edge turns salmon with a message below, exactly as `Input`'s error state.
55
+ - **Focus:** the kit's focus ring, 2 px navy, 2 px out, as `Input`'s (a field's edge darkens under the pointer).
56
+ - **Error:** the salmon's AA step as a 1 px edge with a message below, exactly as `Input`'s error state.
57
+ - **Hover (a mouse only):** a day takes the navy wash.
58
+ - **Day focus:** the kit's ring drawn inside the day (the grid is dense); on a navy day the ring is the numeral's colour,
59
+ 2 px further in, so it never vanishes into the fill.
60
+ - **Dark:** the menu, the days and the act take their dark values.
50
61
  - **Disabled:** the field is not editable, the icon and picker are inert.
51
62
 
52
63
  ## Behaviour
@@ -56,7 +67,7 @@ There is one size; the field expands to 40 px on a touch screen, where the platf
56
67
  the active cell, Escape closes the picker and returns focus to the field, and the header's buttons (or Page Up/Down)
57
68
  move months.
58
69
  - Pointer / touch: clicking a day cell chooses it; the field's own calendar icon opens the picker.
59
- - Motion: the picker opens on `--ws-duration-gentle` on `--ws-ease-soft`, as `Menu`.
70
+ - Motion: the picker opens as `Menu` does, growing from its top left corner, under the field's left edge (D7).
60
71
  - Reduced motion: the picker appears without its rise.
61
72
 
62
73
  ## Content
@@ -81,8 +92,8 @@ There is one size; the field expands to 40 px on a touch screen, where the platf
81
92
  - 08-choosing-components.md previously read: "Pick a date or a time | a native input until a picker is built | listed
82
93
  as later." This is that picker arriving (26 Oct 2026): the native field stays the whole story on its own, and the
83
94
  picker is an enhancement, never a replacement.
84
- - Today's colour logic (a salmon outline, nothing else about the cell changes) and the muted day-letter row both come
85
- from `StreakCalendar`; the cell shape does not, since the two components solve different problems.
95
+ - Today is an outline in the salmon's AA step, nothing else about the cell changes; the muted day-letter row comes from
96
+ `StreakCalendar`; the cell shape does not, since the two components solve different problems.
86
97
  - 40% opacity for a past-disabled day matches `Button`'s and `IconButton`'s own disabled value, not `Checkbox`'s 50%.
87
98
 
88
99
  ## Source
@@ -90,3 +101,57 @@ There is one size; the field expands to 40 px on a touch screen, where the platf
90
101
  **Derived from**: `Input`'s field chrome, `Select`'s chevron-positioning pattern, `StreakCalendar`'s today-marking
91
102
  colour and day-letter conventions, and `Menu`'s `ws-menu` panel shell and motion. **Precedent**: an intentional
92
103
  addition decided from the system, 26 Oct 2026 (filling the "listed as later" line in 08-choosing-components.md).
104
+
105
+ ## Markup
106
+
107
+ ```html
108
+ <label class="ws-field">
109
+ <span class="ws-label">Call date</span>
110
+ <span class="ws-date-input">
111
+ <input class="ws-input" type="date" value="2026-10-22">
112
+ <svg class="ws-date-input__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2.5" y="3.5" width="11" height="10" rx="1.5"/><path d="M2.5 6.5h11M5 2v3M11 2v3"/></svg>
113
+ </span>
114
+ </label>
115
+ <div class="ws-menu ws-date-input__picker" role="dialog" aria-label="Choose a date">
116
+ <div class="ws-date-input__head">
117
+ <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Previous month">...</button>
118
+ <span class="ws-date-input__month">October 2026</span>
119
+ <button type="button" class="ws-icon-btn ws-icon-btn--xs" aria-label="Next month">...</button>
120
+ </div>
121
+ <div class="ws-date-input__grid">
122
+ <span class="ws-date-input__letter">M</span> ...
123
+ <!-- outside the month, and a day that cannot be chosen (past or out of range) -->
124
+ <button type="button" class="ws-date-input__cell ws-date-input__cell--muted ws-date-input__cell--disabled" aria-disabled="true">30</button>
125
+ <button type="button" class="ws-date-input__cell ws-date-input__cell--disabled" aria-disabled="true">1</button>
126
+ ...
127
+ <button type="button" class="ws-date-input__cell ws-date-input__cell--chosen" aria-pressed="true">22</button>
128
+ <button type="button" class="ws-date-input__cell ws-date-input__cell--today" aria-current="date">26</button>
129
+ <button type="button" class="ws-date-input__cell ws-date-input__cell--muted">1</button>
130
+ </div>
131
+ </div>
132
+
133
+ <!-- a range: two navy ends, the sunk band between them -->
134
+ <div class="ws-date-input__grid">
135
+ ...
136
+ <button type="button" class="ws-date-input__cell ws-date-input__cell--range-start" aria-pressed="true">12</button>
137
+ <button type="button" class="ws-date-input__cell ws-date-input__cell--range">13</button>
138
+ <button type="button" class="ws-date-input__cell ws-date-input__cell--range">14</button>
139
+ <button type="button" class="ws-date-input__cell ws-date-input__cell--range-end" aria-pressed="true">15</button>
140
+ ...
141
+ </div>
142
+
143
+ <!-- the field in error -->
144
+ <div class="ws-field">
145
+ <label class="ws-label" for="close">Close date</label>
146
+ <span class="ws-date-input">
147
+ <input class="ws-input" id="close" type="date" aria-invalid="true" aria-describedby="close-msg">
148
+ <svg class="ws-date-input__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2.5" y="3.5" width="11" height="10" rx="1.5"/><path d="M2.5 6.5h11M5 2v3M11 2v3"/></svg>
149
+ </span>
150
+ <p class="ws-field-msg ws-field-msg--error" id="close-msg">Pick a day after the offer was sent</p>
151
+ </div>
152
+ ```
153
+
154
+ ## Styles
155
+
156
+ `design-system/components/DateInput/style.css`: `ws-date-input`, `__icon`, `__picker`, `__head`, `__month`, `__grid`,
157
+ `__letter`, `__cell` and its `--muted`, `--today`, `--chosen`, `--disabled`, `--range`, `--range-start`, `--range-end`.