@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
@@ -1,7 +1,11 @@
1
1
  .crisp-datatable {
2
- display: flex; flex-direction: column; gap: var(--crisp-space-2-5); font-family: var(--crisp-font-sans); /* The toolbar carried no horizontal inset of its own, so its content (search box, sort/filter chips) sat flush at the table's outer edge
3
- (x=0) while the header row's own th/td padding (table.recipe.ts, #465) starts every column's text at 12px -- one row down, the SAME
4
- grid's own header cell already begins at that inset. c.space["3"] here just matches the row directly below it, measured live against Attio (the sort/filter row's search chip lines up with the first
2
+ display: flex; flex-direction: column; gap: var(--crisp-space-2-5); font-family: var(--crisp-font-sans); /* The toolbar carried no horizontal inset of its own, so its content
3
+ (search box, sort/filter chips) sat flush at the table's outer edge
4
+ (x=0) while the header row's own th/td padding (table.recipe.ts,
5
+ #465) starts every column's text at 12px -- one row down, the SAME
6
+ grid's own header cell already begins at that inset. c.space["3"]
7
+ here just matches the row directly below it, measured live against
8
+ Attio (the sort/filter row's search chip lines up with the first
5
9
  column header's text, not the grid's raw edge). */
6
10
  & .crisp-datatable-toolbar { display: flex; align-items: center; gap: var(--crisp-space-2); min-height: 49px; border-top: 1px solid var(--crisp-border-subtle); padding: 0 var(--crisp-space-3); }
7
11
  & .crisp-datatable-search { position: relative; flex: 1; max-width: 280px; display: inline-flex; align-items: center; }
@@ -11,10 +15,7 @@
11
15
  & .crisp-datatable-search input:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
12
16
  & .crisp-datatable-count { margin-inline-start: auto; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
13
17
  /* announced, never drawn */
14
- & .crisp-datatable-live {
15
- position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
16
- overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
17
- }
18
+ & .crisp-datatable-live { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
18
19
  /* crisp/#645: visually-hidden-but-focusable, not visually-hidden-and-
19
20
  inert like .crisp-datatable-live above -- same clip-rect shape,
20
21
  this one just needs to actually hold DOM focus so a native
@@ -22,7 +23,8 @@
22
23
  in datatable.tsx). resize: none keeps a stray native textarea handle
23
24
  from ever being drawable, even though it's clipped to 1px anyway. */
24
25
  & .crisp-datatable-clipboard-proxy { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; resize: none; }
25
- /* single active cell (crisp/#645 follow-up -- this had no styling of its own at all before, a gap against Golden Rule 0: RecordsTable's own
26
+ /* single active cell (crisp/#645 follow-up -- this had no styling of its
27
+ own at all before, a gap against Golden Rule 0: RecordsTable's own
26
28
  measured value, .crisp-recordstable-td[data-selected], brought
27
29
  across unchanged now that a visible anchor actually matters for the
28
30
  Shift+Click range below). */
@@ -31,57 +33,85 @@
31
33
  tint formula already used twice below (tbody tr[data-selected] td)
32
34
  for the same reason a selected group of rows gets one: a selected
33
35
  GROUP of cells is the same kind of state, just cell-scoped instead of
34
- row-scoped. Not independently re-measured against Attio's own range highlight (out of scope this slice -- flagged on crisp#645). */
36
+ row-scoped. Not independently re-measured against Attio's own range
37
+ highlight (out of scope this slice -- flagged on crisp#645). */
35
38
  & td[data-in-range] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 10%, var(--crisp-bg-surface)); }
36
- /* The header cell has no padding of its own -- the button owns the full cell so the whole header is clickable (its own inset is 12px). Mirrors the summary-row fix. `& .crisp-table th`, not bare `& th` (found while re-checking #691's
39
+ /* The header cell has no padding of its own -- the button owns the
40
+ full cell so the whole header is clickable (its own inset is 12px).
41
+ Mirrors the summary-row fix.
42
+ `& .crisp-table th`, not bare `& th` (found while re-checking #691's
37
43
  own fix live): DataTable's root nests `Table`'s own wrapper, whose
38
44
  `table.recipe.ts` carries `& th, & td { padding: 0 12px }` at the
39
45
  SAME specificity (.crisp-table th vs .crisp-datatable th, both one
40
46
  class + one element) -- a bare `& th` here only won by source
41
- order, which flipped the moment table.recipe.ts's own CSS file happened to land after datatable's in the build (alphabetical:
47
+ order, which flipped the moment table.recipe.ts's own CSS file
48
+ happened to land after datatable's in the build (alphabetical:
42
49
  datatable < table), silently reinstating 12px on every header cell
43
- in the whole product and making every interactive column's button double it to 24px. Scoping through `.crisp-table` adds a second class to the selector (0,2,1 beats 0,1,1) so this can never lose a specificity tie to source order again. `thead th`, not a bare `th` (crisp#829): #779 made the primary column's BODY cell a real `<th scope="row">` for a11y, and a bare
50
+ in the whole product and making every interactive column's button
51
+ double it to 24px. Scoping through `.crisp-table` adds a second
52
+ class to the selector (0,2,1 beats 0,1,1) so this can never lose a
53
+ specificity tie to source order again.
54
+ `thead th`, not a bare `th` (crisp#829): #779 made the primary
55
+ column's BODY cell a real `<th scope="row">` for a11y, and a bare
44
56
  `th` here matches that one too, zeroing an inset nothing else
45
57
  supplies -- the primary column's text sat flush left, one column's
46
58
  cell no longer matching its own header or any sibling `<td>`. Only
47
- the header row's own `<th>` needs zero padding (its sort BUTTON owns the inset); the body row's `<th scope="row">` has no button,
59
+ the header row's own `<th>` needs zero padding (its sort BUTTON
60
+ owns the inset); the body row's `<th scope="row">` has no button,
48
61
  and needs the SAME base 12px (table.recipe.ts, #465) every other
49
62
  cell already gets. */
50
63
  & .crisp-table thead th { padding: 0; }
51
- /* Same wrapper trap as AUTHORING.md Lesson 40 (ColumnCalc's summary trigger): Menu wraps its trigger in a flex div that sizes to its content, so a long header grew past the column instead of filling it -- with nothing left to squeeze, the label's own ellipsis CSS (below) had no properly
52
- -sized box to truncate against, and the th's own overflow hard-clipped it with no "...". Fill the wrapper, scoped to th so Menu's default
64
+ /* Same wrapper trap as AUTHORING.md Lesson 40 (ColumnCalc's summary trigger):
65
+ Menu wraps its trigger in a flex div that sizes to its content, so a
66
+ long header grew past the column instead of filling it -- with nothing
67
+ left to squeeze, the label's own ellipsis CSS (below) had no properly
68
+ -sized box to truncate against, and the th's own overflow hard-clipped
69
+ it with no "...". Fill the wrapper, scoped to th so Menu's default
53
70
  (correct everywhere else) is untouched. */
54
71
  & th .crisp-menu { width: 100%; height: 100%; }
55
72
  & .crisp-datatable-th-inner { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); width: 100%; min-width: 0; height: 100%; }
56
73
  & .crisp-datatable-th-inner > svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
57
74
  /* crisp/#605 follow-up: a header with neither a Menu nor a sort button
58
- (the primary/entity column's now-inert path, or any column with no columnMenu/sortable at all) renders .crisp-datatable-th-inner as a DIRECT child of th instead of nested inside a button -- and loses the button's own 12px inset, drifting left of the td's 12px base inset. Measured live on Attio's own Companies grid: the header label
59
- and the cell's own text land at the exact same x (335px from the viewport, both 40px from the column's left edge) via two different
75
+ (the primary/entity column's now-inert path, or any column with no
76
+ columnMenu/sortable at all) renders .crisp-datatable-th-inner as a
77
+ DIRECT child of th instead of nested inside a button -- and loses
78
+ the button's own 12px inset, drifting left of the td's 12px base
79
+ inset. Measured live on Attio's own Companies grid: the header label
80
+ and the cell's own text land at the exact same x (335px from the
81
+ viewport, both 40px from the column's left edge) via two different
60
82
  padding+icon+gap combinations -- Attio does not leave the inert
61
83
  primary header flush left either. The `>` combinator targets only
62
- the button-less case: Menu's own wrapper (`.crisp-menu`) and the plain sort `button` both put >=1 more level between `th` and this span, so their own 12px (already on the button) isn't doubled. */
84
+ the button-less case: Menu's own wrapper (`.crisp-menu`) and the
85
+ plain sort `button` both put >=1 more level between `th` and this
86
+ span, so their own 12px (already on the button) isn't doubled. */
63
87
  & th > .crisp-datatable-th-inner { box-sizing: border-box; padding: 0 var(--crisp-space-3); }
64
- /* The summary cell has NO padding of its own -- the calculation trigger
88
+ /* The summary cell has NO padding of its own -- the calculation trigger
65
89
  owns the whole 246x37 area so a click anywhere in the cell opens the
66
90
  menu. Zero the cell's inset and let ColumnCalc supply the 12px. */
67
91
  & tfoot td { padding: 0; }
68
- /* Group heading row -- a view is grouped under a subtle label with the bucket's count beside it. */
69
- & .crisp-datatable-viewsettings { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; color: var(--crisp-fg-muted); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s; }
92
+ /* Group heading row -- a view is grouped under a subtle label with the
93
+ bucket's count beside it. */
94
+ & .crisp-datatable-viewsettings { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; color: var(--crisp-fg-muted); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s; }
70
95
  & .crisp-datatable-viewsettings:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); color: var(--crisp-fg-primary); }
71
96
  & .crisp-datatable-group-label { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-1); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
72
- & .crisp-datatable-group { height: var(--crisp-size-menuRow); padding: 0 var(--crisp-space-3); background: var(--crisp-bg-subtle); border-bottom: 1px solid var(--crisp-border-subtle); font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
97
+ & .crisp-datatable-group { height: var(--crisp-size-menuRow); padding: 0 var(--crisp-space-3); background: var(--crisp-bg-subtle); border-bottom: 1px solid var(--crisp-border-subtle); font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
73
98
  & .crisp-datatable-group-count { margin-inline-start: var(--crisp-space-1-5); color: var(--crisp-fg-muted); font-variant-numeric: tabular-nums; }
74
99
  & .crisp-datatable-th-rename { width: 100%; min-width: 0; height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-1); border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); outline: none; }
75
100
  & .crisp-datatable-th-rename:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
76
101
  & .crisp-datatable-th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
77
- /* #465: 12px per the comment above (and Attio's measured header cell padding: 0 12px) -- was still c.space["2"] (8px), drifted from its own documented value. */
102
+ /* #465: 12px per the comment above (and Attio's measured header cell
103
+ padding: 0 12px) -- was still c.space["2"] (8px), drifted from its
104
+ own documented value. */
78
105
  & .crisp-datatable-sort { display: flex; align-items: center; gap: var(--crisp-space-1-5); width: 100%; min-width: 0; height: 100%; margin: 0; padding: 0 var(--crisp-space-3); border: none; background: none; font: inherit; letter-spacing: inherit; color: inherit; text-align: start; cursor: pointer; }
79
106
  /* A right-aligned column's header keeps its field-icon + label packed at
80
107
  the START, matching its own values only in that the VALUES right-align
81
108
  -- Attio's own right-aligned header (measured live: "Twitter follower
82
- count") keeps the icon+label left and only the trailing column-menu icon sits pinned to the right edge, independent of the label's width
83
- (#406, reversing #393's own justify-content: flex-end here). The chevron's own margin-inline-start: auto below already pins IT to the
84
- end of a flex-start row with no override needed -- that's what pins the trailing icon on Attio too. */
109
+ count") keeps the icon+label left and only the trailing column-menu
110
+ icon sits pinned to the right edge, independent of the label's width
111
+ (#406, reversing #393's own justify-content: flex-end here). The
112
+ chevron's own margin-inline-start: auto below already pins IT to the
113
+ end of a flex-start row with no override needed -- that's what pins
114
+ the trailing icon on Attio too. */
85
115
  & .crisp-datatable-chevron { margin-inline-start: auto; flex-shrink: 0; color: var(--crisp-fg-muted); opacity: 0; transition: opacity .12s; }
86
116
  & .crisp-datatable-sort:hover .crisp-datatable-chevron { opacity: 0.6; }
87
117
  & .crisp-datatable-sort[data-sorted] .crisp-datatable-chevron { opacity: 1; color: var(--crisp-fg-primary); }
@@ -89,17 +119,23 @@
89
119
  & th[data-sticky], & td[data-sticky] { position: sticky; z-index: 1; background: var(--crisp-bg-surface); }
90
120
  /* `thead th[data-sticky]`, not a bare `th[data-sticky]` (crisp#848, same
91
121
  bare-`th` family as #829/#833/#835): this z-index:3 was written for
92
- the HEADER's own sticky corner cell (sticky column x sticky header), meant to win over everything else. Unscoped, it also matched the primary column's BODY cell -- a real `<th scope="row" data-sticky>`
93
- since #779 -- giving every scrolled body row's own sticky cell a HIGHER z-index than the sticky FOOTER's (2), so it painted over the
122
+ the HEADER's own sticky corner cell (sticky column x sticky header),
123
+ meant to win over everything else. Unscoped, it also matched the
124
+ primary column's BODY cell -- a real `<th scope="row" data-sticky>`
125
+ since #779 -- giving every scrolled body row's own sticky cell a
126
+ HIGHER z-index than the sticky FOOTER's (2), so it painted over the
94
127
  footer instead of the footer showing through. Confirmed live on a
95
- real bounded-height, 25-row table (GRC's Risk register): scrolled partway, `elementFromPoint` at the footer's own on-screen cell
128
+ real bounded-height, 25-row table (GRC's Risk register): scrolled
129
+ partway, `elementFromPoint` at the footer's own on-screen cell
96
130
  resolved to a body row's `<th>`, not the footer's `<td>`, and that
97
131
  `<th>`'s computed z-index read 3. Scoped to `thead`, a body row's
98
132
  own sticky `<th>` now falls back to the base rule above (z-index 1,
99
- correct -- the same as a plain sticky `<td>`), and the footer's own explicit z-index below is unaffected either way. */
133
+ correct -- the same as a plain sticky `<td>`), and the footer's own
134
+ explicit z-index below is unaffected either way. */
100
135
  & thead th[data-sticky] { z-index: 3; }
101
136
  /* #554: a footer sticky-column cell sits in the bottom-sticky row (table.recipe.ts's
102
- `tfoot td { z-index: 2 }`), which `td[data-sticky]`'s own higher-specificity `z-index: 1` would otherwise undercut -- keep it level with the row it's in. */
137
+ `tfoot td { z-index: 2 }`), which `td[data-sticky]`'s own higher-specificity
138
+ `z-index: 1` would otherwise undercut -- keep it level with the row it's in. */
103
139
  & tfoot td[data-sticky] { z-index: 2; }
104
140
  & tbody tr[data-selected] td[data-sticky] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 10%, var(--crisp-bg-surface)); }
105
141
  & tbody tr:hover td[data-sticky] { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); }
@@ -119,7 +155,8 @@
119
155
  /* crisp/#758: AI-enriched column marker, ported from RecordsTable's own
120
156
  already-measured value -- a full-bleed #9b69ff (bgPurple) wash at 4%,
121
157
  composited OVER whatever row-state background the cell already has
122
- (hover, selected), which is why it's an ::after overlay and not a plain background. */
158
+ (hover, selected), which is why it's an ::after overlay and not a
159
+ plain background. */
123
160
  & td[data-enriched]::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: color-mix(in srgb, var(--crisp-bg-purple) 4%, transparent); }
124
161
  & .crisp-datatable-edit { width: 100%; height: 28px; margin: 0; padding: 0 var(--crisp-space-1-5); border: none; border-radius: var(--crisp-radius-sm); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); outline: none; vertical-align: middle; }
125
162
  & .crisp-datatable-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
@@ -130,40 +167,56 @@
130
167
  & .crisp-datatable-edit:disabled { opacity: 0.5; cursor: not-allowed; }
131
168
  & .crisp-datatable-edit-pending { flex-shrink: 0; margin-inline-start: var(--crisp-space-1); color: var(--crisp-fg-muted); vertical-align: middle; }
132
169
  /* The rejection's message, beside the cell's own content -- a sibling in
133
- the TableCell, never nested inside a column's own render output, so a hover-only wrapper (a Tooltip, say) around a custom render can't hide
170
+ the TableCell, never nested inside a column's own render output, so a
171
+ hover-only wrapper (a Tooltip, say) around a custom render can't hide
134
172
  it. Block-level: the row grows to fit it rather than floating over
135
173
  the row below, so it can never end up clipped by the scroll
136
- container's overflow the way a position:fixed escape would need guarding against. */
174
+ container's overflow the way a position:fixed escape would need
175
+ guarding against. */
137
176
  & .crisp-datatable-edit-error { display: block; padding: var(--crisp-space-0-5) 0 0; font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
138
- /* editor: "select"/"switch" -- always live, no separate edit mode, so the cell IS the picker: same chromeless-fill treatment as RecordsTable's own --picker cells (measured there already; DataTable
177
+ /* editor: "select"/"switch" -- always live, no separate edit mode, so
178
+ the cell IS the picker: same chromeless-fill treatment as
179
+ RecordsTable's own --picker cells (measured there already; DataTable
139
180
  shares RecordsTable's grid, Golden Rule 0). */
140
181
  & .crisp-datatable-td--picker { padding: 0; }
141
182
  & .crisp-datatable-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); }
142
183
  & .crisp-datatable-edit-picker .crisp-select-trigger { flex: 1; min-width: 0; height: 100%; min-height: 0; border-radius: 0; box-shadow: none; padding: 0; }
143
184
  & .crisp-datatable-td--picker .crisp-datatable-edit-error { padding-inline-start: var(--crisp-space-2); }
144
- /* reference picker: a leading 16px avatar per option, plus a trailing "Create X" row when the consumer supplies one (#449) -- same measured values as RecordsTable's own .crisp-recordstable-refoption*. */
185
+ /* reference picker: a leading 16px avatar per option, plus a trailing
186
+ "Create X" row when the consumer supplies one (#449) -- same measured
187
+ values as RecordsTable's own .crisp-recordstable-refoption*. */
145
188
  & .crisp-datatable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
146
189
  & .crisp-datatable-refoption-avatar { flex-shrink: 0; }
147
190
  & .crisp-datatable-refoption--create { color: var(--crisp-fg-muted); }
148
191
  & .crisp-datatable-empty { padding: var(--crisp-space-8) var(--crisp-space-3); text-align: center; color: var(--crisp-fg-muted); font-size: var(--crisp-text-lg); }
149
192
  /* #826 -- the full-body loading state (a filter/sort re-query, or a
150
- fresh page boot), measured live on Attio's Companies grid on both triggers: icon+text centred in the row-body area, 10px gap, 14px/500 weight/20px line-height, both icon and text in the SAME muted rgba(0,0,0,0.63) -- the same color-mix figure this file already uses for other muted text (e.g. -phone-dial). Distinct from the cold in-place row load (blank, no indicator) and the warm-navigation per-cell shimmer (#599) -- neither of those swaps the whole body. */
193
+ fresh page boot), measured live on Attio's Companies grid on both
194
+ triggers: icon+text centred in the row-body area, 10px gap, 14px/500
195
+ weight/20px line-height, both icon and text in the SAME muted
196
+ rgba(0,0,0,0.63) -- the same color-mix figure this file already uses
197
+ for other muted text (e.g. -phone-dial). Distinct from the cold
198
+ in-place row load (blank, no indicator) and the warm-navigation
199
+ per-cell shimmer (#599) -- neither of those swaps the whole body. */
151
200
  & .crisp-datatable-loading { display: flex; align-items: center; justify-content: center; gap: 10px; padding: var(--crisp-space-8) var(--crisp-space-3); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); line-height: 20px; }
152
201
  & .crisp-datatable-loading .crisp-spinner { border-top-color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
153
- /* #579: click-to-expand overlay for a truncated cell -- a read-only, full-value card, settled live as click (not Attio's usual
154
- hover-expand) and measured position: absolute, unlike this file's floating chrome (Menu/Select popovers) which portals and escapes the scroll container. Deliberately NOT the edit-error pattern above (grow the row, block-level, never clipped): a virtualized grid assumes a fixed row height for its scroll math (owned by the grid core, not this cell), so growing a row here would fight it. Anchored to the SAME column width the cell itself renders at (measured: Attio's own overlay came out only slightly wider than the
155
- triggering cell's clientWidth -- the overshoot is this padding), wrapping onto as many lines as the value needs; it CAN be clipped by `.crisp-table-scroll`'s own `overflow: auto` if it grows past the
202
+ /* #579: click-to-expand overlay for a truncated cell -- a read-only,
203
+ full-value card, settled live as click (not Attio's usual
204
+ hover-expand) and measured position: absolute, unlike this file's
205
+ floating chrome (Menu/Select popovers) which portals and escapes the
206
+ scroll container. Deliberately NOT the edit-error pattern above
207
+ (grow the row, block-level, never clipped): a virtualized grid
208
+ assumes a fixed row height for its scroll math (owned by the grid
209
+ core, not this cell), so growing a row here would fight it. Anchored
210
+ to the SAME column width the cell itself renders at (measured:
211
+ Attio's own overlay came out only slightly wider than the
212
+ triggering cell's clientWidth -- the overshoot is this padding),
213
+ wrapping onto as many lines as the value needs; it CAN be clipped by
214
+ `.crisp-table-scroll`'s own `overflow: auto` if it grows past the
156
215
  visible viewport, same as the edit-error comment above already
157
216
  notes for any position:absolute escape -- unmeasured against Attio
158
217
  for this exact case, flagged rather than guessed. */
159
218
  & td[data-cell-expanded] { overflow: visible; z-index: 7; }
160
- & .crisp-datatable-cell-overlay {
161
- position: absolute; inset-inline-start: 0; top: 0; width: 100%; box-sizing: border-box;
162
- padding: var(--crisp-space-2) var(--crisp-space-3); background: var(--crisp-bg-surface);
163
- border: 1px solid var(--crisp-bg-brand-solid); border-radius: 4px;
164
- font-family: var(--crisp-font-sans); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium);
165
- color: var(--crisp-fg-primary); white-space: normal; word-break: break-word; cursor: default;
166
- }
219
+ & .crisp-datatable-cell-overlay { position: absolute; inset-inline-start: 0; top: 0; width: 100%; box-sizing: border-box; padding: var(--crisp-space-2) var(--crisp-space-3); background: var(--crisp-bg-surface); border: 1px solid var(--crisp-bg-brand-solid); border-radius: 4px; font-family: var(--crisp-font-sans); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); white-space: normal; word-break: break-word; cursor: default; }
167
220
  /* fixed layout so column widths (and resize) are exact — like RecordsTable */
168
221
  & table { table-layout: fixed; }
169
222
  /* read-only/computed column marker (#596) -- sits just inside the
@@ -175,42 +228,70 @@
175
228
  & .crisp-datatable-resize { position: absolute; top: 0; inset-inline-end: -3px; width: 9px; height: 100%; cursor: col-resize; z-index: 6; touch-action: none; }
176
229
  & .crisp-datatable-resize::after { content: ""; position: absolute; top: 0; inset-inline-start: 3px; width: 2px; height: 100%; background: var(--crisp-bg-brand-solid); opacity: 0; transition: opacity .12s; }
177
230
  & .crisp-datatable-resize:hover::after, & .crisp-datatable-resize[data-resizing]::after { opacity: 1; }
178
- /* crisp/#731 -- column drag-to-reorder. Measured live against Attio's own grid (the issue's own comment): the dragged header keeps full
231
+ /* crisp/#731 -- column drag-to-reorder. Measured live against Attio's
232
+ own grid (the issue's own comment): the dragged header keeps full
179
233
  opacity and the plain `pointer` cursor throughout (Attio draws no
180
234
  ghost and no "grabbing" cursor of its own), so this adds nothing to
181
235
  `[data-dragging]` itself -- the ONLY new paint is the drop-indicator
182
- line, a 3px bar in the same measured brand blue the resize handle's own hover state (above) already uses, positioned on whichever edge of the hovered header the pointer is closer to. */
236
+ line, a 3px bar in the same measured brand blue the resize handle's
237
+ own hover state (above) already uses, positioned on whichever edge of
238
+ the hovered header the pointer is closer to. */
183
239
  & th[data-dragging] { cursor: pointer; }
184
240
  & th[data-drop-before]::before, & th[data-drop-after]::after { content: ""; position: absolute; top: 0; width: 3px; height: 100%; background: var(--crisp-bg-brand-solid); z-index: 6; pointer-events: none; }
185
241
  & th[data-drop-before]::before { inset-inline-start: -1.5px; }
186
242
  & th[data-drop-after]::after { inset-inline-end: -1.5px; }
187
243
  /* typed cells — entity (avatar + name), colour-coded tags, numbers, dates */
188
244
  & .crisp-datatable-entity { display: flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; color: var(--crisp-fg-primary); font-weight: var(--crisp-weight-medium); }
189
- /* crisp/#601 supersession follow-up -- the same flex-row shape .crisp-datatable-entity gives its own avatar+name+actions, but structural only (no entity-specific colour/weight): lets onOpenComments/onOpenPreview compose alongside ANY column's own
245
+ /* crisp/#601 supersession follow-up -- the same flex-row shape
246
+ .crisp-datatable-entity gives its own avatar+name+actions, but
247
+ structural only (no entity-specific colour/weight): lets
248
+ onOpenComments/onOpenPreview compose alongside ANY column's own
190
249
  content (a custom render, or a non-entity built-in type), not just
191
250
  type: "entity"'s own inline rendering. */
192
251
  & .crisp-datatable-cell-actions-row { display: flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; width: 100%; }
193
- /* crisp/#601, G-050: measured LIVE (getComputedStyle on the name text, plain hover vs rest) that Attio's underline is unconditional, not a
252
+ /* crisp/#601, G-050: measured LIVE (getComputedStyle on the name text,
253
+ plain hover vs rest) that Attio's underline is unconditional, not a
194
254
  hover reveal -- identical at rest and on hover: text-decoration-color
195
- is rgba(0,0,0,0.09), a 9% tint, not the name's own full-contrast text colour. The previous :hover-gated, full-contrast rule here was itself unmeasured and wrong in two ways at once. */ /* crisp#851 -- Attio's own entity/record names are measured at
196
- font-weight 500, distinct from a plain-text primary column's 400 (table.recipe.ts's own `tbody th` default). This was never its own
255
+ is rgba(0,0,0,0.09), a 9% tint, not the name's own full-contrast text
256
+ colour. The previous :hover-gated, full-contrast rule here was itself
257
+ unmeasured and wrong in two ways at once. */ /* crisp#851 -- Attio's own entity/record names are measured at
258
+ font-weight 500, distinct from a plain-text primary column's 400
259
+ (table.recipe.ts's own `tbody th` default). This was never its own
197
260
  explicit style -- it silently rode on a since-fixed header-rule leak
198
261
  (#833/#835/#848) that happened to apply the same 500 to every
199
262
  primary-column body cell regardless of type. Made explicit here so
200
263
  fixing that leak doesn't also (wrongly) drop entity names to 400. */
201
264
  & .crisp-datatable-entity-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: var(--crisp-weight-medium); text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--crisp-fg-primary) 9%, transparent); }
202
- & button.crisp-datatable-entity-name--link { margin: 0; padding: 0; border: none; background: none; font: inherit; color: inherit; letter-spacing: inherit; text-align: start; cursor: pointer; max-width: 100%; }
203
- /* crisp/#601, G-048: two 20px ghost icons, right-aligned in the primary column, revealed on ROW hover (the issue's own title says "row
265
+ /* #893: shared by the button (onEntityClick, a different record) and
266
+ the anchor (href, the row's own record) -- was button-only, which
267
+ silently left a real <a> unstyled the day #893 added one. */
268
+ & .crisp-datatable-entity-name--link { margin: 0; padding: 0; border: none; background: none; font: inherit; color: inherit; letter-spacing: inherit; text-align: start; cursor: pointer; max-width: 100%; }
269
+ /* crisp/#601, G-048: two 20px ghost icons, right-aligned in the primary
270
+ column, revealed on ROW hover (the issue's own title says "row
204
271
  hover", and a live check confirmed hovering well past the name --
205
- not just the icons' own hit target -- still reveals them) or keyboard focus. Measured live: border-radius 6px, icon colour rgba(0,0,0,0.55) at rest, darkening to the full text colour with a rgba(0,0,0,0.04) background on the icon's OWN hover -- both
272
+ not just the icons' own hit target -- still reveals them) or
273
+ keyboard focus. Measured live: border-radius 6px, icon colour
274
+ rgba(0,0,0,0.55) at rest, darkening to the full text colour with a
275
+ rgba(0,0,0,0.04) background on the icon's OWN hover -- both
206
276
  expressed as color-mix against fgPrimary so they stay correct in
207
277
  dark mode instead of a literal black that would invert. */
208
278
  & .crisp-datatable-entity-actions { display: flex; align-items: center; gap: var(--crisp-space-1-5); margin-inline-start: auto; flex-shrink: 0; opacity: 0; }
209
279
  & tr:hover .crisp-datatable-entity-actions, & .crisp-datatable-entity-actions:focus-within { opacity: 1; }
210
280
  & .crisp-datatable-entity-action { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; font-family: inherit; color: color-mix(in srgb, var(--crisp-fg-primary) 55%, transparent); cursor: pointer; flex-shrink: 0; }
211
281
  & .crisp-datatable-entity-action:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); color: var(--crisp-fg-primary); }
212
- & .crisp-datatable-avatar { width: var(--crisp-size-icon); height: var(--crisp-size-icon); border-radius: var(--crisp-radius-sm); flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; line-height: 1; font-weight: var(--crisp-weight-semibold); text-transform: uppercase; color: var(--crisp-fg-on-brand); background: var(--crisp-bg-brand-solid); }
213
- & .crisp-datatable-avatar[data-tone="success"] { background: var(--crisp-bg-success); } & .crisp-datatable-avatar[data-tone="warning"] { background: var(--crisp-bg-warning); } & .crisp-datatable-avatar[data-tone="danger"] { background: var(--crisp-bg-danger); } & .crisp-datatable-avatar[data-tone="purple"] { background: var(--crisp-bg-purple); } & .crisp-datatable-avatar[data-tone="cyan"] { background: var(--crisp-bg-cyan); } & .crisp-datatable-avatar[data-tone="orange"] { background: var(--crisp-bg-orange); }
282
+ /* #892: the default shape's radius was a stray literal (radius.sm, 6px)
283
+ -- Attio's own real company/object avatar measures 30%, which is
284
+ Avatar's own already-shipped shape="rounded" value, not a new number.
285
+ shape="circle" reuses Avatar's own shape="circle" value (radius.full)
286
+ the same way, measured live on a real Attio person avatar. */
287
+ & .crisp-datatable-avatar { width: var(--crisp-size-icon); height: var(--crisp-size-icon); border-radius: 30%; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; line-height: 1; font-weight: var(--crisp-weight-semibold); text-transform: uppercase; color: var(--crisp-fg-on-brand); background: var(--crisp-bg-brand-solid); }
288
+ & .crisp-datatable-avatar[data-shape="circle"] { border-radius: var(--crisp-radius-full); }
289
+ & .crisp-datatable-avatar[data-tone="success"] { background: var(--crisp-bg-success); }
290
+ & .crisp-datatable-avatar[data-tone="warning"] { background: var(--crisp-bg-warning); }
291
+ & .crisp-datatable-avatar[data-tone="danger"] { background: var(--crisp-bg-danger); }
292
+ & .crisp-datatable-avatar[data-tone="purple"] { background: var(--crisp-bg-purple); }
293
+ & .crisp-datatable-avatar[data-tone="cyan"] { background: var(--crisp-bg-cyan); }
294
+ & .crisp-datatable-avatar[data-tone="orange"] { background: var(--crisp-bg-orange); }
214
295
  & .crisp-datatable-avatar img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }
215
296
  & .crisp-datatable-tags { display: flex; align-items: center; gap: var(--crisp-space-1); overflow: hidden; }
216
297
  & .crisp-datatable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); }
@@ -223,13 +304,19 @@
223
304
  & .crisp-datatable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); }
224
305
  & .crisp-datatable-num { font-variant-numeric: tabular-nums; }
225
306
  & .crisp-datatable-muted { color: var(--crisp-fg-muted); }
226
- /* crisp#822 -- a date/datetime cell's danger/overdue tone: same token as TasksTable's own overdue due-date (crisp#462), plain text colour, no
307
+ /* crisp#822 -- a date/datetime cell's danger/overdue tone: same token as
308
+ TasksTable's own overdue due-date (crisp#462), plain text colour, no
227
309
  fill/weight change. */
228
310
  & .crisp-datatable-danger { color: var(--crisp-fg-danger); }
229
- /* url/email cell types (#654) -- same measured values as RecordsTable's own .crisp-recordstable-link, which this mirrors: no underline at rest, underline on hover, own-colour text rather than a browser-blue link. */
311
+ /* url/email cell types (#654) -- same measured values as RecordsTable's
312
+ own .crisp-recordstable-link, which this mirrors: no underline at
313
+ rest, underline on hover, own-colour text rather than a browser-blue
314
+ link. */
230
315
  & .crisp-datatable-link { color: var(--crisp-fg-primary); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
231
316
  & .crisp-datatable-link:hover { text-decoration: underline; }
232
- /* phone cell type/editor (#765) -- measured live: the dial-code prefix is a muted rgba(0,0,0,0.63) at 14px, matching every other muted-text value already measured elsewhere in this file. */
317
+ /* phone cell type/editor (#765) -- measured live: the dial-code prefix
318
+ is a muted rgba(0,0,0,0.63) at 14px, matching every other muted-text
319
+ value already measured elsewhere in this file. */
233
320
  & .crisp-datatable-phone { display: inline-flex; align-items: center; gap: var(--crisp-space-1); }
234
321
  & .crisp-datatable-phone-dial { color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
235
322
  & .crisp-datatable-phone-editor { display: flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); }
@@ -259,7 +346,8 @@
259
346
  value rows (32px = size.menuRow, 5px 8px padding, 8px gap between
260
347
  the grip/value/actions, 16px icons) above one ALWAYS-blank trailing
261
348
  DataPhoneEditor-shaped row -- that blank row is the only "add
262
- another" affordance, there's no separate button for it. The copy/delete pair reuses .crisp-datatable-entity-action's own
349
+ another" affordance, there's no separate button for it. The
350
+ copy/delete pair reuses .crisp-datatable-entity-action's own
263
351
  hover-reveal chrome (not independently re-measured as its own hit
264
352
  target this pass, only the 16px icon glyphs were). */
265
353
  & .crisp-datatable-phone-multi-editor { display: flex; flex-direction: column; }
@@ -267,8 +355,7 @@
267
355
  & .crisp-datatable-phone-multi-row .crisp-datatable-phone-link { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
268
356
  & .crisp-datatable-phone-multi-grip { color: var(--crisp-fg-muted); flex-shrink: 0; cursor: grab; }
269
357
  & .crisp-datatable-phone-multi-actions { display: flex; align-items: center; gap: var(--crisp-space-1); margin-inline-start: auto; flex-shrink: 0; opacity: 0; }
270
- & .crisp-datatable-phone-multi-row:hover .crisp-datatable-phone-multi-actions,
271
- & .crisp-datatable-phone-multi-actions:focus-within { opacity: 1; }
358
+ & .crisp-datatable-phone-multi-row:hover .crisp-datatable-phone-multi-actions, & .crisp-datatable-phone-multi-actions:focus-within { opacity: 1; }
272
359
  & .crisp-datatable-phone-multi-action { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; font-family: inherit; color: color-mix(in srgb, var(--crisp-fg-primary) 55%, transparent); cursor: pointer; flex-shrink: 0; }
273
360
  & .crisp-datatable-phone-multi-action:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); color: var(--crisp-fg-primary); }
274
361
  /* datetime cell editor (#762) -- DatePickerField + TimePicker side by side. */
@@ -277,7 +364,10 @@
277
364
  18px pitch (a 2px gap), an empty star at rgba(0,0,0,0.1), a
278
365
  committed/filled star at brand600 (--crisp-bg-brand-solid, an exact
279
366
  match to the measured #266df0), and a distinct hover-preview colour
280
- -- rgb(33,91,196) -- that's close to but NOT brand700/bgBrandSolidPressed (#1f5fd6); kept as its own literal rather than forced onto that token, since the two were measured stable and different. The read-only svg and the editable button's own inner svg both carry the
367
+ -- rgb(33,91,196) -- that's close to but NOT brand700/bgBrandSolidPressed
368
+ (#1f5fd6); kept as its own literal rather than forced onto that token,
369
+ since the two were measured stable and different. The read-only svg
370
+ and the editable button's own inner svg both carry the
281
371
  crisp-datatable-rating-star class on the svg itself (not the
282
372
  button), so one set of fill rules covers both -- the button only
283
373
  adds its own reset + cursor via a separate -btn class. */
@@ -288,9 +378,13 @@
288
378
  & .crisp-datatable-rating-star[data-hovering] path { fill: #215bc4; }
289
379
  & .crisp-datatable-rating-star-btn { display: inline-flex; padding: 0; margin: 0; border: none; background: none; font-family: inherit; cursor: pointer; }
290
380
  /* row drag-to-reorder -- a Settings > Objects > Attributes screen measures
291
- a leading 20px grip column, a 16px grip icon, and the row's own hairline doubling as the drop indicator (it tints toward the brand colour as the active drop target). The affordance + geometry are measured; the drag MECHANISM is crisp's existing house idiom -- HTML5
381
+ a leading 20px grip column, a 16px grip icon, and the row's own
382
+ hairline doubling as the drop indicator (it tints toward the brand
383
+ colour as the active drop target). The affordance + geometry are
384
+ measured; the drag MECHANISM is crisp's existing house idiom -- HTML5
292
385
  draggable + dataTransfer, the same one column reorder already uses
293
- (RecordsTable's reorderColumn) -- not a proprietary pointer-events implementation. */
386
+ (RecordsTable's reorderColumn) -- not a proprietary
387
+ pointer-events implementation. */
294
388
  & .crisp-datatable-col-grip { width: 20px; padding: 0; text-align: center; }
295
389
  & .crisp-datatable-grip { display: inline-flex; align-items: center; justify-content: center; width: 100%; height: 100%; margin: 0; border: none; border-radius: 0; background: none; font-family: inherit; color: var(--crisp-fg-muted); cursor: grab; }
296
390
  & .crisp-datatable-grip:active { cursor: grabbing; }