@crisp-ui-kit/crisp 0.52.4 → 0.52.6

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 (78) hide show
  1. package/dist/board.css +6 -6
  2. package/dist/board.layered.css +6 -6
  3. package/dist/bulkbar.css +2 -2
  4. package/dist/bulkbar.layered.css +2 -2
  5. package/dist/cjs/components/bulkbar/bulkbar.js +1 -1
  6. package/dist/cjs/components/bulkbar/bulkbar.recipe.js +2 -2
  7. package/dist/cjs/components/datatable/datatable.recipe.js +4 -1
  8. package/dist/cjs/components/input/input.recipe.js +6 -1
  9. package/dist/cjs/components/multiselect/multiselect.js +1 -1
  10. package/dist/cjs/components/multiselect/multiselect.recipe.js +1 -1
  11. package/dist/cjs/components/switch/switch.recipe.js +4 -0
  12. package/dist/cjs/components/table/table.recipe.js +5 -1
  13. package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +5 -4
  14. package/dist/cjs/components/tabletoolbar/tabletoolbar.js +1 -1
  15. package/dist/cjs/components/textarea/textarea.recipe.js +6 -1
  16. package/dist/cjs/components/tooltip/tooltip.recipe.js +13 -4
  17. package/dist/cjs/product/board/board.recipe.js +16 -6
  18. package/dist/cjs/product/entitycard/entitycard.recipe.js +20 -4
  19. package/dist/cjs/product/listpage/listpage.js +1 -1
  20. package/dist/cjs/product/listpage/listpage.recipe.js +5 -7
  21. package/dist/cjs/tokens/elevation.js +17 -2
  22. package/dist/cjs/tokens/palette.js +17 -0
  23. package/dist/cjs/tokens/semantic.js +2 -0
  24. package/dist/datatable.css +30 -24
  25. package/dist/datatable.layered.css +30 -24
  26. package/dist/entitycard.css +4 -4
  27. package/dist/entitycard.layered.css +4 -4
  28. package/dist/esm/components/bulkbar/bulkbar.js +1 -1
  29. package/dist/esm/components/bulkbar/bulkbar.recipe.js +2 -2
  30. package/dist/esm/components/datatable/datatable.recipe.js +4 -1
  31. package/dist/esm/components/input/input.recipe.js +6 -1
  32. package/dist/esm/components/multiselect/multiselect.js +1 -1
  33. package/dist/esm/components/multiselect/multiselect.recipe.js +1 -1
  34. package/dist/esm/components/switch/switch.recipe.js +4 -0
  35. package/dist/esm/components/table/table.recipe.js +5 -1
  36. package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +5 -4
  37. package/dist/esm/components/tabletoolbar/tabletoolbar.js +1 -1
  38. package/dist/esm/components/textarea/textarea.recipe.js +6 -1
  39. package/dist/esm/components/tooltip/tooltip.recipe.js +13 -4
  40. package/dist/esm/product/board/board.recipe.js +16 -6
  41. package/dist/esm/product/entitycard/entitycard.recipe.js +20 -4
  42. package/dist/esm/product/listpage/listpage.js +2 -2
  43. package/dist/esm/product/listpage/listpage.recipe.js +5 -7
  44. package/dist/esm/tokens/elevation.js +17 -2
  45. package/dist/esm/tokens/palette.js +17 -0
  46. package/dist/esm/tokens/semantic.js +2 -0
  47. package/dist/input.css +1 -1
  48. package/dist/input.layered.css +1 -1
  49. package/dist/listpage.css +5 -5
  50. package/dist/listpage.layered.css +5 -5
  51. package/dist/multiselect.css +1 -1
  52. package/dist/multiselect.layered.css +1 -1
  53. package/dist/native/tokens.d.ts +1 -1
  54. package/dist/native/tokens.js +8 -0
  55. package/dist/recordstable.css +5 -4
  56. package/dist/recordstable.layered.css +5 -4
  57. package/dist/styles.css +69 -55
  58. package/dist/styles.layered.css +69 -55
  59. package/dist/switch.css +1 -1
  60. package/dist/switch.layered.css +1 -1
  61. package/dist/table.css +3 -1
  62. package/dist/table.layered.css +3 -1
  63. package/dist/tabletoolbar.css +5 -4
  64. package/dist/tabletoolbar.layered.css +5 -4
  65. package/dist/textarea.css +1 -1
  66. package/dist/textarea.layered.css +1 -1
  67. package/dist/tokens.css +4 -0
  68. package/dist/tokens.json +8 -0
  69. package/dist/tooltip.css +1 -1
  70. package/dist/tooltip.layered.css +1 -1
  71. package/dist/types/components/bulkbar/bulkbar.d.ts +3 -3
  72. package/dist/types/components/switch/switch.recipe.d.ts +1 -0
  73. package/dist/types/components/tooltip/tooltip.recipe.d.ts +2 -2
  74. package/dist/types/tokens/contract.d.ts +2 -0
  75. package/dist/types/tokens/elevation.d.ts +17 -2
  76. package/dist/types/tokens/palette.d.ts +8 -0
  77. package/dist/types/tokens/semantic.d.ts +2 -0
  78. package/package.json +1 -1
package/dist/board.css CHANGED
@@ -1,17 +1,17 @@
1
1
  .crisp-board {
2
- display: flex; gap: var(--crisp-space-3); height: 100%; box-sizing: border-box; padding: var(--crisp-space-3); overflow-x: auto; align-items: flex-start; font-family: var(--crisp-font-sans);
3
- & .crisp-board-col { display: flex; flex-direction: column; width: 280px; flex-shrink: 0; max-height: 100%; box-sizing: border-box; }
2
+ display: flex; gap: var(--crisp-space-2); height: 100%; box-sizing: border-box; padding: var(--crisp-space-3); overflow-x: auto; align-items: flex-start; font-family: var(--crisp-font-sans);
3
+ & .crisp-board-col { display: flex; flex-direction: column; width: 268px; flex-shrink: 0; max-height: 100%; box-sizing: border-box; }
4
4
  & .crisp-board-col-header { display: flex; align-items: center; gap: var(--crisp-space-2); height: 36px; padding: 0 var(--crisp-space-1); flex-shrink: 0; }
5
- & .crisp-board-col-dot { width: 9px; height: 9px; border-radius: var(--crisp-radius-full); flex-shrink: 0; }
5
+ & .crisp-board-col-dot { width: 12px; height: 12px; border-radius: var(--crisp-radius-full); flex-shrink: 0; }
6
6
  & .crisp-board-col-title { font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-semibold); color: var(--crisp-fg-primary); }
7
- & .crisp-board-col-count { font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
8
- & .crisp-board-col-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-inline-start: auto; padding: 0; border: none; border-radius: var(--crisp-radius-md); background: none; color: var(--crisp-fg-muted); font-family: inherit; cursor: pointer; }
7
+ & .crisp-board-col-count { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-sm); background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
8
+ & .crisp-board-col-add { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin-inline-start: auto; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; color: var(--crisp-fg-muted); font-family: inherit; cursor: pointer; }
9
9
  & .crisp-board-col-add:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: var(--crisp-fg-primary); }
10
10
  & .crisp-board-col-body { display: flex; flex-direction: column; gap: var(--crisp-space-2); flex: 1; min-height: 48px; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-lg); overflow-y: auto; transition: background 0.12s; }
11
11
  & .crisp-board-col[data-over] .crisp-board-col-body { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 7%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent); }
12
12
  & .crisp-board-newcard { display: flex; align-items: center; justify-content: center; gap: var(--crisp-space-1-5); height: 32px; flex-shrink: 0; border: none; border-radius: var(--crisp-radius-md); background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); color: var(--crisp-fg-muted); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; }
13
13
  & .crisp-board-newcard:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 7%, transparent); color: var(--crisp-fg-primary); }
14
- & .crisp-board-card { display: flex; flex-direction: column; gap: var(--crisp-space-2); box-sizing: border-box; padding: var(--crisp-space-2-5) var(--crisp-space-3); border-radius: var(--crisp-radius-lg); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle), 0 1px 2px rgba(0,0,0,0.04); cursor: grab; }
14
+ & .crisp-board-card { display: flex; flex-direction: column; gap: var(--crisp-space-2); box-sizing: border-box; padding: var(--crisp-space-2-5) var(--crisp-space-3); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); cursor: grab; }
15
15
  & .crisp-board-card:active { cursor: grabbing; }
16
16
  & .crisp-board-card[data-dragging] { opacity: 0.4; }
17
17
  & .crisp-board-card:focus { outline: none; }
@@ -1,18 +1,18 @@
1
1
  @layer crisp-components {
2
2
  .crisp-board {
3
- display: flex; gap: var(--crisp-space-3); height: 100%; box-sizing: border-box; padding: var(--crisp-space-3); overflow-x: auto; align-items: flex-start; font-family: var(--crisp-font-sans);
4
- & .crisp-board-col { display: flex; flex-direction: column; width: 280px; flex-shrink: 0; max-height: 100%; box-sizing: border-box; }
3
+ display: flex; gap: var(--crisp-space-2); height: 100%; box-sizing: border-box; padding: var(--crisp-space-3); overflow-x: auto; align-items: flex-start; font-family: var(--crisp-font-sans);
4
+ & .crisp-board-col { display: flex; flex-direction: column; width: 268px; flex-shrink: 0; max-height: 100%; box-sizing: border-box; }
5
5
  & .crisp-board-col-header { display: flex; align-items: center; gap: var(--crisp-space-2); height: 36px; padding: 0 var(--crisp-space-1); flex-shrink: 0; }
6
- & .crisp-board-col-dot { width: 9px; height: 9px; border-radius: var(--crisp-radius-full); flex-shrink: 0; }
6
+ & .crisp-board-col-dot { width: 12px; height: 12px; border-radius: var(--crisp-radius-full); flex-shrink: 0; }
7
7
  & .crisp-board-col-title { font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-semibold); color: var(--crisp-fg-primary); }
8
- & .crisp-board-col-count { font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
9
- & .crisp-board-col-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-inline-start: auto; padding: 0; border: none; border-radius: var(--crisp-radius-md); background: none; color: var(--crisp-fg-muted); font-family: inherit; cursor: pointer; }
8
+ & .crisp-board-col-count { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-sm); background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
9
+ & .crisp-board-col-add { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin-inline-start: auto; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; color: var(--crisp-fg-muted); font-family: inherit; cursor: pointer; }
10
10
  & .crisp-board-col-add:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: var(--crisp-fg-primary); }
11
11
  & .crisp-board-col-body { display: flex; flex-direction: column; gap: var(--crisp-space-2); flex: 1; min-height: 48px; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-lg); overflow-y: auto; transition: background 0.12s; }
12
12
  & .crisp-board-col[data-over] .crisp-board-col-body { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 7%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent); }
13
13
  & .crisp-board-newcard { display: flex; align-items: center; justify-content: center; gap: var(--crisp-space-1-5); height: 32px; flex-shrink: 0; border: none; border-radius: var(--crisp-radius-md); background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); color: var(--crisp-fg-muted); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; }
14
14
  & .crisp-board-newcard:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 7%, transparent); color: var(--crisp-fg-primary); }
15
- & .crisp-board-card { display: flex; flex-direction: column; gap: var(--crisp-space-2); box-sizing: border-box; padding: var(--crisp-space-2-5) var(--crisp-space-3); border-radius: var(--crisp-radius-lg); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle), 0 1px 2px rgba(0,0,0,0.04); cursor: grab; }
15
+ & .crisp-board-card { display: flex; flex-direction: column; gap: var(--crisp-space-2); box-sizing: border-box; padding: var(--crisp-space-2-5) var(--crisp-space-3); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); cursor: grab; }
16
16
  & .crisp-board-card:active { cursor: grabbing; }
17
17
  & .crisp-board-card[data-dragging] { opacity: 0.4; }
18
18
  & .crisp-board-card:focus { outline: none; }
package/dist/bulkbar.css CHANGED
@@ -2,13 +2,13 @@
2
2
  position: absolute; left: 0; right: 0; bottom: var(--crisp-space-4); display: flex; justify-content: center; pointer-events: none; z-index: 10;
3
3
  & .crisp-bulkbar-bar { pointer-events: auto; display: flex; align-items: center; gap: var(--crisp-space-0-5); height: 48px; padding: 0 var(--crisp-space-1) 0 var(--crisp-space-1-5); border-radius: 14px; 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); color: var(--crisp-fg-primary); transition: opacity .16s ease, transform .16s ease; }
4
4
  & .crisp-bulkbar-bar { @starting-style { opacity: 0; transform: translateY(10px); } }
5
- & .crisp-bulkbar-count { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
5
+ & .crisp-bulkbar-count { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-lg); background: color-mix(in srgb, var(--crisp-fg-primary) 2%, transparent); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
6
6
  & .crisp-bulkbar-count:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); color: var(--crisp-fg-primary); }
7
7
  & .crisp-bulkbar-count svg { flex-shrink: 0; }
8
8
  /* the ", Clear selection" ARIA concatenates onto the pill's name (#324)
9
9
  -- read, never drawn. Same technique as Slider's thumblabel. */
10
10
  & .crisp-bulkbar-clearlabel { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
11
- & .crisp-bulkbar-btn { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
11
+ & .crisp-bulkbar-btn { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-lg); 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); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
12
12
  & .crisp-bulkbar-btn:hover { background: var(--crisp-bg-raised); }
13
13
  & .crisp-bulkbar-btn--danger { color: var(--crisp-bg-danger); }
14
14
  & .crisp-bulkbar-btn--danger:hover { background: color-mix(in srgb, var(--crisp-bg-danger) 10%, transparent); }
@@ -3,13 +3,13 @@
3
3
  position: absolute; left: 0; right: 0; bottom: var(--crisp-space-4); display: flex; justify-content: center; pointer-events: none; z-index: 10;
4
4
  & .crisp-bulkbar-bar { pointer-events: auto; display: flex; align-items: center; gap: var(--crisp-space-0-5); height: 48px; padding: 0 var(--crisp-space-1) 0 var(--crisp-space-1-5); border-radius: 14px; 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); color: var(--crisp-fg-primary); transition: opacity .16s ease, transform .16s ease; }
5
5
  & .crisp-bulkbar-bar { @starting-style { opacity: 0; transform: translateY(10px); } }
6
- & .crisp-bulkbar-count { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
6
+ & .crisp-bulkbar-count { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-lg); background: color-mix(in srgb, var(--crisp-fg-primary) 2%, transparent); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
7
7
  & .crisp-bulkbar-count:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); color: var(--crisp-fg-primary); }
8
8
  & .crisp-bulkbar-count svg { flex-shrink: 0; }
9
9
  /* the ", Clear selection" ARIA concatenates onto the pill's name (#324)
10
10
  -- read, never drawn. Same technique as Slider's thumblabel. */
11
11
  & .crisp-bulkbar-clearlabel { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
12
- & .crisp-bulkbar-btn { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
12
+ & .crisp-bulkbar-btn { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-lg); 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); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
13
13
  & .crisp-bulkbar-btn:hover { background: var(--crisp-bg-raised); }
14
14
  & .crisp-bulkbar-btn--danger { color: var(--crisp-bg-danger); }
15
15
  & .crisp-bulkbar-btn--danger:hover { background: color-mix(in srgb, var(--crisp-bg-danger) 10%, transparent); }
@@ -44,7 +44,7 @@ const bulkbar_recipe_1 = require("./bulkbar.recipe");
44
44
  * positioned ancestor when a selection is active; render it conditionally
45
45
  * (e.g. `count > 0 && <BulkBar …/>`). Measured from a records table.
46
46
  */
47
- function BulkBar({ count, onClear, countLabel = "selected", countText = (count, label) => ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [count, " ", label] })), children, className, clearLabel = "Clear selection", ...rest }) {
47
+ function BulkBar({ count, onClear, countLabel = "Selected", countText = (count, label) => ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [count, " ", label] })), children, className, clearLabel = "Clear selection", ...rest }) {
48
48
  return ((0, jsx_runtime_1.jsx)("div", { className: (0, bulkbar_recipe_1.bulkbarRecipe)({ className }), ...rest, children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-bulkbar-bar", children: [count != null && ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-bulkbar-count", onClick: onClear, title: clearLabel, children: [countText(count, countLabel), (0, jsx_runtime_1.jsx)("span", { className: "crisp-bulkbar-clearlabel", children: clearLabel }), (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 13, strokeWidth: 2, "aria-hidden": "true" })] })), children] }) }));
49
49
  }
50
50
  BulkBar.displayName = "BulkBar";
@@ -15,7 +15,7 @@ const config = (0, core_1.defineRecipe)({
15
15
  base: `position: absolute; left: 0; right: 0; bottom: ${tokens_1.contract.space["4"]}; display: flex; justify-content: center; pointer-events: none; z-index: 10;
16
16
  & .crisp-bulkbar-bar { pointer-events: auto; display: flex; align-items: center; gap: ${tokens_1.contract.space["0.5"]}; height: 48px; padding: 0 ${tokens_1.contract.space["1"]} 0 ${tokens_1.contract.space["1.5"]}; border-radius: 14px; background: ${tokens_1.contract.bgSurface}; box-shadow: ${tokens_1.elevation.floating}; color: ${tokens_1.contract.fgPrimary}; transition: opacity .16s ease, transform .16s ease; }
17
17
  & .crisp-bulkbar-bar { @starting-style { opacity: 0; transform: translateY(10px); } }
18
- & .crisp-bulkbar-count { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1"]}; height: ${tokens_1.contract.size.menuRow}; margin: 0; padding: 0 ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.md}; background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 4%, transparent); font-family: inherit; font-size: ${tokens_1.contract.text.md}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; white-space: nowrap; cursor: pointer; transition: background-color .12s; }
18
+ & .crisp-bulkbar-count { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1"]}; height: ${tokens_1.contract.size.menuRow}; margin: 0; padding: 0 ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.lg}; background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 2%, transparent); font-family: inherit; font-size: ${tokens_1.contract.text.md}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; white-space: nowrap; cursor: pointer; transition: background-color .12s; }
19
19
  & .crisp-bulkbar-count:hover { background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 8%, transparent); color: ${tokens_1.contract.fgPrimary}; }
20
20
  & .crisp-bulkbar-count svg { flex-shrink: 0; }
21
21
  /* the ", Clear selection" ARIA concatenates onto the pill's name (#324)
@@ -24,7 +24,7 @@ const config = (0, core_1.defineRecipe)({
24
24
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
25
25
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
26
26
  }
27
- & .crisp-bulkbar-btn { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1"]}; height: ${tokens_1.contract.size.menuRow}; padding: 0 ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.md}; background: transparent; color: ${tokens_1.contract.fgPrimary}; font-family: inherit; font-size: ${tokens_1.contract.text.md}; font-weight: ${tokens_1.contract.weight.medium}; white-space: nowrap; cursor: pointer; transition: background-color .12s; }
27
+ & .crisp-bulkbar-btn { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1"]}; height: ${tokens_1.contract.size.menuRow}; padding: 0 ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.lg}; background: ${tokens_1.contract.bgSurface}; box-shadow: ${tokens_1.elevation.field}; color: ${tokens_1.contract.fgPrimary}; font-family: inherit; font-size: ${tokens_1.contract.text.md}; font-weight: ${tokens_1.contract.weight.medium}; white-space: nowrap; cursor: pointer; transition: background-color .12s; }
28
28
  & .crisp-bulkbar-btn:hover { background: ${tokens_1.contract.bgRaised}; }
29
29
  & .crisp-bulkbar-btn--danger { color: ${tokens_1.contract.bgDanger}; }
30
30
  & .crisp-bulkbar-btn--danger:hover { background: color-mix(in srgb, ${tokens_1.contract.bgDanger} 10%, transparent); }
@@ -50,7 +50,10 @@ const config = (0, core_1.defineRecipe)({
50
50
  & .crisp-datatable-th-rename { width: 100%; min-width: 0; height: ${tokens_1.contract.size.row}; margin: 0; padding: 0 ${tokens_1.contract.space["1"]}; border: none; border-radius: ${tokens_1.contract.radius.md}; background: ${tokens_1.contract.bgSurface}; box-shadow: inset 0 0 0 1px ${tokens_1.contract.bgBrandSolid}; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; outline: none; }
51
51
  & .crisp-datatable-th-rename:focus { box-shadow: inset 0 0 0 1px ${tokens_1.contract.bgBrandSolid}; }
52
52
  & .crisp-datatable-th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
53
- & .crisp-datatable-sort { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; width: 100%; min-width: 0; height: 100%; margin: 0; padding: 0 ${tokens_1.contract.space["2"]}; border: none; background: none; font: inherit; letter-spacing: inherit; color: inherit; text-align: start; cursor: pointer; }
53
+ /* #465: 12px per the comment above (and Attio's measured header cell
54
+ padding: 0 12px) -- was still c.space["2"] (8px), drifted from its
55
+ own documented value. */
56
+ & .crisp-datatable-sort { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; width: 100%; min-width: 0; height: 100%; margin: 0; padding: 0 ${tokens_1.contract.space["3"]}; border: none; background: none; font: inherit; letter-spacing: inherit; color: inherit; text-align: start; cursor: pointer; }
54
57
  /* A right-aligned column's header keeps its field-icon + label packed at
55
58
  the START, matching its own values only in that the VALUES right-align
56
59
  -- Attio's own right-aligned header (measured live: "Twitter follower
@@ -4,6 +4,11 @@ exports.inputRecipe = void 0;
4
4
  const core_1 = require("../../core");
5
5
  const tokens_1 = require("../../tokens");
6
6
  // Geometry is measured: 32/36px tall, r8/r10, 10/12px side padding.
7
+ // The shadow is `elevation.textField` (#466), not `elevation.field` — a real
8
+ // typed field on Attio's own Settings page carries one 1px ring, not
9
+ // `field`'s button-chrome glow/drop-shadow layers too; `field`'s own doc
10
+ // comment had claimed "inputs, textareas" among its consumers, which this
11
+ // corrects.
7
12
  // The FOCUS TREATMENT is seed-design's, measured from @seed-design/css: a 2px
8
13
  // ring on an ::after overlay that is present-but-transparent at rest, so
9
14
  // focusing cannot shift layout the way a width change would, and animates
@@ -18,7 +23,7 @@ const config = (0, core_1.defineRecipe)({
18
23
  name: "input",
19
24
  base: `
20
25
  position: relative; box-sizing: border-box; display: inline-flex; align-items: center;
21
- width: 100%; background: ${tokens_1.contract.bgSurface}; box-shadow: ${tokens_1.elevation.field};
26
+ width: 100%; background: ${tokens_1.contract.bgSurface}; box-shadow: ${tokens_1.elevation.textField};
22
27
  font-family: ${tokens_1.contract.font.sans}; font-size: ${tokens_1.contract.text.lg}; line-height: 20px;
23
28
 
24
29
  &::after {
@@ -202,7 +202,7 @@ id, placeholder = "Select…", searchable = true, searchPlaceholder = "Search…
202
202
  e.preventDefault();
203
203
  openMenu();
204
204
  }
205
- }, children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-multiselect-chips", children: selectedOptions.length === 0 ? ((0, jsx_runtime_1.jsx)("span", { className: "crisp-multiselect-placeholder", children: placeholder })) : (selectedOptions.map((o) => (0, jsx_runtime_1.jsx)(Chip, { opt: o }, o.value))) }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { className: "crisp-multiselect-chevron", size: 16, strokeWidth: 1.75 })] }), open && ((0, jsx_runtime_1.jsx)(core_1.FloatingPortal, { sourceRef: rootRef, children: (0, jsx_runtime_1.jsxs)("div", { ref: listboxRef, id: listboxId, className: "crisp-multiselect-listbox", role: "listbox", "aria-multiselectable": "true", "aria-label": ariaLabel, "data-up": up ? "" : undefined, style: pos, children: [searchable && ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-multiselect-search", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Search, { size: 15, strokeWidth: 1.75 }), (0, jsx_runtime_1.jsx)("input", { ref: searchRef, type: "text", placeholder: searchPlaceholder, "aria-label": searchPlaceholder, "aria-controls": listboxId, "aria-activedescendant": activeId, value: query, onChange: (e) => {
205
+ }, children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-multiselect-chips", children: selectedOptions.length === 0 ? ((0, jsx_runtime_1.jsx)("span", { className: "crisp-multiselect-placeholder", children: placeholder })) : (selectedOptions.map((o) => (0, jsx_runtime_1.jsx)(Chip, { opt: o }, o.value))) }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { className: "crisp-multiselect-chevron", size: 16, strokeWidth: 1.75 })] }), open && ((0, jsx_runtime_1.jsx)(core_1.FloatingPortal, { sourceRef: rootRef, children: (0, jsx_runtime_1.jsxs)("div", { ref: listboxRef, id: listboxId, className: "crisp-multiselect-listbox", role: "listbox", "aria-multiselectable": "true", "aria-label": ariaLabel, "data-up": up ? "" : undefined, style: pos, children: [searchable && ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-multiselect-search", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Search, { size: 16, strokeWidth: 1.75 }), (0, jsx_runtime_1.jsx)("input", { ref: searchRef, type: "text", placeholder: searchPlaceholder, "aria-label": searchPlaceholder, "aria-controls": listboxId, "aria-activedescendant": activeId, value: query, onChange: (e) => {
206
206
  setQuery(e.target.value);
207
207
  setHighlight(0);
208
208
  }, onKeyDown: onNavKeys })] })), filtered.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-multiselect-empty", children: emptyLabel })) : (filtered.map((opt, i) => {
@@ -65,7 +65,7 @@ const config = (0, core_1.defineRecipe)({
65
65
  }
66
66
  .crisp-multiselect-listbox[data-up] { transform-origin: bottom left; }
67
67
  .crisp-multiselect-listbox { @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
68
- .crisp-multiselect-search { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: 34px; flex-shrink: 0; margin: calc(-1 * ${tokens_1.contract.space["1"]}) calc(-1 * ${tokens_1.contract.space["1"]}) ${tokens_1.contract.space["1"]}; padding: 0 ${tokens_1.contract.space["2.5"]}; border-bottom: 1px solid ${tokens_1.contract.borderSubtle}; color: ${tokens_1.contract.fgMuted}; }
68
+ .crisp-multiselect-search { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; height: 36px; flex-shrink: 0; margin: calc(-1 * ${tokens_1.contract.space["1"]}) calc(-1 * ${tokens_1.contract.space["1"]}) ${tokens_1.contract.space["1"]}; padding: ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["3"]}; color: ${tokens_1.contract.fgMuted}; }
69
69
  .crisp-multiselect-search svg { flex-shrink: 0; }
70
70
  .crisp-multiselect-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; }
71
71
  .crisp-multiselect-search input::placeholder { color: ${tokens_1.contract.fgMuted}; }
@@ -6,6 +6,9 @@ const tokens_1 = require("../../tokens");
6
6
  // A settings toggle, measured from the live app: a 24×16 pill track that
7
7
  // flips from a muted grey to brand blue (#266df0), with a 12px white thumb
8
8
  // (2px inset) that slides 8px across. background + transform both animate .2s.
9
+ // The thumb also carries a 1px ring (#463, `rgb(217,218,222)`) — missed in
10
+ // the original measurement pass; without it the white thumb has no defined
11
+ // edge against the track's own light grey.
9
12
  const spec = (0, core_1.defineSpec)({
10
13
  name: "switch",
11
14
  base: {
@@ -33,6 +36,7 @@ const spec = (0, core_1.defineSpec)({
33
36
  margin: "0 2px",
34
37
  borderRadius: tokens_1.contract.radius.full,
35
38
  background: "#fff",
39
+ boxShadow: `0 0 0 1px ${tokens_1.contract.ringSwitch}`,
36
40
  transition: "transform .2s ease",
37
41
  },
38
42
  },
@@ -13,7 +13,11 @@ const config = (0, core_1.defineRecipe)({
13
13
  base: `display: block; box-sizing: border-box; background: ${tokens_1.contract.bgSurface};
14
14
  & .crisp-table-scroll { overflow-x: auto; }
15
15
  & table { width: 100%; border-collapse: separate; border-spacing: 0; font-family: ${tokens_1.contract.font.sans}; font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; }
16
- & th, & td { position: relative; height: ${tokens_1.contract.size.tableRow}; padding: 0 ${tokens_1.contract.space["2"]}; border-bottom: 1px solid ${tokens_1.contract.borderSubtle}; border-inline-end: 1px solid ${tokens_1.contract.borderSubtle}; text-align: start; vertical-align: middle; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
16
+ /* #465: 12px, not crisp's old 8px -- measured on a live header cell
17
+ (padding: 0 12px) and independently on a body cell's text inset
18
+ (getBoundingClientRect delta from the cell edge). Matches
19
+ ColumnCalc's own already-correct 12px trigger inset. */
20
+ & th, & td { position: relative; height: ${tokens_1.contract.size.tableRow}; padding: 0 ${tokens_1.contract.space["3"]}; border-bottom: 1px solid ${tokens_1.contract.borderSubtle}; border-inline-end: 1px solid ${tokens_1.contract.borderSubtle}; text-align: start; vertical-align: middle; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
17
21
  & th { height: ${tokens_1.contract.size.tableHeader}; background: ${tokens_1.contract.bgSurface}; border-top: 1px solid ${tokens_1.contract.borderSubtle}; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; letter-spacing: -0.14px; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); user-select: none; }
18
22
  & td { color: ${tokens_1.contract.fgPrimary}; background: ${tokens_1.contract.bgSurface}; }
19
23
  & th:last-child, & td:last-child { border-inline-end: none; }
@@ -17,7 +17,7 @@ const tokens_1 = require("../../tokens");
17
17
  // block, and those depend on following `.menu` in source order. Keeping the
18
18
  // split preserves that cascade exactly, which is what lets the generated CSS
19
19
  // stay byte-for-byte identical to what shipped before the extraction.
20
- const toolbarChromeHead = (p) => ` & .${namespace_1.CLASS_PREFIX}${p}-toolbar { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; padding: 0 ${tokens_1.contract.space["3"]} ${tokens_1.contract.space["2"]}; }
20
+ const toolbarChromeHead = (p) => ` & .${namespace_1.CLASS_PREFIX}${p}-toolbar { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; padding: 0 ${tokens_1.contract.space["3"]} ${tokens_1.contract.space["2"]}; }
21
21
  & .${namespace_1.CLASS_PREFIX}${p}-toolbar[data-inline] { padding-bottom: 0; }
22
22
  & .${namespace_1.CLASS_PREFIX}${p}-search { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; height: ${tokens_1.contract.size.row}; padding: 0 ${tokens_1.contract.space["2.5"]}; border: none; border-radius: ${tokens_1.contract.radius.md}; background: ${tokens_1.contract.bgSurface}; box-shadow: inset 0 0 0 1px ${tokens_1.contract.borderSubtle}; color: ${tokens_1.contract.fgMuted}; }
23
23
  & .${namespace_1.CLASS_PREFIX}${p}-search svg { flex-shrink: 0; }
@@ -30,11 +30,12 @@ const toolbarChromeHead = (p) => ` & .${namespace_1.CLASS_PREFIX}${p}-toolbar
30
30
  & .${namespace_1.CLASS_PREFIX}${p}-tool--ghost { box-shadow: none; background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 3%, transparent); color: ${tokens_1.contract.fgMuted}; }
31
31
  & .${namespace_1.CLASS_PREFIX}${p}-tool--ghost:hover { background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 6%, transparent); }
32
32
  & .${namespace_1.CLASS_PREFIX}${p}-toolgroup { position: relative; display: inline-flex; }
33
- & .${namespace_1.CLASS_PREFIX}${p}-menu { position: absolute; top: calc(100% + ${tokens_1.contract.space["1"]}); left: 0; z-index: 30; min-width: 232px; padding: ${tokens_1.contract.space["1"]}; border-radius: ${tokens_1.contract.radius.lg}; background: ${tokens_1.contract.bgPopover}; box-shadow: ${tokens_1.elevation.floating}; display: flex; flex-direction: column; gap: ${tokens_1.contract.space.px}; transform-origin: top; opacity: 1; transform: none; transition: opacity .13s ease, transform .13s ease; }
33
+ & .${namespace_1.CLASS_PREFIX}${p}-divider { flex-shrink: 0; width: 1px; height: 20px; background: ${tokens_1.contract.borderSubtle}; }
34
+ & .${namespace_1.CLASS_PREFIX}${p}-menu { position: absolute; top: calc(100% + ${tokens_1.contract.space["1"]}); left: 0; z-index: 30; min-width: 232px; padding: ${tokens_1.contract.space["1"]}; border-radius: ${tokens_1.contract.radius.xl}; background: ${tokens_1.contract.bgPopover}; box-shadow: ${tokens_1.elevation.floating}; display: flex; flex-direction: column; gap: ${tokens_1.contract.space.px}; transform-origin: top; opacity: 1; transform: none; transition: opacity .13s ease, transform .13s ease; }
34
35
  & .${namespace_1.CLASS_PREFIX}${p}-menu { @starting-style { opacity: 0; transform: scale(0.96); } }`;
35
36
  exports.toolbarChromeHead = toolbarChromeHead;
36
37
  const toolbarChromeBody = (p) => ` & .${namespace_1.CLASS_PREFIX}${p}-menu-head { padding: ${tokens_1.contract.space["1"]} ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["0.5"]}; font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; }
37
- & .${namespace_1.CLASS_PREFIX}${p}-sortpop { min-width: 460px; overflow: visible; padding: ${tokens_1.contract.space["1.5"]}; gap: ${tokens_1.contract.space["1"]}; }
38
+ & .${namespace_1.CLASS_PREFIX}${p}-sortpop { min-width: 480px; overflow: visible; padding: ${tokens_1.contract.space["3"]} ${tokens_1.contract.space["1.5"]}; gap: ${tokens_1.contract.space["2"]}; }
38
39
  & .${namespace_1.CLASS_PREFIX}${p}-sort-empty { padding: ${tokens_1.contract.space["1"]} ${tokens_1.contract.space["1"]} ${tokens_1.contract.space["2"]}; font-size: ${tokens_1.contract.text.md}; color: ${tokens_1.contract.fgMuted}; }
39
40
  & .${namespace_1.CLASS_PREFIX}${p}-sort-row { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; }
40
41
  & .${namespace_1.CLASS_PREFIX}${p}-sort-grip { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 28px; flex-shrink: 0; margin-right: calc(-1 * ${tokens_1.contract.space["1"]}); padding: 0; border: none; background: none; color: ${tokens_1.contract.fgMuted}; cursor: grab; }
@@ -55,7 +56,7 @@ const toolbarChromeBody = (p) => ` & .${namespace_1.CLASS_PREFIX}${p}-menu-he
55
56
  & .${namespace_1.CLASS_PREFIX}${p}-sort-learn { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; font-size: ${tokens_1.contract.text.lg}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); text-decoration: none; }
56
57
  & .${namespace_1.CLASS_PREFIX}${p}-sort-learn svg { flex-shrink: 0; }
57
58
  & .${namespace_1.CLASS_PREFIX}${p}-sort-learn:hover { color: ${tokens_1.contract.fgPrimary}; }
58
- & .${namespace_1.CLASS_PREFIX}${p}-menu-item { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; width: 100%; height: ${tokens_1.contract.size.row}; margin: 0; padding: 0 ${tokens_1.contract.space["2"]}; border: none; background: none; border-radius: ${tokens_1.contract.radius.md}; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; text-align: left; cursor: pointer; }
59
+ & .${namespace_1.CLASS_PREFIX}${p}-menu-item { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; width: 100%; height: ${tokens_1.contract.size.menuRow}; margin: 0; padding: 0 ${tokens_1.contract.space["2"]}; border: none; background: none; border-radius: ${tokens_1.contract.radius.md}; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; text-align: left; cursor: pointer; }
59
60
  & .${namespace_1.CLASS_PREFIX}${p}-menu-item:hover { background: ${tokens_1.contract.bgRaised}; }
60
61
  & .${namespace_1.CLASS_PREFIX}${p}-menu-item:disabled { opacity: 0.4; cursor: default; }
61
62
  & .${namespace_1.CLASS_PREFIX}${p}-menu-item:disabled:hover { background: none; }
@@ -273,7 +273,7 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
273
273
  label: ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-sort-optlabel", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDownWideNarrow, { size: 15, strokeWidth: 1.75 }), descendingLabel] })),
274
274
  keywords: descendingLabel,
275
275
  },
276
- ], "aria-label": sortDirectionLabel }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-sort-remove", onClick: () => removeSort(i), "aria-label": removeSortLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 15, strokeWidth: 1.75 }) })] }, s.key)))), (0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-addrow", children: (0, jsx_runtime_1.jsxs)("button", { ref: addSortRef, type: "button", className: "crisp-tabletoolbar-sort-add", onClick: addSort, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), addSortLabel] }) }), helpHref && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-foot", children: (0, jsx_runtime_1.jsxs)("a", { className: "crisp-tabletoolbar-sort-learn", href: helpHref, target: "_blank", rel: "noreferrer", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CircleHelp, { size: 14, strokeWidth: 1.75 }), learnSortingLabel] }) }))] }))] }), (0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-toolgroup", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: `crisp-tabletoolbar-tool crisp-tabletoolbar-tool--ghost${activeFilters ? " crisp-tabletoolbar-tool--active" : ""}`, onClick: () => setOpenMenu(openMenu === "filter" ? null : "filter"), "aria-haspopup": "dialog", "aria-expanded": openMenu === "filter", "data-menu-trigger": true, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ListFilter, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" }), filterTriggerLabel
276
+ ], "aria-label": sortDirectionLabel }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-sort-remove", onClick: () => removeSort(i), "aria-label": removeSortLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 15, strokeWidth: 1.75 }) })] }, s.key)))), (0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-addrow", children: (0, jsx_runtime_1.jsxs)("button", { ref: addSortRef, type: "button", className: "crisp-tabletoolbar-sort-add", onClick: addSort, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), addSortLabel] }) }), helpHref && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-foot", children: (0, jsx_runtime_1.jsxs)("a", { className: "crisp-tabletoolbar-sort-learn", href: helpHref, target: "_blank", rel: "noreferrer", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CircleHelp, { size: 14, strokeWidth: 1.75 }), learnSortingLabel] }) }))] }))] }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-divider", "aria-hidden": "true" }), (0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-toolgroup", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: `crisp-tabletoolbar-tool crisp-tabletoolbar-tool--ghost${activeFilters ? " crisp-tabletoolbar-tool--active" : ""}`, onClick: () => setOpenMenu(openMenu === "filter" ? null : "filter"), "aria-haspopup": "dialog", "aria-expanded": openMenu === "filter", "data-menu-trigger": true, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ListFilter, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" }), filterTriggerLabel
277
277
  ? filterTriggerLabel(activeFilters)
278
278
  : activeFilters
279
279
  ? `Filter · ${activeFilters}`
@@ -7,6 +7,11 @@ const tokens_1 = require("../../tokens");
7
7
  // optional character counter pinned bottom-right (12px, muted). Focus rings
8
8
  // the field brand.
9
9
  //
10
+ // The ring is `elevation.textField` (#466), not `elevation.field` — this
11
+ // comment already correctly described "an inset 1px ring", but the code
12
+ // pulled in `field`'s own button-chrome shadow (a ring PLUS a glow and a
13
+ // drop-shadow layer), which live Attio never carries on a real typed field.
14
+ //
10
15
  // The inset is seed-design's, not Attio's -- the second deliberate divergence
11
16
  // after the focus treatment. seed's text-input sets its inline inset to
12
17
  // `$dimension.x3_5`, which rootage/dimension.yaml gives as **14px**, against
@@ -23,7 +28,7 @@ const config = (0, core_1.defineRecipe)({
23
28
  & .crisp-textarea-field {
24
29
  box-sizing: border-box; display: block; width: 100%; min-height: 80px; resize: vertical;
25
30
  margin: 0; padding: ${tokens_1.contract.space["2.5"]} 14px; border: none; border-radius: ${tokens_1.contract.radius.md};
26
- background: ${tokens_1.contract.bgSurface}; box-shadow: ${tokens_1.elevation.field};
31
+ background: ${tokens_1.contract.bgSurface}; box-shadow: ${tokens_1.elevation.textField};
27
32
  font-family: inherit; font-size: ${tokens_1.contract.text.lg}; line-height: 20px; color: ${tokens_1.contract.fgPrimary};
28
33
  outline: none; transition: box-shadow .15s ease;
29
34
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
@@ -5,6 +5,15 @@ const core_1 = require("../../core");
5
5
  const tokens_1 = require("../../tokens");
6
6
  // The floating bubble for a Tooltip — a dark hint chip. Applied to the
7
7
  // portaled bubble itself (not a wrapper), so its styles survive the portal.
8
+ //
9
+ // Re-measured live against Attio's own tooltip (crisp#465): background,
10
+ // text colour, vertical padding and radius were all off — #20242c/#fff/4px
11
+ // vertical/6px radius were an earlier, uncorroborated guess (not the same
12
+ // surface Lesson 24 in AUTHORING.md describes for the RichText toolbar,
13
+ // despite the similar wording). The real values are gray900's light hex
14
+ // (#101112, the same "dark pill" ink NavItem's own text uses) and
15
+ // line100's light hex (#eeeff1) — both theme-constant, same as before,
16
+ // just the wrong pair.
8
17
  const spec = (0, core_1.defineSpec)({
9
18
  name: "tooltip",
10
19
  base: {
@@ -13,10 +22,10 @@ const spec = (0, core_1.defineSpec)({
13
22
  boxSizing: "border-box",
14
23
  pointerEvents: "none",
15
24
  maxWidth: "260px",
16
- padding: `${tokens_1.contract.space["1"]} ${tokens_1.contract.space["2"]}`,
17
- borderRadius: tokens_1.contract.radius.sm,
18
- background: "#20242c",
19
- color: "#fff",
25
+ padding: `${tokens_1.contract.space["1.5"]} ${tokens_1.contract.space["2"]}`,
26
+ borderRadius: tokens_1.contract.radius.md,
27
+ background: "#101112",
28
+ color: "#eeeff1",
20
29
  fontFamily: tokens_1.contract.font.sans,
21
30
  fontSize: tokens_1.contract.text.sm,
22
31
  fontWeight: tokens_1.contract.weight.medium,
@@ -6,21 +6,31 @@ const tokens_1 = require("../../tokens");
6
6
  // A kanban board — measured from a Deals pipeline: horizontally scrolling
7
7
  // columns (dot + title + count header, a "New" button, a stack of draggable
8
8
  // cards), with the hovered drop column highlighted.
9
+ //
10
+ // Re-measured directly against a live Deals pipeline board (#463): column
11
+ // 268px (was an unmeasured 280), 8px gap between columns (was space[3]/12,
12
+ // measured space[2]), the stage dot 12x12 (was a guessed 9x9), the header's
13
+ // "+" 20x20 at radius.sm (was 24x24 at radius.md), the count as a filled
14
+ // 16px pill rather than bare text, and the card at radius.xl/12px (was
15
+ // radius.lg/9) with a single measured 1px ring and no second shadow layer —
16
+ // the extra `0 1px 2px rgba(0,0,0,0.04)` layer doesn't exist on the
17
+ // reference card at all (see AUTHORING Lesson 22: don't add polish the
18
+ // reference lacks).
9
19
  const config = (0, core_1.defineRecipe)({
10
20
  name: "board",
11
- base: `display: flex; gap: ${tokens_1.contract.space["3"]}; height: 100%; box-sizing: border-box; padding: ${tokens_1.contract.space["3"]}; overflow-x: auto; align-items: flex-start; font-family: ${tokens_1.contract.font.sans};
12
- & .crisp-board-col { display: flex; flex-direction: column; width: 280px; flex-shrink: 0; max-height: 100%; box-sizing: border-box; }
21
+ base: `display: flex; gap: ${tokens_1.contract.space["2"]}; height: 100%; box-sizing: border-box; padding: ${tokens_1.contract.space["3"]}; overflow-x: auto; align-items: flex-start; font-family: ${tokens_1.contract.font.sans};
22
+ & .crisp-board-col { display: flex; flex-direction: column; width: 268px; flex-shrink: 0; max-height: 100%; box-sizing: border-box; }
13
23
  & .crisp-board-col-header { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: 36px; padding: 0 ${tokens_1.contract.space["1"]}; flex-shrink: 0; }
14
- & .crisp-board-col-dot { width: 9px; height: 9px; border-radius: ${tokens_1.contract.radius.full}; flex-shrink: 0; }
24
+ & .crisp-board-col-dot { width: 12px; height: 12px; border-radius: ${tokens_1.contract.radius.full}; flex-shrink: 0; }
15
25
  & .crisp-board-col-title { font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.semibold}; color: ${tokens_1.contract.fgPrimary}; }
16
- & .crisp-board-col-count { font-size: ${tokens_1.contract.text.md}; color: ${tokens_1.contract.fgMuted}; }
17
- & .crisp-board-col-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-inline-start: auto; padding: 0; border: none; border-radius: ${tokens_1.contract.radius.md}; background: none; color: ${tokens_1.contract.fgMuted}; font-family: inherit; cursor: pointer; }
26
+ & .crisp-board-col-count { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 ${tokens_1.contract.space["1"]}; border-radius: ${tokens_1.contract.radius.sm}; background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 4%, transparent); font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); }
27
+ & .crisp-board-col-add { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin-inline-start: auto; padding: 0; border: none; border-radius: ${tokens_1.contract.radius.sm}; background: none; color: ${tokens_1.contract.fgMuted}; font-family: inherit; cursor: pointer; }
18
28
  & .crisp-board-col-add:hover { background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 6%, transparent); color: ${tokens_1.contract.fgPrimary}; }
19
29
  & .crisp-board-col-body { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["2"]}; flex: 1; min-height: 48px; padding: ${tokens_1.contract.space["1"]}; border-radius: ${tokens_1.contract.radius.lg}; overflow-y: auto; transition: background 0.12s; }
20
30
  & .crisp-board-col[data-over] .crisp-board-col-body { background: color-mix(in srgb, ${tokens_1.contract.bgBrandSolid} 7%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, ${tokens_1.contract.bgBrandSolid} 30%, transparent); }
21
31
  & .crisp-board-newcard { display: flex; align-items: center; justify-content: center; gap: ${tokens_1.contract.space["1.5"]}; height: 32px; flex-shrink: 0; border: none; border-radius: ${tokens_1.contract.radius.md}; background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 4%, transparent); color: ${tokens_1.contract.fgMuted}; font-family: inherit; font-size: ${tokens_1.contract.text.md}; font-weight: ${tokens_1.contract.weight.medium}; cursor: pointer; }
22
32
  & .crisp-board-newcard:hover { background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 7%, transparent); color: ${tokens_1.contract.fgPrimary}; }
23
- & .crisp-board-card { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["2"]}; box-sizing: border-box; padding: ${tokens_1.contract.space["2.5"]} ${tokens_1.contract.space["3"]}; border-radius: ${tokens_1.contract.radius.lg}; background: ${tokens_1.contract.bgSurface}; box-shadow: inset 0 0 0 1px ${tokens_1.contract.borderSubtle}, 0 1px 2px rgba(0,0,0,0.04); cursor: grab; }
33
+ & .crisp-board-card { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["2"]}; box-sizing: border-box; padding: ${tokens_1.contract.space["2.5"]} ${tokens_1.contract.space["3"]}; border-radius: ${tokens_1.contract.radius.xl}; background: ${tokens_1.contract.bgSurface}; box-shadow: inset 0 0 0 1px ${tokens_1.contract.borderSubtle}; cursor: grab; }
24
34
  & .crisp-board-card:active { cursor: grabbing; }
25
35
  & .crisp-board-card[data-dragging] { opacity: 0.4; }
26
36
  & .crisp-board-card:focus { outline: none; }
@@ -6,6 +6,22 @@ const tokens_1 = require("../../tokens");
6
6
  // A note / entity card — measured from a Notes grid: a bordered white card
7
7
  // with an author row (avatar + name) at the top, a title, a clamped excerpt,
8
8
  // and a footer row (avatar + name … date). The whole card is clickable.
9
+ //
10
+ // Re-measured directly against a live note card (#474): the author name
11
+ // renders at fgPrimary/text.sm (12px), not a muted 13px — it reads as
12
+ // regular body text, not a caption. The title is weight.medium (500), not
13
+ // semibold — "my" measured 500 on the live card, and semibold was an
14
+ // unmeasured guess. The excerpt is text.sm (12px)/16px line-height, and
15
+ // both the excerpt body and the footer date share one muted tone that is
16
+ // darker than `fgMuted` (measured `rgba(0,0,0,0.63)` on the excerpt
17
+ // paragraph AND, independently, on the footer date — the same value also
18
+ // turned up on Board's "29d" age pill in the same audit, so it's a real,
19
+ // reused Attio tone and not noise). `fgMuted` (gray400, #71717a) doesn't
20
+ // carry that ring, so this reads it as 63% of `fgPrimary` instead of adding
21
+ // an unmeasured new dark-mode literal (AUTHORING Lesson 47) — `fgPrimary`
22
+ // already flips correctly per theme, so the mix preserves the *relationship*
23
+ // Attio is expressing (a darker secondary text tone) in both themes.
24
+ const secondaryFg = `color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent)`;
9
25
  const config = (0, core_1.defineRecipe)({
10
26
  name: "entitycard",
11
27
  base: `display: flex; flex-direction: column; box-sizing: border-box; width: 100%; min-width: 0; text-align: start;
@@ -17,11 +33,11 @@ const config = (0, core_1.defineRecipe)({
17
33
  &:hover { box-shadow: inset 0 0 0 1px ${tokens_1.contract.borderDefault}, 0 1px 2px rgba(0,0,0,0.04), 0 6px 16px -6px rgba(28,40,64,0.12); }
18
34
  &:focus-visible { outline: 2px solid ${tokens_1.contract.bgBrandSolid}; outline-offset: 2px; }
19
35
 
20
- & .crisp-entitycard-author { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; font-size: ${tokens_1.contract.text.md}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; }
21
- & .crisp-entitycard-title { margin-top: ${tokens_1.contract.space["2"]}; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.semibold}; letter-spacing: -0.1px; color: ${tokens_1.contract.fgPrimary}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
22
- & .crisp-entitycard-excerpt { margin-top: ${tokens_1.contract.space["1"]}; font-size: ${tokens_1.contract.text.md}; line-height: 18px; color: ${tokens_1.contract.fgMuted}; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
36
+ & .crisp-entitycard-author { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; }
37
+ & .crisp-entitycard-title { margin-top: ${tokens_1.contract.space["2"]}; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; letter-spacing: -0.1px; color: ${tokens_1.contract.fgPrimary}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
38
+ & .crisp-entitycard-excerpt { margin-top: ${tokens_1.contract.space["1"]}; font-size: ${tokens_1.contract.text.sm}; line-height: 16px; color: ${secondaryFg}; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
23
39
  & .crisp-entitycard-spacer { flex: 1; min-height: ${tokens_1.contract.space["3"]}; }
24
- & .crisp-entitycard-foot { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; padding-top: ${tokens_1.contract.space["2.5"]}; margin-top: ${tokens_1.contract.space["1"]}; border-top: 1px solid ${tokens_1.contract.borderSubtle}; font-size: ${tokens_1.contract.text.sm}; color: ${tokens_1.contract.fgMuted}; }
40
+ & .crisp-entitycard-foot { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; padding-top: ${tokens_1.contract.space["2.5"]}; margin-top: ${tokens_1.contract.space["1"]}; border-top: 1px solid ${tokens_1.contract.borderSubtle}; font-size: ${tokens_1.contract.text.sm}; color: ${secondaryFg}; }
25
41
  & .crisp-entitycard-foot-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: ${tokens_1.contract.fgPrimary}; }
26
42
  & .crisp-entitycard-date { margin-inline-start: auto; flex-shrink: 0; white-space: nowrap; }`,
27
43
  variants: {},
@@ -20,6 +20,6 @@ function ListRow({ children, onClick, }) {
20
20
  */
21
21
  function ListPage({ leading, trailing, count, favorites, favoritesLabel = "Favorites", columns, groups, emptyLabel = "Nothing here yet", className, ...rest }) {
22
22
  const total = groups?.reduce((s, g) => s + g.rows.length, 0) ?? 0;
23
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, listpage_recipe_1.listpageRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-listpage-toolbar", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-toolbar-lead", children: leading }), count != null && (0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-count", children: count }), trailing != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-toolbar-trail", children: trailing }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-listpage-body", children: [favorites != null && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-section-label", children: favoritesLabel }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-favorites", "data-dashed": "", children: favorites })] })), columns && columns.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-colhead", children: columns.map((col, i) => ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-listpage-colhead-cell", children: [col.icon, col.label] }, i))) })), total === 0 && !groups?.length ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-empty", children: emptyLabel })) : (groups?.map((g) => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-listpage-group", children: [g.label, g.count != null && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-listpage-group-count", children: g.count }))] }), g.rows] }, g.id))))] })] }));
23
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, listpage_recipe_1.listpageRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-listpage-toolbar", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-toolbar-lead", children: leading }), count != null && (0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-count", children: count }), trailing != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-toolbar-trail", children: trailing }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-listpage-body", children: [favorites != null && ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-listpage-favorites-section", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-section-label", children: favoritesLabel }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-favorites", children: favorites })] })), columns && columns.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-colhead", children: columns.map((col, i) => ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-listpage-colhead-cell", children: [col.icon, col.label] }, i))) })), total === 0 && !groups?.length ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-listpage-empty", children: emptyLabel })) : (groups?.map((g) => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-listpage-group", children: [g.label, g.count != null && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-listpage-group-count", children: g.count }))] }), g.rows] }, g.id))))] })] }));
24
24
  }
25
25
  ListPage.displayName = "ListPage";
@@ -12,7 +12,7 @@ const config = (0, core_1.defineRecipe)({
12
12
  base: `display: flex; flex-direction: column; min-height: 0; box-sizing: border-box; font-family: ${tokens_1.contract.font.sans}; color: ${tokens_1.contract.fgPrimary};
13
13
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
14
14
 
15
- & .crisp-listpage-toolbar { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: 52px; flex-shrink: 0; padding: 0 ${tokens_1.contract.space["3"]}; }
15
+ & .crisp-listpage-toolbar { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: ${tokens_1.contract.size.header}; flex-shrink: 0; padding: 0 ${tokens_1.contract.space["3"]}; }
16
16
  & .crisp-listpage-toolbar-lead { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; }
17
17
  & .crisp-listpage-count { margin-inline-start: auto; font-size: ${tokens_1.contract.text.md}; color: ${tokens_1.contract.fgMuted}; white-space: nowrap; }
18
18
  & .crisp-listpage-toolbar-trail { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; }
@@ -21,15 +21,13 @@ const config = (0, core_1.defineRecipe)({
21
21
  & .crisp-listpage-body { flex: 1; min-height: 0; overflow-y: auto; padding: 0 ${tokens_1.contract.space["3"]} ${tokens_1.contract.space["3"]}; }
22
22
 
23
23
  & .crisp-listpage-section-label { padding: ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["1"]}; font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; }
24
- & .crisp-listpage-favorites { display: flex; align-items: center; justify-content: center; min-height: 200px; padding: ${tokens_1.contract.space["6"]}; border-radius: ${tokens_1.contract.radius.xl};
25
- background: repeating-linear-gradient(0deg, transparent, transparent) padding-box,
26
- border-box; box-shadow: inset 0 0 0 1px color-mix(in srgb, ${tokens_1.contract.fgPrimary} 8%, transparent); }
27
- & .crisp-listpage-favorites[data-dashed] { box-shadow: none; border: 1px dashed color-mix(in srgb, ${tokens_1.contract.fgPrimary} 14%, transparent); }
24
+ & .crisp-listpage-favorites-section { background: ${tokens_1.contract.bgSubtle}; box-shadow: inset 0 -1px 0 ${tokens_1.contract.borderSubtle}; }
25
+ & .crisp-listpage-favorites { display: flex; align-items: center; justify-content: center; min-height: 200px; padding: ${tokens_1.contract.space["6"]}; }
28
26
 
29
- & .crisp-listpage-colhead { display: flex; align-items: center; gap: ${tokens_1.contract.space["2.5"]}; height: 40px; padding: 0 ${tokens_1.contract.space["2"]}; box-shadow: inset 0 -1px 0 ${tokens_1.contract.borderSubtle}; font-size: ${tokens_1.contract.text.sm}; color: ${tokens_1.contract.fgMuted}; }
27
+ & .crisp-listpage-colhead { display: flex; align-items: center; gap: ${tokens_1.contract.space["2.5"]}; height: ${tokens_1.contract.size.menuRow}; padding: 0 ${tokens_1.contract.space["4"]}; box-shadow: inset 0 -1px 0 ${tokens_1.contract.borderSubtle}; font-size: ${tokens_1.contract.text.sm}; color: ${tokens_1.contract.fgMuted}; }
30
28
  & .crisp-listpage-colhead-cell { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; }
31
29
 
32
- & .crisp-listpage-group { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; height: 36px; padding: 0 ${tokens_1.contract.space["2"]}; font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; }
30
+ & .crisp-listpage-group { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; height: ${tokens_1.contract.size.menuRow}; padding: ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["4"]}; box-shadow: inset 0 -1px 0 ${tokens_1.contract.borderSubtle}; background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 2%, transparent); font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; }
33
31
  & .crisp-listpage-group-count { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 ${tokens_1.contract.space["1"]}; border-radius: ${tokens_1.contract.radius.sm}; background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 6%, transparent); font-size: ${tokens_1.contract.text.xs}; color: ${tokens_1.contract.fgMuted}; }
34
32
 
35
33
  & .crisp-listpage-row { display: flex; align-items: center; gap: ${tokens_1.contract.space["2.5"]}; width: 100%; height: 52px; padding: 0 ${tokens_1.contract.space["2"]}; margin: 0; border: none; border-top: 1px solid ${tokens_1.contract.borderSubtle}; background: none; font-family: inherit; color: inherit; text-align: start; cursor: pointer; transition: background-color .12s; }
@@ -27,8 +27,16 @@ exports.elevation = {
27
27
  */
28
28
  modal: `0 8px 28px -6px ${contract_1.contract.shadowOverlay1}, 0 18px 88px -4px ${contract_1.contract.shadowOverlay2}, 0 0 1px ${contract_1.contract.shadowOverlay3}`,
29
29
  /**
30
- * The neutral/outlined control shadow — buttons, inputs, textareas, the
31
- * sidebar search, record-page actions.
30
+ * The neutral/outlined BUTTON-CHROME shadow — real buttons only: the
31
+ * sidebar search trigger, record-page action buttons, table toolbar
32
+ * buttons. #466 corrects this doc comment's own former claim that it
33
+ * covers "inputs, textareas" too — it doesn't: a live Attio text field
34
+ * (Settings page, a real typed input) measures a single 1px ring, none of
35
+ * this token's glow/drop-shadow layers. Confirmed the other direction
36
+ * too — Attio's own white-filled chrome buttons ("Inbox", "Ask Attio",
37
+ * "All Companies" view chip) match this three-layer value exactly, so the
38
+ * token itself was right; only Input/Textarea's use of it was wrong. See
39
+ * `textField` below for the real field shadow.
32
40
  *
33
41
  * The two raw values **are** the measured value (Lessons 22 and 29) and
34
42
  * must stay raw. `rgba(0,0,0,0.04)` equals `tileActiveShadow`'s light value by
@@ -36,6 +44,13 @@ exports.elevation = {
36
44
  * dark mode. Only the ring is theme-aware, via `ringNeutral`.
37
45
  */
38
46
  field: `inset 0 0 0 1px ${contract_1.contract.ringNeutral}, 0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04)`,
47
+ /**
48
+ * A real text-entry field (Input, Textarea) — measured live on Attio's
49
+ * Settings page: one 1px inset ring, nothing else (#466). Distinct from
50
+ * `field` above, which is button chrome and carries two extra shadow
51
+ * layers a typed field never has.
52
+ */
53
+ textField: `inset 0 0 0 1px ${contract_1.contract.ringField}`,
39
54
  /**
40
55
  * The same control shadow **without** the theme-aware ring. Lesson 29 added
41
56
  * the ring to the neutral-button family but deliberately left `trialbanner`
@@ -13,6 +13,23 @@ exports.palette = {
13
13
  line200: { light: "#e4e4e7", dark: "#212224" },
14
14
  line100: { light: "#eeeff1", dark: "#1c1d1f" },
15
15
  ringNeutral: { light: "transparent", dark: "#212224" },
16
+ // Text-entry fields (Input, Textarea) — measured live on app.attio.com's
17
+ // Settings page, a real typed field: `inset 0 0 0 1px rgba(0,0,0,.06)`,
18
+ // ONE layer, not `elevation.field`'s button-chrome three (that token's own
19
+ // doc comment claimed "inputs, textareas" among its consumers; #466
20
+ // corrects it — a real field never carried the extra glow/drop-shadow
21
+ // layers, only its own 1px ring). Dark value not independently
22
+ // re-measured (Attio's own theme setting is off-limits to toggle) — reuses
23
+ // `ringNeutral`/`ringPopover`'s existing dark ring (#212224), the same
24
+ // "edge visible against a dark surface" role those already establish,
25
+ // rather than inventing a new value.
26
+ ringField: { light: "rgba(0,0,0,0.06)", dark: "#212224" },
27
+ // Switch's thumb ring (#463) — measured live, `rgb(217,218,222)` on the
28
+ // white thumb. Dark value not independently re-measured (same Attio-theme
29
+ // restriction as ringField above); the thumb itself stays pure white in
30
+ // both themes (Switch's own spec), so this reuses ringField's dark value
31
+ // rather than inventing a third "field-adjacent ring, dark" colour.
32
+ ringSwitch: { light: "#d9dade", dark: "#212224" },
16
33
  tileActive: { light: "#ffffff", dark: "#101112" },
17
34
  tileActiveShadow: { light: "rgba(0,0,0,0.04)", dark: "rgba(0,0,0,0)" },
18
35
  overlayFrost: { light: "#ffffff", dark: "#1c1d1f" },
@@ -14,6 +14,8 @@ exports.semantic = {
14
14
  borderDefault: "line200",
15
15
  borderSubtle: "line100",
16
16
  ringNeutral: "ringNeutral",
17
+ ringField: "ringField",
18
+ ringSwitch: "ringSwitch",
17
19
  bgTileActive: "tileActive",
18
20
  shadowTileActive: "tileActiveShadow",
19
21
  bgOverlayFrost: "overlayFrost",