@crisp-ui-kit/crisp 0.57.0 → 0.57.2

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 (293) hide show
  1. package/dist/accentpicker.css +5 -0
  2. package/dist/accentpicker.d.ts +7 -0
  3. package/dist/accentpicker.layered.css +7 -0
  4. package/dist/authshell.css +9 -4
  5. package/dist/authshell.layered.css +9 -4
  6. package/dist/avatar.css +1 -1
  7. package/dist/avatar.layered.css +1 -1
  8. package/dist/badge.css +5 -5
  9. package/dist/badge.layered.css +5 -5
  10. package/dist/board.css +28 -8
  11. package/dist/board.layered.css +28 -8
  12. package/dist/bottomsheet.css +26 -0
  13. package/dist/bottomsheet.d.ts +7 -0
  14. package/dist/bottomsheet.layered.css +28 -0
  15. package/dist/button.css +9 -8
  16. package/dist/button.layered.css +9 -8
  17. package/dist/checkbox.css +7 -3
  18. package/dist/checkbox.layered.css +7 -3
  19. package/dist/chip.css +15 -0
  20. package/dist/chip.d.ts +3 -1
  21. package/dist/chip.layered.css +15 -0
  22. package/dist/chipgroup.css +5 -0
  23. package/dist/chipgroup.d.ts +7 -0
  24. package/dist/chipgroup.layered.css +7 -0
  25. package/dist/cjs/components/accentpicker/accentpicker.js +66 -0
  26. package/dist/cjs/components/accentpicker/accentpicker.recipe.js +25 -0
  27. package/dist/cjs/components/accentpicker/index.js +7 -0
  28. package/dist/cjs/components/avatar/avatar.recipe.js +4 -1
  29. package/dist/cjs/components/badge/badge.recipe.js +38 -10
  30. package/dist/cjs/components/bottomsheet/bottomsheet.js +90 -0
  31. package/dist/cjs/components/bottomsheet/bottomsheet.recipe.js +77 -0
  32. package/dist/cjs/components/bottomsheet/index.js +9 -0
  33. package/dist/cjs/components/button/button.recipe.js +55 -21
  34. package/dist/cjs/components/checkbox/checkbox.recipe.js +61 -9
  35. package/dist/cjs/components/chip/chip.js +14 -2
  36. package/dist/cjs/components/chip/chip.recipe.js +69 -1
  37. package/dist/cjs/components/chipgroup/chipgroup.js +51 -0
  38. package/dist/cjs/components/chipgroup/chipgroup.recipe.js +36 -0
  39. package/dist/cjs/components/chipgroup/index.js +7 -0
  40. package/dist/cjs/components/datatable/datatable.js +5 -1
  41. package/dist/cjs/components/datatable/datatable.recipe.js +11 -2
  42. package/dist/cjs/components/dialog/dialog.recipe.js +21 -10
  43. package/dist/cjs/components/emptystate/emptystate.recipe.js +7 -2
  44. package/dist/cjs/components/fileupload/fileupload.js +21 -4
  45. package/dist/cjs/components/input/index.js +2 -1
  46. package/dist/cjs/components/input/input.js +33 -3
  47. package/dist/cjs/components/input/input.recipe.js +22 -7
  48. package/dist/cjs/components/menu/menu.recipe.js +21 -7
  49. package/dist/cjs/components/menusheet/index.js +9 -0
  50. package/dist/cjs/components/menusheet/menusheet.js +133 -0
  51. package/dist/cjs/components/menusheet/menusheet.recipe.js +103 -0
  52. package/dist/cjs/components/multiselect/multiselect.js +2 -2
  53. package/dist/cjs/components/multiselect/multiselect.recipe.js +45 -12
  54. package/dist/cjs/components/progress/progress.js +21 -4
  55. package/dist/cjs/components/progress/progress.recipe.js +30 -0
  56. package/dist/cjs/components/select/select.js +3 -3
  57. package/dist/cjs/components/select/select.recipe.js +63 -10
  58. package/dist/cjs/components/snackbar/index.js +8 -0
  59. package/dist/cjs/components/snackbar/snackbar.js +121 -0
  60. package/dist/cjs/components/snackbar/snackbar.recipe.js +71 -0
  61. package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +7 -2
  62. package/dist/cjs/components/tabletoolbar/tabletoolbar.js +37 -12
  63. package/dist/cjs/components/tabs/tabs.js +10 -4
  64. package/dist/cjs/components/tabs/tabs.recipe.js +23 -6
  65. package/dist/cjs/components/text/text.recipe.js +8 -7
  66. package/dist/cjs/components/textarea/textarea.js +3 -2
  67. package/dist/cjs/components/textarea/textarea.recipe.js +13 -9
  68. package/dist/cjs/components/textlink/textlink.recipe.js +6 -3
  69. package/dist/cjs/index.js +8 -0
  70. package/dist/cjs/product/authshell/authshell.recipe.js +5 -1
  71. package/dist/cjs/product/command/command.recipe.js +4 -1
  72. package/dist/cjs/product/comments/comments.js +7 -2
  73. package/dist/cjs/product/comments/comments.recipe.js +25 -7
  74. package/dist/cjs/product/memberssettings/index.js +6 -0
  75. package/dist/cjs/product/memberssettings/memberssettings.js +99 -0
  76. package/dist/cjs/product/memberssettings/memberssettings.recipe.js +83 -0
  77. package/dist/cjs/product/notificationssettings/index.js +5 -0
  78. package/dist/cjs/product/notificationssettings/notificationssettings.js +19 -0
  79. package/dist/cjs/product/notificationssettings/notificationssettings.recipe.js +44 -0
  80. package/dist/cjs/product/recordpage/recordpage.js +101 -9
  81. package/dist/cjs/product/recordpage/recordpage.recipe.js +43 -6
  82. package/dist/cjs/product/workspacegeneralsettings/index.js +5 -0
  83. package/dist/cjs/product/workspacegeneralsettings/workspacegeneralsettings.js +21 -0
  84. package/dist/cjs/product/workspacegeneralsettings/workspacegeneralsettings.recipe.js +51 -0
  85. package/dist/cjs/tokens/contract.js +1 -0
  86. package/dist/cjs/tokens/elevation.js +8 -5
  87. package/dist/cjs/tokens/palette.js +107 -33
  88. package/dist/cjs/tokens/scale.js +45 -2
  89. package/dist/cjs/tokens/semantic.js +26 -0
  90. package/dist/columncalc.css +15 -7
  91. package/dist/columncalc.layered.css +15 -7
  92. package/dist/command.css +23 -19
  93. package/dist/command.layered.css +23 -19
  94. package/dist/comments.css +28 -19
  95. package/dist/comments.d.ts +2 -2
  96. package/dist/comments.layered.css +28 -19
  97. package/dist/datatable.css +161 -67
  98. package/dist/datatable.layered.css +161 -67
  99. package/dist/datepicker.css +13 -41
  100. package/dist/datepicker.layered.css +13 -41
  101. package/dist/datepickerfield.css +4 -1
  102. package/dist/datepickerfield.layered.css +4 -1
  103. package/dist/dialog.css +12 -7
  104. package/dist/dialog.layered.css +12 -7
  105. package/dist/emptystate.css +5 -3
  106. package/dist/emptystate.layered.css +5 -3
  107. package/dist/esm/components/accentpicker/accentpicker.js +30 -0
  108. package/dist/esm/components/accentpicker/accentpicker.recipe.js +22 -0
  109. package/dist/esm/components/accentpicker/index.js +2 -0
  110. package/dist/esm/components/avatar/avatar.recipe.js +4 -1
  111. package/dist/esm/components/badge/badge.recipe.js +38 -10
  112. package/dist/esm/components/bottomsheet/bottomsheet.js +52 -0
  113. package/dist/esm/components/bottomsheet/bottomsheet.recipe.js +74 -0
  114. package/dist/esm/components/bottomsheet/index.js +2 -0
  115. package/dist/esm/components/button/button.recipe.js +56 -22
  116. package/dist/esm/components/checkbox/checkbox.recipe.js +61 -9
  117. package/dist/esm/components/chip/chip.js +14 -2
  118. package/dist/esm/components/chip/chip.recipe.js +69 -1
  119. package/dist/esm/components/chipgroup/chipgroup.js +15 -0
  120. package/dist/esm/components/chipgroup/chipgroup.recipe.js +33 -0
  121. package/dist/esm/components/chipgroup/index.js +2 -0
  122. package/dist/esm/components/datatable/datatable.js +5 -1
  123. package/dist/esm/components/datatable/datatable.recipe.js +11 -2
  124. package/dist/esm/components/dialog/dialog.recipe.js +22 -11
  125. package/dist/esm/components/emptystate/emptystate.recipe.js +7 -2
  126. package/dist/esm/components/fileupload/fileupload.js +20 -5
  127. package/dist/esm/components/input/index.js +1 -1
  128. package/dist/esm/components/input/input.js +33 -3
  129. package/dist/esm/components/input/input.recipe.js +23 -8
  130. package/dist/esm/components/menu/menu.recipe.js +21 -7
  131. package/dist/esm/components/menusheet/index.js +2 -0
  132. package/dist/esm/components/menusheet/menusheet.js +95 -0
  133. package/dist/esm/components/menusheet/menusheet.recipe.js +100 -0
  134. package/dist/esm/components/multiselect/multiselect.js +2 -2
  135. package/dist/esm/components/multiselect/multiselect.recipe.js +45 -12
  136. package/dist/esm/components/progress/progress.js +22 -5
  137. package/dist/esm/components/progress/progress.recipe.js +30 -0
  138. package/dist/esm/components/select/select.js +3 -3
  139. package/dist/esm/components/select/select.recipe.js +63 -10
  140. package/dist/esm/components/snackbar/index.js +2 -0
  141. package/dist/esm/components/snackbar/snackbar.js +84 -0
  142. package/dist/esm/components/snackbar/snackbar.recipe.js +68 -0
  143. package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +7 -2
  144. package/dist/esm/components/tabletoolbar/tabletoolbar.js +37 -12
  145. package/dist/esm/components/tabs/tabs.js +10 -4
  146. package/dist/esm/components/tabs/tabs.recipe.js +23 -6
  147. package/dist/esm/components/text/text.recipe.js +8 -7
  148. package/dist/esm/components/textarea/textarea.js +3 -2
  149. package/dist/esm/components/textarea/textarea.recipe.js +14 -10
  150. package/dist/esm/components/textlink/textlink.recipe.js +6 -3
  151. package/dist/esm/index.js +8 -0
  152. package/dist/esm/product/authshell/authshell.recipe.js +5 -1
  153. package/dist/esm/product/command/command.recipe.js +4 -1
  154. package/dist/esm/product/comments/comments.js +7 -2
  155. package/dist/esm/product/comments/comments.recipe.js +25 -7
  156. package/dist/esm/product/memberssettings/index.js +1 -0
  157. package/dist/esm/product/memberssettings/memberssettings.js +62 -0
  158. package/dist/esm/product/memberssettings/memberssettings.recipe.js +80 -0
  159. package/dist/esm/product/notificationssettings/index.js +1 -0
  160. package/dist/esm/product/notificationssettings/notificationssettings.js +16 -0
  161. package/dist/esm/product/notificationssettings/notificationssettings.recipe.js +41 -0
  162. package/dist/esm/product/recordpage/recordpage.js +102 -10
  163. package/dist/esm/product/recordpage/recordpage.recipe.js +43 -6
  164. package/dist/esm/product/workspacegeneralsettings/index.js +1 -0
  165. package/dist/esm/product/workspacegeneralsettings/workspacegeneralsettings.js +18 -0
  166. package/dist/esm/product/workspacegeneralsettings/workspacegeneralsettings.recipe.js +48 -0
  167. package/dist/esm/tokens/contract.js +2 -1
  168. package/dist/esm/tokens/elevation.js +8 -5
  169. package/dist/esm/tokens/palette.js +107 -33
  170. package/dist/esm/tokens/scale.js +44 -1
  171. package/dist/esm/tokens/semantic.js +26 -0
  172. package/dist/fileupload.css +3 -1
  173. package/dist/fileupload.layered.css +3 -1
  174. package/dist/input.css +11 -2
  175. package/dist/input.layered.css +11 -2
  176. package/dist/listpage.css +3 -1
  177. package/dist/listpage.layered.css +3 -1
  178. package/dist/memberssettings.css +67 -0
  179. package/dist/memberssettings.d.ts +7 -0
  180. package/dist/memberssettings.layered.css +69 -0
  181. package/dist/menu.css +2 -2
  182. package/dist/menu.layered.css +2 -2
  183. package/dist/menusheet.css +36 -0
  184. package/dist/menusheet.d.ts +7 -0
  185. package/dist/menusheet.layered.css +38 -0
  186. package/dist/multiselect.css +17 -6
  187. package/dist/multiselect.d.ts +2 -2
  188. package/dist/multiselect.layered.css +17 -6
  189. package/dist/native/tokens.d.ts +2 -1
  190. package/dist/native/tokens.js +53 -25
  191. package/dist/notificationssettings.css +22 -0
  192. package/dist/notificationssettings.d.ts +7 -0
  193. package/dist/notificationssettings.layered.css +24 -0
  194. package/dist/objectsettings.css +4 -4
  195. package/dist/objectsettings.layered.css +4 -4
  196. package/dist/progress.css +3 -0
  197. package/dist/progress.layered.css +3 -0
  198. package/dist/recordpage.css +67 -23
  199. package/dist/recordpage.layered.css +67 -23
  200. package/dist/recordpanel.css +35 -16
  201. package/dist/recordpanel.layered.css +35 -16
  202. package/dist/resizablepanel.css +8 -5
  203. package/dist/resizablepanel.layered.css +8 -5
  204. package/dist/richtext.css +24 -8
  205. package/dist/richtext.layered.css +24 -8
  206. package/dist/savedviews.css +9 -2
  207. package/dist/savedviews.layered.css +9 -2
  208. package/dist/select.css +47 -7
  209. package/dist/select.d.ts +2 -2
  210. package/dist/select.layered.css +47 -7
  211. package/dist/settingsshell.css +2 -3
  212. package/dist/settingsshell.layered.css +2 -3
  213. package/dist/slider.css +6 -27
  214. package/dist/slider.layered.css +6 -27
  215. package/dist/snackbar.css +24 -0
  216. package/dist/snackbar.d.ts +7 -0
  217. package/dist/snackbar.layered.css +26 -0
  218. package/dist/statcard.css +3 -1
  219. package/dist/statcard.layered.css +3 -1
  220. package/dist/styles.css +927 -365
  221. package/dist/styles.layered.css +927 -365
  222. package/dist/table.css +28 -10
  223. package/dist/table.layered.css +28 -10
  224. package/dist/tabletoolbar.css +35 -24
  225. package/dist/tabletoolbar.layered.css +35 -24
  226. package/dist/tabs.css +18 -4
  227. package/dist/tabs.layered.css +18 -4
  228. package/dist/text.css +1 -1
  229. package/dist/text.layered.css +1 -1
  230. package/dist/textarea.css +4 -7
  231. package/dist/textarea.layered.css +4 -7
  232. package/dist/textlink.css +2 -2
  233. package/dist/textlink.layered.css +2 -2
  234. package/dist/themepicker.css +2 -1
  235. package/dist/themepicker.layered.css +2 -1
  236. package/dist/tokens.css +31 -13
  237. package/dist/tokens.json +53 -25
  238. package/dist/types/components/accentpicker/accentpicker.d.ts +23 -0
  239. package/dist/types/components/accentpicker/accentpicker.recipe.d.ts +3 -0
  240. package/dist/types/components/accentpicker/index.d.ts +2 -0
  241. package/dist/types/components/bottomsheet/bottomsheet.d.ts +35 -0
  242. package/dist/types/components/bottomsheet/bottomsheet.recipe.d.ts +3 -0
  243. package/dist/types/components/bottomsheet/index.d.ts +2 -0
  244. package/dist/types/components/button/button.recipe.d.ts +13 -8
  245. package/dist/types/components/checkbox/checkbox.recipe.d.ts +28 -5
  246. package/dist/types/components/chip/chip.d.ts +22 -0
  247. package/dist/types/components/chip/chip.recipe.d.ts +48 -0
  248. package/dist/types/components/chipgroup/chipgroup.d.ts +14 -0
  249. package/dist/types/components/chipgroup/chipgroup.recipe.d.ts +5 -0
  250. package/dist/types/components/chipgroup/index.d.ts +2 -0
  251. package/dist/types/components/datatable/datatable.d.ts +19 -0
  252. package/dist/types/components/fileupload/fileupload.d.ts +26 -0
  253. package/dist/types/components/input/index.d.ts +1 -1
  254. package/dist/types/components/input/input.d.ts +84 -0
  255. package/dist/types/components/menusheet/index.d.ts +2 -0
  256. package/dist/types/components/menusheet/menusheet.d.ts +42 -0
  257. package/dist/types/components/menusheet/menusheet.recipe.d.ts +3 -0
  258. package/dist/types/components/multiselect/multiselect.d.ts +4 -3
  259. package/dist/types/components/multiselect/multiselect.recipe.d.ts +3 -0
  260. package/dist/types/components/progress/progress.d.ts +16 -4
  261. package/dist/types/components/progress/progress.recipe.d.ts +22 -0
  262. package/dist/types/components/select/select.d.ts +6 -5
  263. package/dist/types/components/select/select.recipe.d.ts +3 -0
  264. package/dist/types/components/snackbar/index.d.ts +2 -0
  265. package/dist/types/components/snackbar/snackbar.d.ts +36 -0
  266. package/dist/types/components/snackbar/snackbar.recipe.d.ts +5 -0
  267. package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +28 -1
  268. package/dist/types/components/tabs/tabs.d.ts +11 -1
  269. package/dist/types/components/textarea/textarea.d.ts +16 -0
  270. package/dist/types/index.d.ts +8 -0
  271. package/dist/types/product/comments/comments.d.ts +9 -3
  272. package/dist/types/product/comments/comments.recipe.d.ts +12 -2
  273. package/dist/types/product/memberssettings/index.d.ts +1 -0
  274. package/dist/types/product/memberssettings/memberssettings.d.ts +85 -0
  275. package/dist/types/product/memberssettings/memberssettings.recipe.d.ts +3 -0
  276. package/dist/types/product/notificationssettings/index.d.ts +1 -0
  277. package/dist/types/product/notificationssettings/notificationssettings.d.ts +37 -0
  278. package/dist/types/product/notificationssettings/notificationssettings.recipe.d.ts +3 -0
  279. package/dist/types/product/recordpage/recordpage.d.ts +89 -2
  280. package/dist/types/product/workspacegeneralsettings/index.d.ts +1 -0
  281. package/dist/types/product/workspacegeneralsettings/workspacegeneralsettings.d.ts +48 -0
  282. package/dist/types/product/workspacegeneralsettings/workspacegeneralsettings.recipe.d.ts +3 -0
  283. package/dist/types/tokens/contract.d.ts +7 -1
  284. package/dist/types/tokens/elevation.d.ts +8 -5
  285. package/dist/types/tokens/palette.d.ts +28 -12
  286. package/dist/types/tokens/scale.d.ts +12 -1
  287. package/dist/types/tokens/semantic.d.ts +17 -0
  288. package/dist/wheelpicker.css +4 -2
  289. package/dist/wheelpicker.layered.css +4 -2
  290. package/dist/workspacegeneralsettings.css +30 -0
  291. package/dist/workspacegeneralsettings.d.ts +7 -0
  292. package/dist/workspacegeneralsettings.layered.css +32 -0
  293. package/package.json +41 -1
@@ -9,11 +9,14 @@
9
9
  beneath (the same borderSubtle every other panel/row edge here
10
10
  already uses). Close keeps the existing transparent ghost button;
11
11
  Previous/Next/Open record are a distinct field-elevation style
12
- (white fill, e.field's own ring+shadow, solid icon) -- measured as genuinely different chrome from Close, not a reuse. */
12
+ (white fill, e.field's own ring+shadow, solid icon) -- measured as
13
+ genuinely different chrome from Close, not a reuse. */
13
14
  & .crisp-recordpanel-toolbar { display: flex; align-items: center; height: 49px; flex-shrink: 0; padding: var(--crisp-space-2) var(--crisp-space-2-5); border-bottom: 1px solid var(--crisp-border-subtle); }
14
15
  & .crisp-recordpanel-toolbar-spacer { flex: 1; }
15
16
  & .crisp-recordpanel-pager { display: flex; align-items: center; gap: var(--crisp-space-1-5); margin-inline-start: var(--crisp-space-3); }
16
- /* #413: "2 of 37 in All Companies" -- measured live, same toolbar row, right after Prev/Next. 12px/500, the same 63%-of-fgPrimary mix every other muted heading in this panel already uses. */
17
+ /* #413: "2 of 37 in All Companies" -- measured live, same toolbar row,
18
+ right after Prev/Next. 12px/500, the same 63%-of-fgPrimary mix every
19
+ other muted heading in this panel already uses. */
17
20
  & .crisp-recordpanel-counter { margin-inline-start: var(--crisp-space-3); font-size: 12px; font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
18
21
  & .crisp-recordpanel-iconbtn { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; flex-shrink: 0; padding: 0; border: none; border-radius: var(--crisp-radius-md); background: transparent; color: color-mix(in srgb, var(--crisp-fg-primary) 55%, transparent); font-family: inherit; cursor: pointer; transition: background-color .12s; }
19
22
  & .crisp-recordpanel-iconbtn:hover { background: var(--crisp-bg-raised); color: var(--crisp-fg-primary); }
@@ -21,26 +24,36 @@
21
24
  & .crisp-recordpanel-navbtn:hover:not(:disabled) { background: var(--crisp-bg-raised); }
22
25
  & .crisp-recordpanel-navbtn:disabled { opacity: 0.4; cursor: not-allowed; }
23
26
  /* #413: measured live -- a 10px strip at the panel's own left edge,
24
- cursor: col-resize (the issue's own repro calls it "ew-resize"; the actual computed value read off the live DOM is col-resize, the same cursor family under a different keyword). Kept fully inside the panel's own box, not extending past inset-inline-start: 0, so the
25
- panel's own overflow: hidden (there for its rounded corners) never clips it. touch-action: none stops a touchscreen's own pan gesture
27
+ cursor: col-resize (the issue's own repro calls it "ew-resize";
28
+ the actual computed value read off the live DOM is col-resize, the
29
+ same cursor family under a different keyword). Kept fully inside the
30
+ panel's own box, not extending past inset-inline-start: 0, so the
31
+ panel's own overflow: hidden (there for its rounded corners) never
32
+ clips it. touch-action: none stops a touchscreen's own pan gesture
26
33
  from fighting the drag. */
27
34
  & .crisp-recordpanel-resize-handle { position: absolute; top: 0; bottom: 0; inset-inline-start: 0; width: 10px; cursor: col-resize; z-index: 1; touch-action: none; }
28
35
  & .crisp-recordpanel-resize-handle:hover, & .crisp-recordpanel-resize-handle:active { background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); }
29
-
30
36
  & .crisp-recordpanel-header { display: flex; align-items: center; gap: var(--crisp-space-2); height: 52px; flex-shrink: 0; padding: 0 var(--crisp-space-3); }
31
37
  & .crisp-recordpanel-fav { width: 22px; height: var(--crisp-size-chip); border-radius: var(--crisp-radius-sm); flex-shrink: 0; object-fit: cover; background: var(--crisp-bg-raised); }
32
38
  & .crisp-recordpanel-title { flex: 1; min-width: 0; font-size: var(--crisp-text-xl); font-weight: var(--crisp-weight-semibold); letter-spacing: -0.2px; color: var(--crisp-fg-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
33
-
34
39
  & .crisp-recordpanel-body { flex: 1; min-height: 0; overflow-y: auto; padding: var(--crisp-space-2) var(--crisp-space-3); }
35
-
36
- /* #448: measured live on app.attio.com's peek (hover a Companies row, click "Open preview"). Section label reads identically for both Highlights and Activity: 14px/500, the same 63%-of-fgPrimary mix RecordPage's own field-label already uses (product/recordpage's .crisp-recordpage-field-label) -- one more surface landing on the same measured "muted section heading" colour. */
40
+ /* #448: measured live on app.attio.com's peek (hover a Companies row,
41
+ click "Open preview"). Section label reads identically for both
42
+ Highlights and Activity: 14px/500, the same 63%-of-fgPrimary mix
43
+ RecordPage's own field-label already uses (product/recordpage's
44
+ .crisp-recordpage-field-label) -- one more surface landing on the
45
+ same measured "muted section heading" colour. */
37
46
  & .crisp-recordpanel-section { padding: var(--crisp-space-2) var(--crisp-space-1) 0; }
38
47
  & .crisp-recordpanel-section-head { display: flex; align-items: center; justify-content: space-between; gap: var(--crisp-space-2); height: 20px; margin-bottom: var(--crisp-space-2); }
39
48
  & .crisp-recordpanel-section-label { font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
40
- /* "View all" -- measured 10px/400, a lighter mix than the section label (55%, not 63%) -- its own distinct, honestly-measured value, not a reuse of a nearby one that happened to be close. */
49
+ /* "View all" -- measured 10px/400, a lighter mix than the section label
50
+ (55%, not 63%) -- its own distinct, honestly-measured value, not a
51
+ reuse of a nearby one that happened to be close. */
41
52
  & .crisp-recordpanel-section-action { border: none; background: none; padding: 0; font-family: inherit; font-size: 10px; font-weight: var(--crisp-weight-regular); color: color-mix(in srgb, var(--crisp-fg-primary) 55%, transparent); cursor: pointer; }
42
53
  & .crisp-recordpanel-section-action:hover { color: var(--crisp-fg-primary); }
43
- /* Highlights: a 2-column grid of label+icon+value cards, no card chrome at all (no border/background/radius/shadow -- confirmed on the live DOM: every highlight's computed style is fully transparent).
54
+ /* Highlights: a 2-column grid of label+icon+value cards, no card
55
+ chrome at all (no border/background/radius/shadow -- confirmed on
56
+ the live DOM: every highlight's computed style is fully transparent).
44
57
  8px row/column gap; two rows measured "233x86" inside 473px content
45
58
  width is exactly (473 - 8) / 2. */
46
59
  & .crisp-recordpanel-highlights { display: grid; grid-template-columns: 1fr 1fr; gap: var(--crisp-space-2); }
@@ -49,27 +62,33 @@
49
62
  & .crisp-recordpanel-highlight-label span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
50
63
  & .crisp-recordpanel-highlight-label svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
51
64
  & .crisp-recordpanel-highlight-value { font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); overflow: hidden; text-overflow: ellipsis; }
52
-
53
65
  /* Activity is a consumer-supplied slot (crisp has no activity-feed
54
66
  model of its own to render) -- this only wraps it with the measured
55
67
  section heading above. */
56
68
  & .crisp-recordpanel-activity { font-size: var(--crisp-text-lg); }
57
-
58
69
  /* #413: collapsed Emails/Notes/Tasks below Activity -- measured live: a
59
- 473px-wide row (the panel's own content width, 497 minus its 12px/8px side insets), 20px tall, 14px/500 solid fgPrimary label (NOT the 63% mix Highlights/Activity headings use -- this is body text, not a muted heading), a trailing count. padding "0 8px 0 12px" measured on the row itself; reproduced here as the trigger's own padding, since
60
- the trigger IS the row (a plain div, not a button, when there's no content to expand into -- matches the empty ("Emails 0") row measured live, which has no expand affordance at all). */
70
+ 473px-wide row (the panel's own content width, 497 minus its 12px/8px
71
+ side insets), 20px tall, 14px/500 solid fgPrimary label (NOT the 63%
72
+ mix Highlights/Activity headings use -- this is body text, not a
73
+ muted heading), a trailing count. padding "0 8px 0 12px" measured on
74
+ the row itself; reproduced here as the trigger's own padding, since
75
+ the trigger IS the row (a plain div, not a button, when there's no
76
+ content to expand into -- matches the empty ("Emails 0") row
77
+ measured live, which has no expand affordance at all). */
61
78
  & .crisp-recordpanel-sections { display: flex; flex-direction: column; padding-top: var(--crisp-space-2); }
62
79
  & .crisp-recordpanel-section-trigger { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; height: 20px; padding: 0 var(--crisp-space-2) 0 var(--crisp-space-3); border: none; background: none; font-family: inherit; text-align: start; cursor: pointer; }
63
80
  & .crisp-recordpanel-section-trigger-inert { cursor: default; }
64
81
  & .crisp-recordpanel-section-row-label { font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
65
82
  /* The count wasn't captured with its own background/pill chrome in the
66
83
  live measurement (only its text: 14px, a "tertiary" internal variant
67
- name that doesn't map to anything crisp defines) -- muted text next to the label, not an invented badge shape. */
84
+ name that doesn't map to anything crisp defines) -- muted text next
85
+ to the label, not an invented badge shape. */
68
86
  & .crisp-recordpanel-section-row-count { font-size: var(--crisp-text-lg); color: var(--crisp-fg-muted); }
69
87
  & .crisp-recordpanel-section-chevron { margin-inline-start: auto; flex-shrink: 0; color: var(--crisp-fg-muted); transition: transform .15s ease; }
70
88
  & .crisp-recordpanel-section-chevron[data-open] { transform: rotate(180deg); }
71
89
  & .crisp-recordpanel-section-content { padding: var(--crisp-space-2) var(--crisp-space-2) var(--crisp-space-2) var(--crisp-space-3); }
72
- /* #329: an optional slot for record actions (e.g. Edit). Reuses the header's own measured values rather than inventing new ones -- the
90
+ /* #329: an optional slot for record actions (e.g. Edit). Reuses the
91
+ header's own measured values rather than inventing new ones -- the
73
92
  same horizontal inset (space.3), the same hairline border token
74
93
  (borderSubtle, flipped to border-top since this sits at the opposite
75
94
  edge), and the header/body gap (space.2) for its own vertical padding
@@ -8,13 +8,15 @@
8
8
  & .crisp-resizablepanel-panel[data-floating="false"] { border-radius: 0; box-shadow: none; }
9
9
  & .crisp-resizablepanel-panel[data-floating="false"][data-side="left"] { border-inline-end: 1px solid var(--crisp-border-subtle); }
10
10
  & .crisp-resizablepanel-panel[data-floating="false"][data-side="right"] { border-inline-start: 1px solid var(--crisp-border-subtle); }
11
- /* floating — position: fixed, 8px gutter, r10, the measured floating elevation. Rest is transform: none (Lesson 27); the off-canvas value is the @starting-style enter only. */
11
+ /* floating — position: fixed, 8px gutter, r10, the measured floating elevation.
12
+ Rest is transform: none (Lesson 27); the off-canvas value is the @starting-style enter only. */
12
13
  & .crisp-resizablepanel-panel[data-floating="true"] { position: fixed; top: var(--crisp-space-2); bottom: var(--crisp-space-2); border-inline-end: none; border-inline-start: none; border-radius: 10px; box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform: none; transition: transform 0.14s, padding 0.14s; }
13
14
  & .crisp-resizablepanel-panel[data-floating="true"][data-side="left"] { padding: var(--crisp-space-2) 0 var(--crisp-space-2) var(--crisp-space-2); @starting-style { transform: translateX(calc(-100% - var(--crisp-space-2))); } }
14
15
  & .crisp-resizablepanel-panel[data-floating="true"][data-side="right"] { padding: var(--crisp-space-2) var(--crisp-space-2) var(--crisp-space-2) 0; @starting-style { transform: translateX(calc(100% + var(--crisp-space-2))); } }
15
16
  & .crisp-resizablepanel-inner { height: 100%; opacity: 1; }
16
17
  & .crisp-resizablepanel-panel[data-floating="true"] .crisp-resizablepanel-inner { opacity: 1; transition: opacity 0.14s; @starting-style { opacity: 0; } }
17
- /* handle — variant "panel" (default): a 10px hit target, its ::before the only visible divider (1px rest -> 2px on hover/drag, brand-solid). */
18
+ /* handle — variant "panel" (default): a 10px hit target, its ::before the
19
+ only visible divider (1px rest -> 2px on hover/drag, brand-solid). */
18
20
  & .crisp-resizablepanel-handle { position: absolute; top: 0; width: 10px; height: 100%; z-index: 2; cursor: col-resize; background: transparent; touch-action: none; }
19
21
  & .crisp-resizablepanel-handle[data-side="left"] { right: 0; }
20
22
  & .crisp-resizablepanel-handle[data-side="right"] { left: 0; }
@@ -22,9 +24,10 @@
22
24
  & .crisp-resizablepanel-handle[data-side="left"]::before { right: 0; }
23
25
  & .crisp-resizablepanel-handle[data-side="right"]::before { left: 0; }
24
26
  & .crisp-resizablepanel-handle:hover::before, & .crisp-resizablepanel-handle[data-dragging="true"]::before { width: 2px; background: var(--crisp-bg-brand-solid); }
25
- /* handle — variant "column": a wider 7px hit target straddling a 1px divider (table column edges), with a real 3px inner bar whose opacity comes in on a 100ms DELAY — distinct from the panel variant's instant
26
- ::before swap. */
27
- /* .crisp-resizablepanel-handle.crisp-resizablepanel-handle--column (both classes) to
27
+ /* handle — variant "column": a wider 7px hit target straddling a 1px
28
+ divider (table column edges), with a real 3px inner bar whose opacity
29
+ comes in on a 100ms DELAY — distinct from the panel variant's instant
30
+ ::before swap. */ /* .crisp-resizablepanel-handle.crisp-resizablepanel-handle--column (both classes) to
28
31
  out-specificity the base [data-side] left/right rules above, which
29
32
  otherwise tie-break by source order alone and would win. */
30
33
  & .crisp-resizablepanel-handle.crisp-resizablepanel-handle--column { display: flex; align-items: center; justify-content: center; width: 7px; left: -3px; right: -3px; z-index: 1; cursor: col-resize; }
@@ -9,13 +9,15 @@
9
9
  & .crisp-resizablepanel-panel[data-floating="false"] { border-radius: 0; box-shadow: none; }
10
10
  & .crisp-resizablepanel-panel[data-floating="false"][data-side="left"] { border-inline-end: 1px solid var(--crisp-border-subtle); }
11
11
  & .crisp-resizablepanel-panel[data-floating="false"][data-side="right"] { border-inline-start: 1px solid var(--crisp-border-subtle); }
12
- /* floating — position: fixed, 8px gutter, r10, the measured floating elevation. Rest is transform: none (Lesson 27); the off-canvas value is the @starting-style enter only. */
12
+ /* floating — position: fixed, 8px gutter, r10, the measured floating elevation.
13
+ Rest is transform: none (Lesson 27); the off-canvas value is the @starting-style enter only. */
13
14
  & .crisp-resizablepanel-panel[data-floating="true"] { position: fixed; top: var(--crisp-space-2); bottom: var(--crisp-space-2); border-inline-end: none; border-inline-start: none; border-radius: 10px; box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform: none; transition: transform 0.14s, padding 0.14s; }
14
15
  & .crisp-resizablepanel-panel[data-floating="true"][data-side="left"] { padding: var(--crisp-space-2) 0 var(--crisp-space-2) var(--crisp-space-2); @starting-style { transform: translateX(calc(-100% - var(--crisp-space-2))); } }
15
16
  & .crisp-resizablepanel-panel[data-floating="true"][data-side="right"] { padding: var(--crisp-space-2) var(--crisp-space-2) var(--crisp-space-2) 0; @starting-style { transform: translateX(calc(100% + var(--crisp-space-2))); } }
16
17
  & .crisp-resizablepanel-inner { height: 100%; opacity: 1; }
17
18
  & .crisp-resizablepanel-panel[data-floating="true"] .crisp-resizablepanel-inner { opacity: 1; transition: opacity 0.14s; @starting-style { opacity: 0; } }
18
- /* handle — variant "panel" (default): a 10px hit target, its ::before the only visible divider (1px rest -> 2px on hover/drag, brand-solid). */
19
+ /* handle — variant "panel" (default): a 10px hit target, its ::before the
20
+ only visible divider (1px rest -> 2px on hover/drag, brand-solid). */
19
21
  & .crisp-resizablepanel-handle { position: absolute; top: 0; width: 10px; height: 100%; z-index: 2; cursor: col-resize; background: transparent; touch-action: none; }
20
22
  & .crisp-resizablepanel-handle[data-side="left"] { right: 0; }
21
23
  & .crisp-resizablepanel-handle[data-side="right"] { left: 0; }
@@ -23,9 +25,10 @@
23
25
  & .crisp-resizablepanel-handle[data-side="left"]::before { right: 0; }
24
26
  & .crisp-resizablepanel-handle[data-side="right"]::before { left: 0; }
25
27
  & .crisp-resizablepanel-handle:hover::before, & .crisp-resizablepanel-handle[data-dragging="true"]::before { width: 2px; background: var(--crisp-bg-brand-solid); }
26
- /* handle — variant "column": a wider 7px hit target straddling a 1px divider (table column edges), with a real 3px inner bar whose opacity comes in on a 100ms DELAY — distinct from the panel variant's instant
27
- ::before swap. */
28
- /* .crisp-resizablepanel-handle.crisp-resizablepanel-handle--column (both classes) to
28
+ /* handle — variant "column": a wider 7px hit target straddling a 1px
29
+ divider (table column edges), with a real 3px inner bar whose opacity
30
+ comes in on a 100ms DELAY — distinct from the panel variant's instant
31
+ ::before swap. */ /* .crisp-resizablepanel-handle.crisp-resizablepanel-handle--column (both classes) to
29
32
  out-specificity the base [data-side] left/right rules above, which
30
33
  otherwise tie-break by source order alone and would win. */
31
34
  & .crisp-resizablepanel-handle.crisp-resizablepanel-handle--column { display: flex; align-items: center; justify-content: center; width: 7px; left: -3px; right: -3px; z-index: 1; cursor: col-resize; }
package/dist/richtext.css CHANGED
@@ -9,13 +9,28 @@
9
9
  & .crisp-rte-body h1 { font-size: var(--crisp-text-xl); line-height: 28px; font-weight: var(--crisp-weight-semibold); letter-spacing: -0.3px; margin-top: var(--crisp-space-4); }
10
10
  & .crisp-rte-body h2 { font-size: 17px; line-height: 24px; font-weight: var(--crisp-weight-semibold); letter-spacing: -0.2px; margin-top: var(--crisp-space-3); }
11
11
  & .crisp-rte-body h3 { font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-semibold); margin-top: var(--crisp-space-2-5); }
12
- /* #575: a consumer's CSS reset (e.g. Tailwind preflight's un-scoped ul, ol { list-style: none }
13
- , specificity 0,0,1) was winning every list marker outright -- this rule set padding but never declared list-style-type, so there was no higher-specificity value (this selector is 0,1,1) to beat the reset with. Split into two single-selector rules, each declaring its own marker type, rather than the old single comma-joined rule ( .crisp-rte-body ul, & .crisp-rte-body ol ) the issue flagged as malformed. #611: padding-inline-start re-measured live once CRUD on the measurement workspace was allowed (a "zz-parity" note with a bulleted list, a nested bulleted list, and a numbered list) -- Attio's own <ul>/<ol> measures 36px (getComputedStyle,
12
+ /* #575: a consumer's CSS reset (e.g. Tailwind preflight's un-scoped
13
+ ul, ol { list-style: none }, specificity 0,0,1) was winning every
14
+ list marker outright -- this rule set padding but never declared
15
+ list-style-type, so there was no higher-specificity value (this
16
+ selector is 0,1,1) to beat the reset with. Split into two
17
+ single-selector rules, each declaring its own marker type, rather
18
+ than the old single comma-joined rule ( .crisp-rte-body ul, &
19
+ .crisp-rte-body ol ) the issue flagged as malformed.
20
+ #611: padding-inline-start re-measured live once CRUD on the
21
+ measurement workspace was allowed (a "zz-parity" note with a
22
+ bulleted list, a nested bulleted list, and a numbered list) --
23
+ Attio's own <ul>/<ol> measures 36px (getComputedStyle,
14
24
  ~36.1353px), not the 20px placeholder #575 shipped with no real
15
- content to check against. 36px isn't in tokens/scale.ts (steps stop at 24px, jump to 32px) and is a single component-intrinsic value, so it stays a raw px per AUTHORING.md's golden rule 4b
25
+ content to check against. 36px isn't in tokens/scale.ts (steps
26
+ stop at 24px, jump to 32px) and is a single component-intrinsic
27
+ value, so it stays a raw px per AUTHORING.md's golden rule 4b
16
28
  rather than being rounded to an existing token or added to the
17
29
  shared scale. Marker colour (currentColor via the already-measured
18
- fgPrimary, confirmed to equal Attio's measured rgb(16,17,18) == #101112 exactly) and the ~4px li-to-li gap (the existing li margin-top rule below) were re-checked at the same time and already matched -- only the padding was wrong. Attio doesn't vary
30
+ fgPrimary, confirmed to equal Attio's measured rgb(16,17,18) ==
31
+ #101112 exactly) and the ~4px li-to-li gap (the existing li
32
+ margin-top rule below) were re-checked at the same time and
33
+ already matched -- only the padding was wrong. Attio doesn't vary
19
34
  marker type for a nested list either (nested <ul> is disc too,
20
35
  not circle), which this already doesn't attempt. */
21
36
  & .crisp-rte-body ul { list-style-type: disc; padding-inline-start: 36px; }
@@ -26,10 +41,13 @@
26
41
  & .crisp-rte-body a { color: var(--crisp-bg-brand-solid); text-decoration: underline; text-underline-offset: 2px; }
27
42
  & .crisp-rte-body strong { font-weight: var(--crisp-weight-semibold); }
28
43
  & .crisp-rte-body img { display: block; max-width: 100%; border-radius: var(--crisp-radius-md); }
29
- /* Not measured against Attio (#428) — nothing in a read-only pass over app.attio.com had a live @mention rendered to read computed styles from, and typing one to create one is off-limits there. Reused verbatim from the one measured "brand" tag/chip this repo already has (RecordsTable/MultiSelect's [data-tone="brand"]) rather than
44
+ /* Not measured against Attio (#428) — nothing in a read-only pass over
45
+ app.attio.com had a live @mention rendered to read computed styles
46
+ from, and typing one to create one is off-limits there. Reused
47
+ verbatim from the one measured "brand" tag/chip this repo already
48
+ has (RecordsTable/MultiSelect's [data-tone="brand"]) rather than
30
49
  inventing a new color or shape. */
31
50
  & .crisp-rte-mention { display: inline; border-radius: var(--crisp-radius-chip); padding: 0 var(--crisp-space-1); background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); font-weight: var(--crisp-weight-medium); cursor: default; }
32
-
33
51
  & .crisp-rte-toolbar { position: fixed; z-index: 70; display: inline-flex; align-items: center; gap: 2px; padding: 2px; border-radius: 10px; background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform: translate(-50%, -100%); opacity: 1; transition: opacity 0.1s ease; }
34
52
  & .crisp-rte-toolbar { @starting-style { opacity: 0; } }
35
53
  & .crisp-rte-tool { display: inline-flex; align-items: center; justify-content: center; gap: var(--crisp-space-1); min-width: 30px; height: 28px; padding: 0 7px; margin: 0; border: none; border-radius: var(--crisp-radius-md); background: none; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); font-family: inherit; font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); cursor: pointer; transition: background-color .1s; }
@@ -37,13 +55,11 @@
37
55
  & .crisp-rte-tool:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: var(--crisp-fg-primary); }
38
56
  & .crisp-rte-tool[data-active], & .crisp-rte-tool[aria-expanded="true"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 12%, transparent); color: var(--crisp-bg-brand-solid); }
39
57
  & .crisp-rte-tool-sep { width: 1px; height: 16px; margin: 0 2px; background: var(--crisp-border-subtle); }
40
-
41
58
  & .crisp-rte-swatchpanel { position: fixed; z-index: 71; display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--crisp-space-1); width: 168px; padding: var(--crisp-space-1-5); border-radius: var(--crisp-radius-lg); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform: translate(-50%, var(--crisp-space-1-5)); opacity: 1; transition: opacity 0.1s ease; }
42
59
  & .crisp-rte-swatchpanel { @starting-style { opacity: 0; } }
43
60
  & .crisp-rte-swatch { width: 28px; height: 28px; padding: 0; margin: 0; border: none; border-radius: 50%; background: none; font-family: inherit; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 10%, transparent); cursor: pointer; }
44
61
  & .crisp-rte-swatch--none { background: var(--crisp-bg-surface); position: relative; }
45
62
  & .crisp-rte-swatch--none::after { content: ""; position: absolute; inset: 6px; border-top: 1.5px solid color-mix(in srgb, var(--crisp-fg-primary) 40%, transparent); transform: rotate(-45deg); }
46
-
47
63
  & .crisp-rte-blockmenu { position: fixed; z-index: 71; box-sizing: border-box; width: 356px; padding: 0; border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); opacity: 1; transition: opacity 0.1s ease; }
48
64
  & .crisp-rte-blockmenu { @starting-style { opacity: 0; } }
49
65
  & .crisp-rte-blockmenu-search { display: flex; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-2-5) var(--crisp-space-3); border-bottom: 1px solid var(--crisp-border-subtle); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
@@ -10,13 +10,28 @@
10
10
  & .crisp-rte-body h1 { font-size: var(--crisp-text-xl); line-height: 28px; font-weight: var(--crisp-weight-semibold); letter-spacing: -0.3px; margin-top: var(--crisp-space-4); }
11
11
  & .crisp-rte-body h2 { font-size: 17px; line-height: 24px; font-weight: var(--crisp-weight-semibold); letter-spacing: -0.2px; margin-top: var(--crisp-space-3); }
12
12
  & .crisp-rte-body h3 { font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-semibold); margin-top: var(--crisp-space-2-5); }
13
- /* #575: a consumer's CSS reset (e.g. Tailwind preflight's un-scoped ul, ol { list-style: none }
14
- , specificity 0,0,1) was winning every list marker outright -- this rule set padding but never declared list-style-type, so there was no higher-specificity value (this selector is 0,1,1) to beat the reset with. Split into two single-selector rules, each declaring its own marker type, rather than the old single comma-joined rule ( .crisp-rte-body ul, & .crisp-rte-body ol ) the issue flagged as malformed. #611: padding-inline-start re-measured live once CRUD on the measurement workspace was allowed (a "zz-parity" note with a bulleted list, a nested bulleted list, and a numbered list) -- Attio's own <ul>/<ol> measures 36px (getComputedStyle,
13
+ /* #575: a consumer's CSS reset (e.g. Tailwind preflight's un-scoped
14
+ ul, ol { list-style: none }, specificity 0,0,1) was winning every
15
+ list marker outright -- this rule set padding but never declared
16
+ list-style-type, so there was no higher-specificity value (this
17
+ selector is 0,1,1) to beat the reset with. Split into two
18
+ single-selector rules, each declaring its own marker type, rather
19
+ than the old single comma-joined rule ( .crisp-rte-body ul, &
20
+ .crisp-rte-body ol ) the issue flagged as malformed.
21
+ #611: padding-inline-start re-measured live once CRUD on the
22
+ measurement workspace was allowed (a "zz-parity" note with a
23
+ bulleted list, a nested bulleted list, and a numbered list) --
24
+ Attio's own <ul>/<ol> measures 36px (getComputedStyle,
15
25
  ~36.1353px), not the 20px placeholder #575 shipped with no real
16
- content to check against. 36px isn't in tokens/scale.ts (steps stop at 24px, jump to 32px) and is a single component-intrinsic value, so it stays a raw px per AUTHORING.md's golden rule 4b
26
+ content to check against. 36px isn't in tokens/scale.ts (steps
27
+ stop at 24px, jump to 32px) and is a single component-intrinsic
28
+ value, so it stays a raw px per AUTHORING.md's golden rule 4b
17
29
  rather than being rounded to an existing token or added to the
18
30
  shared scale. Marker colour (currentColor via the already-measured
19
- fgPrimary, confirmed to equal Attio's measured rgb(16,17,18) == #101112 exactly) and the ~4px li-to-li gap (the existing li margin-top rule below) were re-checked at the same time and already matched -- only the padding was wrong. Attio doesn't vary
31
+ fgPrimary, confirmed to equal Attio's measured rgb(16,17,18) ==
32
+ #101112 exactly) and the ~4px li-to-li gap (the existing li
33
+ margin-top rule below) were re-checked at the same time and
34
+ already matched -- only the padding was wrong. Attio doesn't vary
20
35
  marker type for a nested list either (nested <ul> is disc too,
21
36
  not circle), which this already doesn't attempt. */
22
37
  & .crisp-rte-body ul { list-style-type: disc; padding-inline-start: 36px; }
@@ -27,10 +42,13 @@
27
42
  & .crisp-rte-body a { color: var(--crisp-bg-brand-solid); text-decoration: underline; text-underline-offset: 2px; }
28
43
  & .crisp-rte-body strong { font-weight: var(--crisp-weight-semibold); }
29
44
  & .crisp-rte-body img { display: block; max-width: 100%; border-radius: var(--crisp-radius-md); }
30
- /* Not measured against Attio (#428) — nothing in a read-only pass over app.attio.com had a live @mention rendered to read computed styles from, and typing one to create one is off-limits there. Reused verbatim from the one measured "brand" tag/chip this repo already has (RecordsTable/MultiSelect's [data-tone="brand"]) rather than
45
+ /* Not measured against Attio (#428) — nothing in a read-only pass over
46
+ app.attio.com had a live @mention rendered to read computed styles
47
+ from, and typing one to create one is off-limits there. Reused
48
+ verbatim from the one measured "brand" tag/chip this repo already
49
+ has (RecordsTable/MultiSelect's [data-tone="brand"]) rather than
31
50
  inventing a new color or shape. */
32
51
  & .crisp-rte-mention { display: inline; border-radius: var(--crisp-radius-chip); padding: 0 var(--crisp-space-1); background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); font-weight: var(--crisp-weight-medium); cursor: default; }
33
-
34
52
  & .crisp-rte-toolbar { position: fixed; z-index: 70; display: inline-flex; align-items: center; gap: 2px; padding: 2px; border-radius: 10px; background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform: translate(-50%, -100%); opacity: 1; transition: opacity 0.1s ease; }
35
53
  & .crisp-rte-toolbar { @starting-style { opacity: 0; } }
36
54
  & .crisp-rte-tool { display: inline-flex; align-items: center; justify-content: center; gap: var(--crisp-space-1); min-width: 30px; height: 28px; padding: 0 7px; margin: 0; border: none; border-radius: var(--crisp-radius-md); background: none; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); font-family: inherit; font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); cursor: pointer; transition: background-color .1s; }
@@ -38,13 +56,11 @@
38
56
  & .crisp-rte-tool:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: var(--crisp-fg-primary); }
39
57
  & .crisp-rte-tool[data-active], & .crisp-rte-tool[aria-expanded="true"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 12%, transparent); color: var(--crisp-bg-brand-solid); }
40
58
  & .crisp-rte-tool-sep { width: 1px; height: 16px; margin: 0 2px; background: var(--crisp-border-subtle); }
41
-
42
59
  & .crisp-rte-swatchpanel { position: fixed; z-index: 71; display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--crisp-space-1); width: 168px; padding: var(--crisp-space-1-5); border-radius: var(--crisp-radius-lg); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform: translate(-50%, var(--crisp-space-1-5)); opacity: 1; transition: opacity 0.1s ease; }
43
60
  & .crisp-rte-swatchpanel { @starting-style { opacity: 0; } }
44
61
  & .crisp-rte-swatch { width: 28px; height: 28px; padding: 0; margin: 0; border: none; border-radius: 50%; background: none; font-family: inherit; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 10%, transparent); cursor: pointer; }
45
62
  & .crisp-rte-swatch--none { background: var(--crisp-bg-surface); position: relative; }
46
63
  & .crisp-rte-swatch--none::after { content: ""; position: absolute; inset: 6px; border-top: 1.5px solid color-mix(in srgb, var(--crisp-fg-primary) 40%, transparent); transform: rotate(-45deg); }
47
-
48
64
  & .crisp-rte-blockmenu { position: fixed; z-index: 71; box-sizing: border-box; width: 356px; padding: 0; border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); opacity: 1; transition: opacity 0.1s ease; }
49
65
  & .crisp-rte-blockmenu { @starting-style { opacity: 0; } }
50
66
  & .crisp-rte-blockmenu-search { display: flex; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-2-5) var(--crisp-space-3); border-bottom: 1px solid var(--crisp-border-subtle); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
@@ -74,9 +74,16 @@
74
74
 
75
75
  .crisp-savedviews {
76
76
  position: relative; display: inline-flex; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* crisp/#772 follow-up, re-measured live 2026-09-25 in the trigger's
77
- actual position (Attio's real view bar, next to View settings -- fixed there in #766/#768/#778): white (bgSurface, rgb(255,255,255) exact) with elevation.field's 3-layer shadow, the same raised
77
+ actual position (Attio's real view bar, next to View settings --
78
+ fixed there in #766/#768/#778): white (bgSurface, rgb(255,255,255)
79
+ exact) with elevation.field's 3-layer shadow, the same raised
78
80
  chrome View settings and Import/Export both carry
79
- (tabletoolbar.recipe.ts's own --raised, not reused here directly since this is a separate recipe/component, but the identical measured values). Supersedes the original #555 measurement (rgb(246,247,247), reused as bgRaised -- a flat grey fill with no shadow at all), which was wrong: this trigger was never re-checked once it moved into its real view-bar position. */
81
+ (tabletoolbar.recipe.ts's own --raised, not reused here directly
82
+ since this is a separate recipe/component, but the identical measured
83
+ values). Supersedes the original #555 measurement (rgb(246,247,247),
84
+ reused as bgRaised -- a flat grey fill with no shadow at all), which
85
+ was wrong: this trigger was never re-checked once it moved into its
86
+ real view-bar position. */
80
87
  & .crisp-savedviews-trigger { box-sizing: border-box; display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-row); margin: 0; padding: var(--crisp-space-1) var(--crisp-space-1-5); border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-ring-neutral), 0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04); font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); cursor: pointer; white-space: nowrap; transition: background-color .12s ease; }
81
88
  & .crisp-savedviews-trigger:hover, & .crisp-savedviews-trigger[data-open] { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); }
82
89
  & .crisp-savedviews-trigger-icon { flex-shrink: 0; display: inline-flex; width: var(--crisp-size-icon); height: var(--crisp-size-icon); }
@@ -75,9 +75,16 @@
75
75
 
76
76
  .crisp-savedviews {
77
77
  position: relative; display: inline-flex; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* crisp/#772 follow-up, re-measured live 2026-09-25 in the trigger's
78
- actual position (Attio's real view bar, next to View settings -- fixed there in #766/#768/#778): white (bgSurface, rgb(255,255,255) exact) with elevation.field's 3-layer shadow, the same raised
78
+ actual position (Attio's real view bar, next to View settings --
79
+ fixed there in #766/#768/#778): white (bgSurface, rgb(255,255,255)
80
+ exact) with elevation.field's 3-layer shadow, the same raised
79
81
  chrome View settings and Import/Export both carry
80
- (tabletoolbar.recipe.ts's own --raised, not reused here directly since this is a separate recipe/component, but the identical measured values). Supersedes the original #555 measurement (rgb(246,247,247), reused as bgRaised -- a flat grey fill with no shadow at all), which was wrong: this trigger was never re-checked once it moved into its real view-bar position. */
82
+ (tabletoolbar.recipe.ts's own --raised, not reused here directly
83
+ since this is a separate recipe/component, but the identical measured
84
+ values). Supersedes the original #555 measurement (rgb(246,247,247),
85
+ reused as bgRaised -- a flat grey fill with no shadow at all), which
86
+ was wrong: this trigger was never re-checked once it moved into its
87
+ real view-bar position. */
81
88
  & .crisp-savedviews-trigger { box-sizing: border-box; display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-row); margin: 0; padding: var(--crisp-space-1) var(--crisp-space-1-5); border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-ring-neutral), 0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04); font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); cursor: pointer; white-space: nowrap; transition: background-color .12s ease; }
82
89
  & .crisp-savedviews-trigger:hover, & .crisp-savedviews-trigger[data-open] { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); }
83
90
  & .crisp-savedviews-trigger-icon { flex-shrink: 0; display: inline-flex; width: var(--crisp-size-icon); height: var(--crisp-size-icon); }
package/dist/select.css CHANGED
@@ -13,10 +13,34 @@
13
13
  }
14
14
  .crisp-select-listbox[data-up] { transform-origin: bottom left; }
15
15
  .crisp-select-listbox { @starting-style { opacity: 0; transform: scale(0.95); } }
16
- .crisp-select-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: 34px; flex-shrink: 0; margin: calc(-1 * var(--crisp-space-2)) calc(-1 * var(--crisp-space-2)) var(--crisp-space-2); padding: 0 var(--crisp-space-2-5); border-bottom: 1px solid var(--crisp-border-subtle); color: var(--crisp-fg-neutral-muted); }
16
+ /* Composed from @seed-design/rootage's text-input.yaml
17
+ (variant=outline,size=medium) -- seed's Select has no search field of
18
+ its own to resolve this from (see the file header), so this reuses
19
+ the SAME tokens #867 already resolved for the trigger at this size:
20
+ minHeight x10 (var(--crisp-size-selectTriggerMd)), paddingX x3_5
21
+ (var(--crisp-space-3-5)), gap x2 (var(--crisp-space-2)), cornerRadius r2
22
+ (var(--crisp-radius-md)), strokeColor stroke.neutral-weak
23
+ (var(--crisp-stroke-select-trigger)) -- a real bordered field sitting flush
24
+ inside the listbox's own 8px padding, replacing the old bare
25
+ 34px/no-border/bleeds-to-the-edge strip (crisp/#904). */
26
+ .crisp-select-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-selectTriggerMd); flex-shrink: 0; padding: 0 var(--crisp-space-3-5); border: 1px solid var(--crisp-stroke-select-trigger); border-radius: var(--crisp-radius-md); color: var(--crisp-fg-neutral-muted); }
17
27
  .crisp-select-search svg { flex-shrink: 0; }
18
- .crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-select-neutral); }
28
+ .crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); line-height: 19px; color: var(--crisp-fg-select-neutral); }
19
29
  .crisp-select-search input::placeholder { color: var(--crisp-fg-select-placeholder); }
30
+ /* select.yaml's own divider slot (marginX x4, height 1px, colour
31
+ stroke.neutral-muted -- described upstream as "the line marking a
32
+ boundary between semantic units: between sections, between content
33
+ and an action area, between a header and a body" -- exactly the
34
+ search-field/option-list boundary crisp#904's review flagged as
35
+ reading too tight). Not the general-purpose separator #867 declined
36
+ to build (nothing groups options with one) -- scoped to this one
37
+ specific header/body seam, which now exists because searchable
38
+ does. Sits as an ordinary flex child, so the listbox's own 8px gap
39
+ still applies on both sides of it -- total visual seam is
40
+ gap+1px+gap (17px), deliberately more than the 8px between two
41
+ plain option rows, so it reads as a section break, not a wider list
42
+ gap. */
43
+ .crisp-select-divider { flex-shrink: 0; height: 1px; margin-inline: var(--crisp-space-4); background: var(--crisp-stroke-select-divider); }
20
44
  .crisp-select-empty { padding: var(--crisp-space-3) var(--crisp-space-4); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-neutral-subtle); }
21
45
  /* select.yaml's groupLabel -- font-size/line-height/weight are the same
22
46
  across sizes, only paddingY differs (medium 8px, large 10px). */
@@ -46,21 +70,27 @@
46
70
  .crisp-select {
47
71
  position: relative; display: inline-flex; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
48
72
  & .crisp-select-trigger { box-sizing: border-box; display: inline-flex; align-items: center; width: 100%; min-width: 0; margin: 0; border: 1px solid var(--crisp-stroke-select-trigger); background: transparent; cursor: pointer; font-family: inherit; color: var(--crisp-fg-select-neutral); transition: background-color .15s cubic-bezier(.35,0,.35,1), border-color .1s cubic-bezier(.35,0,.35,1), border-width .1s cubic-bezier(.35,0,.35,1); }
49
- /* seed defines no hover state for this trigger -- only pressed, invalid, disabled and readonly. The scale-down is scoped to the CONTENT (seed's scaleScope: content), not the button itself, so the border
50
- never moves. */
51
- /* Only the value scales, not the chevron: the chevron's own transform is its open/close rotation, and a scale would fight it for one shared CSS property when both are true at once (pressing while open). */
73
+ /* seed defines no hover state for this trigger -- only pressed, invalid,
74
+ disabled and readonly. The scale-down is scoped to the CONTENT
75
+ (seed's scaleScope: content), not the button itself, so the border
76
+ never moves. */ /* Only the value scales, not the chevron: the chevron's own transform is
77
+ its open/close rotation, and a scale would fight it for one shared
78
+ CSS property when both are true at once (pressing while open). */
52
79
  & .crisp-select-trigger:active:not(:disabled):not([aria-readonly="true"]) { background: var(--crisp-bg-select-pressed); }
53
80
  & .crisp-select-trigger:active:not(:disabled):not([aria-readonly="true"]) .crisp-select-value { transform: scale(0.98); }
54
81
  & .crisp-select-trigger:focus-visible { outline: 2px solid var(--crisp-stroke-focus-ring); outline-offset: -2px; }
55
82
  & .crisp-select-trigger:disabled { background: var(--crisp-bg-select-disabled); cursor: not-allowed; }
56
83
  & .crisp-select-trigger:disabled .crisp-select-value, & .crisp-select-trigger:disabled .crisp-select-placeholder, & .crisp-select-trigger:disabled .crisp-select-chevron { color: var(--crisp-fg-disabled); }
57
- /* readonly: same fill as disabled, but the value/placeholder text stays normal ink -- it reads as "answered and locked", not "answered and
84
+ /* readonly: same fill as disabled, but the value/placeholder text stays
85
+ normal ink -- it reads as "answered and locked", not "answered and
58
86
  greyed out" (select-trigger.yaml's readonly state only overrides
59
87
  root.color; value/placeholder keep their enabled colours). */
60
88
  & .crisp-select-trigger[aria-readonly="true"] { background: var(--crisp-bg-select-disabled); cursor: default; }
61
89
  & .crisp-select-value { flex: 1; min-width: 0; display: inline-flex; align-items: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: start; transition: transform .15s cubic-bezier(0,0,.15,1); }
62
90
  & .crisp-select-placeholder { color: var(--crisp-fg-select-placeholder); }
63
- /* closeRotateDuration/closeRotateTimingFunction: 100ms, seed's "easing" curve. Overridden to 150ms on open (openRotateDuration) below -- same curve both ways, only the duration differs. */
91
+ /* closeRotateDuration/closeRotateTimingFunction: 100ms, seed's "easing"
92
+ curve. Overridden to 150ms on open (openRotateDuration) below --
93
+ same curve both ways, only the duration differs. */
64
94
  & .crisp-select-chevron { flex-shrink: 0; color: var(--crisp-fg-neutral-muted); transition: transform .1s cubic-bezier(.35,0,.35,1); }
65
95
  & .crisp-select-trigger[data-open] .crisp-select-chevron { transform: rotate(180deg); transition-duration: .15s; }
66
96
  }
@@ -70,6 +100,16 @@
70
100
  .crisp-select--width_auto {
71
101
  width: auto;
72
102
  }
103
+ .crisp-select--size_small {
104
+ & .crisp-select-trigger { height: var(--crisp-size-menuRow); border-radius: var(--crisp-radius-md); gap: var(--crisp-space-1-5); padding-inline: var(--crisp-space-2-5); }
105
+ & .crisp-select-value, & .crisp-select-placeholder { font-size: var(--crisp-text-lg); line-height: 20px; }
106
+ & .crisp-select-chevron { width: var(--crisp-size-icon); height: var(--crisp-size-icon); }
107
+ .crisp-select-option { gap: var(--crisp-space-2); }
108
+ .crisp-select-option-label { font-size: var(--crisp-text-lg); line-height: 19px; }
109
+ .crisp-select-option-description { font-size: var(--crisp-text-sm); line-height: 16px; }
110
+ .crisp-select-option-check { width: var(--crisp-space-3); height: var(--crisp-space-3); }
111
+ .crisp-select-label { padding-top: var(--crisp-space-2); }
112
+ }
73
113
  .crisp-select--size_medium {
74
114
  & .crisp-select-trigger { height: var(--crisp-size-selectTriggerMd); border-radius: var(--crisp-radius-md); gap: var(--crisp-space-2); padding-inline: var(--crisp-space-3-5); }
75
115
  & .crisp-select-value, & .crisp-select-placeholder { font-size: var(--crisp-text-lg); line-height: 19px; }
package/dist/select.d.ts CHANGED
@@ -2,9 +2,9 @@ import type { RecipeFn } from "../core/types";
2
2
 
3
3
  export interface SelectVariants {
4
4
  width?: "full" | "auto";
5
- size?: "medium" | "large";
5
+ size?: "small" | "medium" | "large";
6
6
  invalid?: boolean;
7
7
  variant?: "default" | "ghost";
8
8
  }
9
9
 
10
- export declare const selectRecipe: RecipeFn<{ width: { full: string; auto: string }; size: { medium: string; large: string }; invalid: { true: string; false: string }; variant: { default: string; ghost: string } }>;
10
+ export declare const selectRecipe: RecipeFn<{ width: { full: string; auto: string }; size: { small: string; medium: string; large: string }; invalid: { true: string; false: string }; variant: { default: string; ghost: string } }>;
@@ -14,10 +14,34 @@
14
14
  }
15
15
  .crisp-select-listbox[data-up] { transform-origin: bottom left; }
16
16
  .crisp-select-listbox { @starting-style { opacity: 0; transform: scale(0.95); } }
17
- .crisp-select-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: 34px; flex-shrink: 0; margin: calc(-1 * var(--crisp-space-2)) calc(-1 * var(--crisp-space-2)) var(--crisp-space-2); padding: 0 var(--crisp-space-2-5); border-bottom: 1px solid var(--crisp-border-subtle); color: var(--crisp-fg-neutral-muted); }
17
+ /* Composed from @seed-design/rootage's text-input.yaml
18
+ (variant=outline,size=medium) -- seed's Select has no search field of
19
+ its own to resolve this from (see the file header), so this reuses
20
+ the SAME tokens #867 already resolved for the trigger at this size:
21
+ minHeight x10 (var(--crisp-size-selectTriggerMd)), paddingX x3_5
22
+ (var(--crisp-space-3-5)), gap x2 (var(--crisp-space-2)), cornerRadius r2
23
+ (var(--crisp-radius-md)), strokeColor stroke.neutral-weak
24
+ (var(--crisp-stroke-select-trigger)) -- a real bordered field sitting flush
25
+ inside the listbox's own 8px padding, replacing the old bare
26
+ 34px/no-border/bleeds-to-the-edge strip (crisp/#904). */
27
+ .crisp-select-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-selectTriggerMd); flex-shrink: 0; padding: 0 var(--crisp-space-3-5); border: 1px solid var(--crisp-stroke-select-trigger); border-radius: var(--crisp-radius-md); color: var(--crisp-fg-neutral-muted); }
18
28
  .crisp-select-search svg { flex-shrink: 0; }
19
- .crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-select-neutral); }
29
+ .crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); line-height: 19px; color: var(--crisp-fg-select-neutral); }
20
30
  .crisp-select-search input::placeholder { color: var(--crisp-fg-select-placeholder); }
31
+ /* select.yaml's own divider slot (marginX x4, height 1px, colour
32
+ stroke.neutral-muted -- described upstream as "the line marking a
33
+ boundary between semantic units: between sections, between content
34
+ and an action area, between a header and a body" -- exactly the
35
+ search-field/option-list boundary crisp#904's review flagged as
36
+ reading too tight). Not the general-purpose separator #867 declined
37
+ to build (nothing groups options with one) -- scoped to this one
38
+ specific header/body seam, which now exists because searchable
39
+ does. Sits as an ordinary flex child, so the listbox's own 8px gap
40
+ still applies on both sides of it -- total visual seam is
41
+ gap+1px+gap (17px), deliberately more than the 8px between two
42
+ plain option rows, so it reads as a section break, not a wider list
43
+ gap. */
44
+ .crisp-select-divider { flex-shrink: 0; height: 1px; margin-inline: var(--crisp-space-4); background: var(--crisp-stroke-select-divider); }
21
45
  .crisp-select-empty { padding: var(--crisp-space-3) var(--crisp-space-4); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-neutral-subtle); }
22
46
  /* select.yaml's groupLabel -- font-size/line-height/weight are the same
23
47
  across sizes, only paddingY differs (medium 8px, large 10px). */
@@ -47,21 +71,27 @@
47
71
  .crisp-select {
48
72
  position: relative; display: inline-flex; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
49
73
  & .crisp-select-trigger { box-sizing: border-box; display: inline-flex; align-items: center; width: 100%; min-width: 0; margin: 0; border: 1px solid var(--crisp-stroke-select-trigger); background: transparent; cursor: pointer; font-family: inherit; color: var(--crisp-fg-select-neutral); transition: background-color .15s cubic-bezier(.35,0,.35,1), border-color .1s cubic-bezier(.35,0,.35,1), border-width .1s cubic-bezier(.35,0,.35,1); }
50
- /* seed defines no hover state for this trigger -- only pressed, invalid, disabled and readonly. The scale-down is scoped to the CONTENT (seed's scaleScope: content), not the button itself, so the border
51
- never moves. */
52
- /* Only the value scales, not the chevron: the chevron's own transform is its open/close rotation, and a scale would fight it for one shared CSS property when both are true at once (pressing while open). */
74
+ /* seed defines no hover state for this trigger -- only pressed, invalid,
75
+ disabled and readonly. The scale-down is scoped to the CONTENT
76
+ (seed's scaleScope: content), not the button itself, so the border
77
+ never moves. */ /* Only the value scales, not the chevron: the chevron's own transform is
78
+ its open/close rotation, and a scale would fight it for one shared
79
+ CSS property when both are true at once (pressing while open). */
53
80
  & .crisp-select-trigger:active:not(:disabled):not([aria-readonly="true"]) { background: var(--crisp-bg-select-pressed); }
54
81
  & .crisp-select-trigger:active:not(:disabled):not([aria-readonly="true"]) .crisp-select-value { transform: scale(0.98); }
55
82
  & .crisp-select-trigger:focus-visible { outline: 2px solid var(--crisp-stroke-focus-ring); outline-offset: -2px; }
56
83
  & .crisp-select-trigger:disabled { background: var(--crisp-bg-select-disabled); cursor: not-allowed; }
57
84
  & .crisp-select-trigger:disabled .crisp-select-value, & .crisp-select-trigger:disabled .crisp-select-placeholder, & .crisp-select-trigger:disabled .crisp-select-chevron { color: var(--crisp-fg-disabled); }
58
- /* readonly: same fill as disabled, but the value/placeholder text stays normal ink -- it reads as "answered and locked", not "answered and
85
+ /* readonly: same fill as disabled, but the value/placeholder text stays
86
+ normal ink -- it reads as "answered and locked", not "answered and
59
87
  greyed out" (select-trigger.yaml's readonly state only overrides
60
88
  root.color; value/placeholder keep their enabled colours). */
61
89
  & .crisp-select-trigger[aria-readonly="true"] { background: var(--crisp-bg-select-disabled); cursor: default; }
62
90
  & .crisp-select-value { flex: 1; min-width: 0; display: inline-flex; align-items: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: start; transition: transform .15s cubic-bezier(0,0,.15,1); }
63
91
  & .crisp-select-placeholder { color: var(--crisp-fg-select-placeholder); }
64
- /* closeRotateDuration/closeRotateTimingFunction: 100ms, seed's "easing" curve. Overridden to 150ms on open (openRotateDuration) below -- same curve both ways, only the duration differs. */
92
+ /* closeRotateDuration/closeRotateTimingFunction: 100ms, seed's "easing"
93
+ curve. Overridden to 150ms on open (openRotateDuration) below --
94
+ same curve both ways, only the duration differs. */
65
95
  & .crisp-select-chevron { flex-shrink: 0; color: var(--crisp-fg-neutral-muted); transition: transform .1s cubic-bezier(.35,0,.35,1); }
66
96
  & .crisp-select-trigger[data-open] .crisp-select-chevron { transform: rotate(180deg); transition-duration: .15s; }
67
97
  }
@@ -71,6 +101,16 @@
71
101
  .crisp-select--width_auto {
72
102
  width: auto;
73
103
  }
104
+ .crisp-select--size_small {
105
+ & .crisp-select-trigger { height: var(--crisp-size-menuRow); border-radius: var(--crisp-radius-md); gap: var(--crisp-space-1-5); padding-inline: var(--crisp-space-2-5); }
106
+ & .crisp-select-value, & .crisp-select-placeholder { font-size: var(--crisp-text-lg); line-height: 20px; }
107
+ & .crisp-select-chevron { width: var(--crisp-size-icon); height: var(--crisp-size-icon); }
108
+ .crisp-select-option { gap: var(--crisp-space-2); }
109
+ .crisp-select-option-label { font-size: var(--crisp-text-lg); line-height: 19px; }
110
+ .crisp-select-option-description { font-size: var(--crisp-text-sm); line-height: 16px; }
111
+ .crisp-select-option-check { width: var(--crisp-space-3); height: var(--crisp-space-3); }
112
+ .crisp-select-label { padding-top: var(--crisp-space-2); }
113
+ }
74
114
  .crisp-select--size_medium {
75
115
  & .crisp-select-trigger { height: var(--crisp-size-selectTriggerMd); border-radius: var(--crisp-radius-md); gap: var(--crisp-space-2); padding-inline: var(--crisp-space-3-5); }
76
116
  & .crisp-select-value, & .crisp-select-placeholder { font-size: var(--crisp-text-lg); line-height: 19px; }
@@ -5,14 +5,14 @@
5
5
  & .crisp-settingsshell-back svg { color: var(--crisp-fg-muted); }
6
6
  & .crisp-settingsshell-back:hover svg { color: var(--crisp-fg-primary); }
7
7
  & .crisp-settingsshell-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: 32px; margin-bottom: var(--crisp-space-2); padding: 0 var(--crisp-space-2-5); border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-border-default); color: var(--crisp-fg-muted); }
8
- /* The field box owns the ring, so focus has to move it -- the inner input kills its own outline. Measured live: a focused field's
8
+ /* The field box owns the ring, so focus has to move it -- the inner
9
+ input kills its own outline. Measured live: a focused field's
9
10
  input carries box-shadow: none while its wrapper carries
10
11
  inset 0 0 0 1px #266df0. */
11
12
  & .crisp-settingsshell-search:focus-within { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
12
13
  & .crisp-settingsshell-search svg { flex-shrink: 0; }
13
14
  & .crisp-settingsshell-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
14
15
  & .crisp-settingsshell-search input::placeholder { color: var(--crisp-fg-muted); }
15
-
16
16
  & .crisp-settingsshell-groups { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: var(--crisp-space-2-5); }
17
17
  & .crisp-settingsshell-group { display: flex; flex-direction: column; gap: 1px; }
18
18
  & .crisp-settingsshell-group-label { padding: var(--crisp-space-1) var(--crisp-space-2); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
@@ -23,7 +23,6 @@
23
23
  & .crisp-settingsshell-item[data-active] { background: var(--crisp-bg-raised); font-weight: var(--crisp-weight-medium); }
24
24
  & .crisp-settingsshell-item[data-active] svg { color: var(--crisp-fg-primary); }
25
25
  & .crisp-settingsshell-empty { padding: var(--crisp-space-3) var(--crisp-space-2); font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
26
-
27
26
  & .crisp-settingsshell-content { flex: 1; min-width: 0; min-height: 0; overflow-y: auto; padding: var(--crisp-space-6) var(--crisp-space-8); }
28
27
  [dir="rtl"] & [data-rtl-flip] { transform: scaleX(-1); }
29
28
  }