@crisp-ui-kit/crisp 0.54.0 → 0.54.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 (127) hide show
  1. package/dist/activityfeed.css +12 -0
  2. package/dist/activityfeed.d.ts +7 -0
  3. package/dist/activityfeed.layered.css +14 -0
  4. package/dist/badge.css +3 -0
  5. package/dist/badge.d.ts +2 -2
  6. package/dist/badge.layered.css +3 -0
  7. package/dist/cjs/components/badge/badge.recipe.js +10 -0
  8. package/dist/cjs/components/datatable/datatable.js +2 -1
  9. package/dist/cjs/components/datatable/datatable.recipe.js +4 -0
  10. package/dist/cjs/components/mentionchip/index.js +7 -0
  11. package/dist/cjs/components/mentionchip/mentionchip.js +57 -0
  12. package/dist/cjs/components/mentionchip/mentionchip.recipe.js +38 -0
  13. package/dist/cjs/components/table/table.recipe.js +15 -3
  14. package/dist/cjs/core/floating-stack.js +18 -0
  15. package/dist/cjs/core/index.js +2 -1
  16. package/dist/cjs/index.js +7 -0
  17. package/dist/cjs/product/activityfeed/activityfeed.js +38 -0
  18. package/dist/cjs/product/activityfeed/activityfeed.recipe.js +35 -0
  19. package/dist/cjs/product/activityfeed/index.js +10 -0
  20. package/dist/cjs/product/formdialog/formdialog.js +171 -0
  21. package/dist/cjs/product/formdialog/formdialog.recipe.js +26 -0
  22. package/dist/cjs/product/formdialog/index.js +8 -0
  23. package/dist/cjs/product/importdialog/importdialog.js +134 -0
  24. package/dist/cjs/product/importdialog/importdialog.recipe.js +92 -0
  25. package/dist/cjs/product/importdialog/index.js +18 -0
  26. package/dist/cjs/product/richtext/richtext.js +43 -0
  27. package/dist/cjs/product/savedviews/index.js +7 -0
  28. package/dist/cjs/product/savedviews/savedviews.js +207 -0
  29. package/dist/cjs/product/savedviews/savedviews.recipe.js +103 -0
  30. package/dist/cjs/product/taskstable/index.js +7 -0
  31. package/dist/cjs/product/taskstable/taskstable.js +27 -0
  32. package/dist/cjs/product/taskstable/taskstable.recipe.js +47 -0
  33. package/dist/cjs/product/themepicker/index.js +17 -0
  34. package/dist/cjs/product/themepicker/themepicker.js +32 -0
  35. package/dist/cjs/product/themepicker/themepicker.recipe.js +98 -0
  36. package/dist/cjs/tokens/palette.js +31 -0
  37. package/dist/cjs/tokens/semantic.js +11 -0
  38. package/dist/datatable.css +20 -21
  39. package/dist/datatable.layered.css +20 -21
  40. package/dist/esm/components/badge/badge.recipe.js +10 -0
  41. package/dist/esm/components/datatable/datatable.js +2 -1
  42. package/dist/esm/components/datatable/datatable.recipe.js +4 -0
  43. package/dist/esm/components/mentionchip/index.js +2 -0
  44. package/dist/esm/components/mentionchip/mentionchip.js +21 -0
  45. package/dist/esm/components/mentionchip/mentionchip.recipe.js +35 -0
  46. package/dist/esm/components/table/table.recipe.js +15 -3
  47. package/dist/esm/core/floating-stack.js +17 -0
  48. package/dist/esm/core/index.js +1 -1
  49. package/dist/esm/index.js +7 -0
  50. package/dist/esm/product/activityfeed/activityfeed.js +32 -0
  51. package/dist/esm/product/activityfeed/activityfeed.recipe.js +32 -0
  52. package/dist/esm/product/activityfeed/index.js +2 -0
  53. package/dist/esm/product/formdialog/formdialog.js +134 -0
  54. package/dist/esm/product/formdialog/formdialog.recipe.js +23 -0
  55. package/dist/esm/product/formdialog/index.js +2 -0
  56. package/dist/esm/product/importdialog/importdialog.js +97 -0
  57. package/dist/esm/product/importdialog/importdialog.recipe.js +89 -0
  58. package/dist/esm/product/importdialog/index.js +2 -0
  59. package/dist/esm/product/richtext/richtext.js +43 -0
  60. package/dist/esm/product/savedviews/index.js +2 -0
  61. package/dist/esm/product/savedviews/savedviews.js +171 -0
  62. package/dist/esm/product/savedviews/savedviews.recipe.js +100 -0
  63. package/dist/esm/product/taskstable/index.js +2 -0
  64. package/dist/esm/product/taskstable/taskstable.js +24 -0
  65. package/dist/esm/product/taskstable/taskstable.recipe.js +44 -0
  66. package/dist/esm/product/themepicker/index.js +1 -0
  67. package/dist/esm/product/themepicker/themepicker.js +29 -0
  68. package/dist/esm/product/themepicker/themepicker.recipe.js +95 -0
  69. package/dist/esm/tokens/palette.js +31 -0
  70. package/dist/esm/tokens/semantic.js +11 -0
  71. package/dist/formdialog.css +6 -0
  72. package/dist/formdialog.d.ts +7 -0
  73. package/dist/formdialog.layered.css +8 -0
  74. package/dist/importdialog.css +38 -0
  75. package/dist/importdialog.d.ts +7 -0
  76. package/dist/importdialog.layered.css +40 -0
  77. package/dist/mentionchip.css +3 -0
  78. package/dist/mentionchip.d.ts +7 -0
  79. package/dist/mentionchip.layered.css +5 -0
  80. package/dist/native/tokens.d.ts +1 -1
  81. package/dist/native/tokens.js +24 -4
  82. package/dist/savedviews.css +78 -0
  83. package/dist/savedviews.d.ts +7 -0
  84. package/dist/savedviews.layered.css +80 -0
  85. package/dist/styles.css +242 -27
  86. package/dist/styles.layered.css +242 -27
  87. package/dist/table.css +15 -6
  88. package/dist/table.layered.css +15 -6
  89. package/dist/taskstable.css +23 -0
  90. package/dist/taskstable.d.ts +7 -0
  91. package/dist/taskstable.layered.css +25 -0
  92. package/dist/themepicker.css +27 -0
  93. package/dist/themepicker.d.ts +7 -0
  94. package/dist/themepicker.layered.css +29 -0
  95. package/dist/tokens.css +10 -0
  96. package/dist/tokens.json +24 -4
  97. package/dist/types/components/badge/badge.d.ts +2 -0
  98. package/dist/types/components/badge/badge.recipe.d.ts +8 -0
  99. package/dist/types/components/datatable/datatable.d.ts +12 -1
  100. package/dist/types/components/mentionchip/index.d.ts +2 -0
  101. package/dist/types/components/mentionchip/mentionchip.d.ts +20 -0
  102. package/dist/types/components/mentionchip/mentionchip.recipe.d.ts +18 -0
  103. package/dist/types/core/floating-stack.d.ts +14 -0
  104. package/dist/types/core/index.d.ts +1 -1
  105. package/dist/types/index.d.ts +7 -0
  106. package/dist/types/product/activityfeed/activityfeed.d.ts +57 -0
  107. package/dist/types/product/activityfeed/activityfeed.recipe.d.ts +3 -0
  108. package/dist/types/product/activityfeed/index.d.ts +2 -0
  109. package/dist/types/product/formdialog/formdialog.d.ts +57 -0
  110. package/dist/types/product/formdialog/formdialog.recipe.d.ts +3 -0
  111. package/dist/types/product/formdialog/index.d.ts +2 -0
  112. package/dist/types/product/importdialog/importdialog.d.ts +86 -0
  113. package/dist/types/product/importdialog/importdialog.recipe.d.ts +3 -0
  114. package/dist/types/product/importdialog/index.d.ts +2 -0
  115. package/dist/types/product/savedviews/index.d.ts +2 -0
  116. package/dist/types/product/savedviews/savedviews.d.ts +55 -0
  117. package/dist/types/product/savedviews/savedviews.recipe.d.ts +3 -0
  118. package/dist/types/product/taskstable/index.d.ts +2 -0
  119. package/dist/types/product/taskstable/taskstable.d.ts +54 -0
  120. package/dist/types/product/taskstable/taskstable.recipe.d.ts +3 -0
  121. package/dist/types/product/themepicker/index.d.ts +1 -0
  122. package/dist/types/product/themepicker/themepicker.d.ts +21 -0
  123. package/dist/types/product/themepicker/themepicker.recipe.d.ts +3 -0
  124. package/dist/types/tokens/contract.d.ts +5 -0
  125. package/dist/types/tokens/palette.d.ts +20 -0
  126. package/dist/types/tokens/semantic.d.ts +11 -0
  127. package/package.json +36 -1
@@ -7,6 +7,7 @@
7
7
  --crisp-bg-raised: #f4f4f5;
8
8
  --crisp-border-default: #e4e4e7;
9
9
  --crisp-border-subtle: #eeeff1;
10
+ --crisp-border-dropzone: #e6e7ea;
10
11
  --crisp-ring-neutral: transparent;
11
12
  --crisp-ring-field: rgba(0,0,0,0.06);
12
13
  --crisp-ring-switch: #d9dade;
@@ -25,6 +26,7 @@
25
26
  --crisp-fg-muted: #71717a;
26
27
  --crisp-bg-danger: #e5484d;
27
28
  --crisp-bg-danger-solid: #ba2525;
29
+ --crisp-fg-danger: #eb3b3b;
28
30
  --crisp-stroke-field-focus: #1a1c20;
29
31
  --crisp-fg-disabled: #d1d3d8;
30
32
  --crisp-bg-neutral-weak: #f3f4f5;
@@ -45,6 +47,9 @@
45
47
  --crisp-fg-warning-soft: #80520d;
46
48
  --crisp-fg-danger-soft: #a33539;
47
49
  --crisp-fg-neutral-soft: #686870;
50
+ --crisp-bg-purple-soft: #f5f0ff;
51
+ --crisp-fg-purple-soft: #6238b5;
52
+ --crisp-ring-purple-soft: #e8ddfe;
48
53
  }
49
54
 
50
55
  [data-theme="dark"] {
@@ -56,6 +61,7 @@
56
61
  --crisp-bg-raised: #101112;
57
62
  --crisp-border-default: #212224;
58
63
  --crisp-border-subtle: #1c1d1f;
64
+ --crisp-border-dropzone: #212224;
59
65
  --crisp-ring-neutral: #212224;
60
66
  --crisp-ring-field: #212224;
61
67
  --crisp-ring-switch: #212224;
@@ -74,6 +80,7 @@
74
80
  --crisp-fg-muted: #9a9aa2;
75
81
  --crisp-bg-danger: #ff5a5f;
76
82
  --crisp-bg-danger-solid: #ba2525;
83
+ --crisp-fg-danger: #ff5a5f;
77
84
  --crisp-stroke-field-focus: #f3f4f5;
78
85
  --crisp-fg-disabled: #5b606a;
79
86
  --crisp-bg-neutral-weak: #1d2025;
@@ -94,6 +101,9 @@
94
101
  --crisp-fg-warning-soft: #e0982a;
95
102
  --crisp-fg-danger-soft: #ff5a5f;
96
103
  --crisp-fg-neutral-soft: #9a9aa2;
104
+ --crisp-bg-purple-soft: #2f1e5a;
105
+ --crisp-fg-purple-soft: #d8c4ff;
106
+ --crisp-ring-purple-soft: #45297d;
97
107
  }
98
108
 
99
109
  :root {
@@ -225,6 +235,9 @@
225
235
  .crisp-badge--tone_danger {
226
236
  background: color-mix(in srgb, var(--crisp-bg-danger) 14%, transparent); color: var(--crisp-fg-danger-soft); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-danger) 30%, transparent);
227
237
  }
238
+ .crisp-badge--tone_purple {
239
+ background: var(--crisp-bg-purple-soft); color: var(--crisp-fg-purple-soft); box-shadow: inset 0 0 0 1px var(--crisp-ring-purple-soft);
240
+ }
228
241
  .crisp-badge--size_small {
229
242
  height: 16px; padding-inline: var(--crisp-space-1-5); font-size: var(--crisp-text-xs); border-radius: var(--crisp-radius-sm);
230
243
  }
@@ -593,6 +606,9 @@
593
606
  /* sticky first column(s) + horizontal scroll shadow — RecordsTable's feel */
594
607
  & th[data-sticky], & td[data-sticky] { position: sticky; z-index: 1; background: var(--crisp-bg-surface); }
595
608
  & th[data-sticky] { z-index: 3; }
609
+ /* #554: a footer sticky-column cell sits in the bottom-sticky row (table.recipe.ts's
610
+ `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. */
611
+ & tfoot td[data-sticky] { z-index: 2; }
596
612
  & tbody tr[data-selected] td[data-sticky] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 10%, var(--crisp-bg-surface)); }
597
613
  & tbody tr:hover td[data-sticky] { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); }
598
614
  & .crisp-table-scroll[data-scrolled-x] [data-sticky-edge] { clip-path: inset(0 -38px 0 0); box-shadow: 6px 0 16px 4px rgba(0,0,0,0.12); }
@@ -610,23 +626,25 @@
610
626
  & .crisp-datatable-editable:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); cursor: text; }
611
627
  & .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; }
612
628
  & .crisp-datatable-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
613
- /* An async onEdit's in-flight state (#385) -- the field/picker dims and stops accepting input rather than disappearing, so the just-typed or just-chosen value stays visible while its commit is pending. Same treatment Input already gives its own disabled state. */
629
+ /* An async onEdit's in-flight state (#385) -- the field/picker dims and
630
+ stops accepting input rather than disappearing, so the just-typed or
631
+ just-chosen value stays visible while its commit is pending. Same
632
+ treatment Input already gives its own disabled state. */
614
633
  & .crisp-datatable-edit:disabled { opacity: 0.5; cursor: not-allowed; }
615
634
  & .crisp-datatable-edit-pending { flex-shrink: 0; margin-inline-start: var(--crisp-space-1); color: var(--crisp-fg-muted); vertical-align: middle; }
616
- /* The rejection's message, beside the cell's own content -- a sibling in the TableCell, never nested inside a column's own render output, so a
617
- hover-only wrapper (a Tooltip, say) around a custom render can't hide it. Block-level: the row grows to fit it rather than floating over the row below, so it can never end up clipped by the scroll container's overflow the way a position:fixed escape would need
618
- guarding against. */
635
+ /* The rejection's message, beside the cell's own content -- a sibling in
636
+ 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
637
+ it. Block-level: the row grows to fit it rather than floating over
638
+ the row below, so it can never end up clipped by the scroll
639
+ container's overflow the way a position:fixed escape would need guarding against. */
619
640
  & .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); }
620
- /* editor: "select"/"switch" -- always live, no separate edit mode, so
621
- the cell IS the picker: same chromeless-fill treatment as
622
- RecordsTable's own --picker cells (measured there already; DataTable shares RecordsTable's grid, Golden Rule 0). */
641
+ /* 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
642
+ shares RecordsTable's grid, Golden Rule 0). */
623
643
  & .crisp-datatable-td--picker { padding: 0; }
624
644
  & .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); }
625
645
  & .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; }
626
646
  & .crisp-datatable-td--picker .crisp-datatable-edit-error { padding-inline-start: var(--crisp-space-2); }
627
- /* reference picker: a leading 16px avatar per option, plus a trailing
628
- "Create X" row when the consumer supplies one (#449) -- same measured
629
- values as RecordsTable's own .crisp-recordstable-refoption*. */
647
+ /* 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*. */
630
648
  & .crisp-datatable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
631
649
  & .crisp-datatable-refoption-avatar { flex-shrink: 0; }
632
650
  & .crisp-datatable-refoption--create { color: var(--crisp-fg-muted); }
@@ -643,12 +661,7 @@
643
661
  & .crisp-datatable-entity:hover .crisp-datatable-entity-name { text-decoration: underline; }
644
662
  & 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%; }
645
663
  & .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); }
646
- & .crisp-datatable-avatar[data-tone="success"] { background: var(--crisp-bg-success); }
647
- & .crisp-datatable-avatar[data-tone="warning"] { background: var(--crisp-bg-warning); }
648
- & .crisp-datatable-avatar[data-tone="danger"] { background: var(--crisp-bg-danger); }
649
- & .crisp-datatable-avatar[data-tone="purple"] { background: var(--crisp-bg-purple); }
650
- & .crisp-datatable-avatar[data-tone="cyan"] { background: var(--crisp-bg-cyan); }
651
- & .crisp-datatable-avatar[data-tone="orange"] { background: var(--crisp-bg-orange); }
664
+ & .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); }
652
665
  & .crisp-datatable-avatar img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }
653
666
  & .crisp-datatable-tags { display: flex; align-items: center; gap: var(--crisp-space-1); overflow: hidden; }
654
667
  & .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); }
@@ -661,11 +674,10 @@
661
674
  & .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)); }
662
675
  & .crisp-datatable-num { font-variant-numeric: tabular-nums; }
663
676
  & .crisp-datatable-muted { color: var(--crisp-fg-muted); }
664
- /* row drag-to-reorder -- a Settings > Objects > Attributes screen measures a leading 20px grip column, a 16px grip icon, and the row's own
665
- hairline doubling as the drop indicator (it tints toward the brand
666
- colour as the active drop target). The affordance + geometry are
667
- measured; the drag MECHANISM is crisp's existing house idiom -- HTML5 draggable + dataTransfer, the same one column reorder already uses (RecordsTable's reorderColumn) -- not a proprietary
668
- pointer-events implementation. */
677
+ /* row drag-to-reorder -- a Settings > Objects > Attributes screen measures
678
+ 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
679
+ draggable + dataTransfer, the same one column reorder already uses
680
+ (RecordsTable's reorderColumn) -- not a proprietary pointer-events implementation. */
669
681
  & .crisp-datatable-col-grip { width: 20px; padding: 0; text-align: center; }
670
682
  & .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; }
671
683
  & .crisp-datatable-grip:active { cursor: grabbing; }
@@ -1110,6 +1122,10 @@
1110
1122
  & .crisp-linechart-axis-title { margin-top: var(--crisp-space-1); padding-inline-start: var(--crisp-linechart-yaxis-width); text-align: center; font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); }
1111
1123
  }
1112
1124
 
1125
+ .crisp-mention-chip {
1126
+ display: inline; border-radius: var(--crisp-radius-chip); padding-inline: var(--crisp-space-1); background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); font-weight: var(--crisp-weight-medium); cursor: default;
1127
+ }
1128
+
1113
1129
 
1114
1130
  /* pointer-events: auto (#375): a modal Dialog sets pointer-events: none
1115
1131
  on document.body while open (Zag re-enables it only on layers IT
@@ -1618,17 +1634,26 @@
1618
1634
  }
1619
1635
 
1620
1636
  .crisp-table {
1621
- display: block; box-sizing: border-box; background: var(--crisp-bg-surface);
1622
- & .crisp-table-scroll { overflow-x: auto; }
1637
+ display: block; box-sizing: border-box; background: var(--crisp-bg-surface); /* #554: both axes -- a consumer bounds the height via `scrollProps` (style/className on this element), and the header/footer below pin inside it exactly the way Attio's own grid does ("Both the header and
1638
+ the summary row are sticky, on the scroll container rather than the
1639
+ cells" -- docs/study/attio-table.md). Unbounded, `overflow: auto`
1640
+ shows no vertical scrollbar and nothing sticks, so this is a no-op
1641
+ for every existing consumer that never set a height. */
1642
+ & .crisp-table-scroll { overflow: auto; }
1623
1643
  & table { width: 100%; border-collapse: separate; border-spacing: 0; font-family: var(--crisp-font-sans); font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
1624
- /* #465: 12px, not crisp's old 8px -- measured on a live header cell
1625
- (padding: 0 12px) and independently on a body cell's text inset (getBoundingClientRect delta from the cell edge). Matches ColumnCalc's own already-correct 12px trigger inset. */
1644
+ /* #465: 12px, not crisp's old 8px -- measured on a live header cell (padding: 0 12px) and independently on a body cell's text inset
1645
+ (getBoundingClientRect delta from the cell edge). Matches
1646
+ ColumnCalc's own already-correct 12px trigger inset. */
1626
1647
  & th, & td { position: relative; height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-3); border-bottom: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); text-align: start; vertical-align: middle; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
1627
- & th { height: var(--crisp-size-tableHeader); background: var(--crisp-bg-surface); border-top: 1px solid var(--crisp-border-subtle); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); letter-spacing: -0.14px; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); user-select: none; }
1648
+ /* #554: sticky on the vertical axis, mirroring RecordsTable's own
1649
+ `.crisp-recordstable-th`. z-index 2 sits above a plain body cell (auto)
1650
+ and below a sticky-column corner cell (DataTable's `th[data-sticky]`, z-index 3), so the corner always wins. */
1651
+ & th { position: sticky; top: 0; z-index: 2; height: var(--crisp-size-tableHeader); background: var(--crisp-bg-surface); border-top: 1px solid var(--crisp-border-subtle); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); letter-spacing: -0.14px; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); user-select: none; }
1628
1652
  & td { color: var(--crisp-fg-primary); background: var(--crisp-bg-surface); }
1629
1653
  & th:last-child, & td:last-child { border-inline-end: none; }
1630
1654
  & tbody tr:last-child td { border-bottom: none; }
1631
- & tfoot td { border-top: 1px solid var(--crisp-border-subtle); border-bottom: 1px solid var(--crisp-border-subtle); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
1655
+ /* #554: sticky to the bottom, mirroring `.crisp-recordstable-sum`. */
1656
+ & tfoot td { position: sticky; bottom: 0; z-index: 2; border-top: 1px solid var(--crisp-border-subtle); border-bottom: 1px solid var(--crisp-border-subtle); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
1632
1657
  & caption { padding: var(--crisp-space-2) var(--crisp-space-2); text-align: start; font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); caption-side: bottom; }
1633
1658
  & td[data-align="right"], & th[data-align="right"] { text-align: end; }
1634
1659
  & td[data-align="center"], & th[data-align="center"] { text-align: center; }
@@ -1870,6 +1895,19 @@
1870
1895
  & .crisp-wheelpicker-item { height: 44px; min-height: 44px; font-size: 26px; line-height: 35px; }
1871
1896
  }
1872
1897
 
1898
+ .crisp-activityfeed {
1899
+ box-sizing: border-box; max-width: 767px; margin-inline: auto; padding: var(--crisp-space-6); display: flex; flex-direction: column; gap: var(--crisp-space-4);
1900
+ & .crisp-activityfeed-row { display: flex; flex-direction: column; gap: var(--crisp-space-2); padding-bottom: var(--crisp-space-4); border-bottom: 1px solid var(--crisp-border-subtle); }
1901
+ & .crisp-activityfeed-row:last-of-type { border-bottom: none; padding-bottom: 0; }
1902
+ & .crisp-activityfeed-row-head { display: flex; align-items: center; gap: var(--crisp-space-2); }
1903
+ & .crisp-activityfeed-row-spacer { flex: 1; }
1904
+ & .crisp-activityfeed-row-when { font-size: var(--crisp-text-xs); color: var(--crisp-fg-muted); white-space: nowrap; }
1905
+ & .crisp-activityfeed-diff { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--crisp-space-1); }
1906
+ & .crisp-activityfeed-diff-item { padding-inline-start: var(--crisp-space-8); font-size: var(--crisp-text-md); }
1907
+ & .crisp-activityfeed-diff-field { color: var(--crisp-fg-muted); }
1908
+ & .crisp-activityfeed-diff-before { color: var(--crisp-fg-muted); text-decoration: line-through; }
1909
+ }
1910
+
1873
1911
  .crisp-appshell {
1874
1912
  display: flex; height: 100%; width: 100%; overflow: hidden; background: var(--crisp-bg-surface); font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
1875
1913
  & .crisp-appshell-side { position: relative; flex-shrink: 0; overflow: hidden; }
@@ -2042,6 +2080,13 @@
2042
2080
  & .crisp-flowcanvas-tool-sep { width: 1px; height: 18px; background: var(--crisp-border-subtle); }
2043
2081
  }
2044
2082
 
2083
+ .crisp-formdialog {
2084
+ & .crisp-formdialog-createfoot { display: flex; align-items: center; gap: var(--crisp-space-4); }
2085
+ & .crisp-formdialog-more-label { font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); cursor: pointer; }
2086
+ & .crisp-formdialog-error { font-size: var(--crisp-text-md); color: var(--crisp-fg-danger); margin: 0; }
2087
+ & .crisp-formdialog-form { display: grid; gap: var(--crisp-space-3); }
2088
+ }
2089
+
2045
2090
  .crisp-headerbar {
2046
2091
  box-sizing: border-box; display: flex; align-items: center; justify-content: space-between; gap: var(--crisp-space-2); height: var(--crisp-size-header); flex-shrink: 0; padding: 0 var(--crisp-space-3); font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
2047
2092
  &[data-bordered] { border-bottom: 1px solid var(--crisp-border-subtle); }
@@ -2050,6 +2095,45 @@
2050
2095
  & .crisp-headerbar-trailing { display: flex; align-items: center; gap: var(--crisp-space-2); flex-shrink: 0; }
2051
2096
  }
2052
2097
 
2098
+ .crisp-importdialog {
2099
+ display: contents; font-family: var(--crisp-font-sans);
2100
+ & .crisp-importdialog-backdrop { position: fixed; inset: 0; z-index: 60; background: transparent; }
2101
+ & .crisp-importdialog-positioner { position: fixed; inset: 0; z-index: 61; display: flex; }
2102
+ & .crisp-importdialog-content { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; position: relative; display: flex; flex-direction: column; box-sizing: border-box; width: 100%; height: 100%; border-radius: 0; background: var(--crisp-bg-surface); box-shadow: none; transform: none; opacity: 1; transition: opacity 0.2s ease; @starting-style { opacity: 0; } }
2103
+ & .crisp-importdialog-header { display: flex; align-items: center; gap: var(--crisp-space-2); flex-shrink: 0; height: 52px; padding: 0 var(--crisp-space-2) 0 var(--crisp-space-6); border-bottom: 1px solid var(--crisp-border-subtle); }
2104
+ & .crisp-importdialog-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-xl); font-weight: var(--crisp-weight-semibold); color: var(--crisp-fg-primary); margin: 0; }
2105
+ & .crisp-importdialog-close { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 28px; height: 28px; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-md); background: none; color: var(--crisp-fg-muted); font-family: inherit; cursor: pointer; }
2106
+ & .crisp-importdialog-close:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: var(--crisp-fg-primary); }
2107
+ & .crisp-importdialog-steps { display: flex; align-items: center; gap: var(--crisp-space-2); flex-shrink: 0; padding: var(--crisp-space-4) var(--crisp-space-6) 0; }
2108
+ & .crisp-importdialog-step { display: inline-flex; align-items: center; height: var(--crisp-size-row); padding: 0 var(--crisp-space-2-5); 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); cursor: default; transition: background-color .12s, color .12s; }
2109
+ & button.crisp-importdialog-step { cursor: pointer; }
2110
+ & .crisp-importdialog-step[data-active] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); }
2111
+ & .crisp-importdialog-step:focus-visible { outline: 2px solid var(--crisp-stroke-focus-ring); outline-offset: 1px; }
2112
+ & .crisp-importdialog-body { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow-y: auto; padding: var(--crisp-space-6); }
2113
+ & .crisp-importdialog-footer { display: flex; align-items: center; justify-content: flex-end; gap: var(--crisp-space-3); flex-shrink: 0; min-height: 56px; padding: 0 var(--crisp-space-6); border-top: 1px solid var(--crisp-border-subtle); }
2114
+ & .crisp-importdialog-dropzone { box-sizing: border-box; position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--crisp-space-1); width: 100%; border: 1px dashed var(--crisp-border-dropzone); border-radius: 20px; background: var(--crisp-bg-subtle); text-align: center; transition: background-color .12s, border-color .12s; }
2115
+ & .crisp-importdialog-dropzone[data-dragging-over] { border-color: var(--crisp-bg-brand-solid); background: color-mix(in srgb, var(--crisp-bg-brand-solid) 6%, transparent); }
2116
+ & .crisp-importdialog-dropzone[data-invalid] { border-color: var(--crisp-bg-danger); }
2117
+ & .crisp-importdialog-dropzone-title { color: var(--crisp-fg-primary); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); }
2118
+ & .crisp-importdialog-dropzone-or { color: var(--crisp-fg-muted); font-size: var(--crisp-text-md); line-height: 18px; }
2119
+ & .crisp-importdialog-dropzone-choose { border: none; background: none; padding: 0; margin: 0; font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-bg-brand-solid); cursor: pointer; }
2120
+ & .crisp-importdialog-dropzone-choose:hover { color: var(--crisp-bg-brand-solid-pressed); }
2121
+ & .crisp-importdialog-dropzone-choose:focus-visible { outline: 2px solid var(--crisp-stroke-focus-ring); outline-offset: 2px; border-radius: var(--crisp-radius-sm); }
2122
+ & .crisp-importdialog-dropzone-learnmore { color: var(--crisp-fg-muted); font-size: var(--crisp-text-md); text-decoration: underline; }
2123
+ & .crisp-importdialog-dropzone-input { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
2124
+ & .crisp-importdialog-dropzone-errors { margin: 0; padding: 0; list-style: none; }
2125
+ & .crisp-importdialog-dropzone-errors:empty { position: absolute; }
2126
+ & .crisp-importdialog-dropzone-error { color: var(--crisp-bg-danger); font-size: var(--crisp-text-md); line-height: 18px; }
2127
+ }
2128
+
2129
+ @media (prefers-reduced-motion: reduce) {
2130
+ .crisp-importdialog, .crisp-importdialog * {
2131
+ animation-duration: 0.01ms !important;
2132
+ animation-iteration-count: 1 !important;
2133
+ transition-duration: 0.01ms !important;
2134
+ }
2135
+ }
2136
+
2053
2137
  .crisp-inbox {
2054
2138
  display: flex; flex-direction: column; box-sizing: border-box; width: 380px; max-height: 588px; border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); font-family: var(--crisp-font-sans); overflow: hidden; 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); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
2055
2139
  & .crisp-inbox-head { padding: var(--crisp-space-3) var(--crisp-space-3) 0; }
@@ -2687,6 +2771,85 @@
2687
2771
  }
2688
2772
  }
2689
2773
 
2774
+
2775
+ /* pointer-events: auto (#375) — see Menu/MultiSelect's matching comment:
2776
+ a modal Dialog sets pointer-events: none on document.body, and a
2777
+ portaled layer outside Zag's knowledge inherits that lock. */
2778
+ .crisp-savedviews-panel {
2779
+ font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
2780
+ position: fixed; z-index: 70; pointer-events: auto; box-sizing: border-box; display: flex; flex-direction: column; gap: var(--crisp-space-px);
2781
+ min-width: 200px; max-height: 360px; overflow-y: auto; padding: var(--crisp-space-1);
2782
+ border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover);
2783
+ 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);
2784
+ transform-origin: top left; opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease;
2785
+ }
2786
+ .crisp-savedviews-panel[data-up] { transform-origin: bottom left; }
2787
+ .crisp-savedviews-panel { @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
2788
+
2789
+ .crisp-savedviews-row {
2790
+ box-sizing: border-box; position: relative; display: flex; align-items: center; gap: var(--crisp-space-1-5);
2791
+ height: var(--crisp-size-menuRow); flex-shrink: 0; padding: var(--crisp-space-1-5) var(--crisp-space-2);
2792
+ border-radius: var(--crisp-radius-md); cursor: pointer; -webkit-user-select: none; user-select: none;
2793
+ }
2794
+ .crisp-savedviews-row:hover, .crisp-savedviews-row[data-highlighted] { background: var(--crisp-bg-raised); }
2795
+ .crisp-savedviews-row-icon { flex-shrink: 0; display: inline-flex; width: var(--crisp-size-icon); height: var(--crisp-size-icon); color: var(--crisp-fg-muted); }
2796
+ .crisp-savedviews-row-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
2797
+ .crisp-savedviews-row[aria-selected="true"] .crisp-savedviews-row-label { font-weight: var(--crisp-weight-semibold); }
2798
+ .crisp-savedviews-row-shared { flex-shrink: 0; display: inline-flex; color: var(--crisp-fg-muted); }
2799
+
2800
+ /* The kebab's own <Menu> is wrapped in a slot div (savedviews.tsx) that
2801
+ stops a click from bubbling — through the REACT tree, which a portal
2802
+ does not leave, even though the Menu's content is a DOM sibling under
2803
+ document.body — into the row's own onClick. The slot, not the kebab
2804
+ button itself, is what the row's flex layout pushes to the trailing
2805
+ edge. */
2806
+ .crisp-savedviews-kebab-slot { flex-shrink: 0; margin-inline-start: auto; }
2807
+ /* 20px / 4px padding is a component-intrinsic size (AUTHORING.md §4b —
2808
+ "a badge's 20px" is the named example), used once here: raw, not a
2809
+ scale step. */
2810
+ .crisp-savedviews-kebab {
2811
+ box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center;
2812
+ width: 20px; height: 20px; padding: var(--crisp-space-1); margin: 0;
2813
+ border: none; border-radius: var(--crisp-radius-sm); background: none; color: var(--crisp-fg-muted); cursor: pointer;
2814
+ opacity: 0; transition: opacity .1s ease, background-color .12s ease, color .12s ease;
2815
+ }
2816
+ .crisp-savedviews-row:hover .crisp-savedviews-kebab,
2817
+ .crisp-savedviews-row:focus-within .crisp-savedviews-kebab,
2818
+ .crisp-savedviews-kebab[data-open] { opacity: 1; }
2819
+ .crisp-savedviews-kebab:hover, .crisp-savedviews-kebab[data-open] { background: var(--crisp-bg-surface); color: var(--crisp-fg-primary); }
2820
+
2821
+ .crisp-savedviews {
2822
+ position: relative; display: inline-flex; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* Trigger fill measured rgb(246,247,247); bgRaised's light value is
2823
+ #f4f4f5 (244,244,245) — a 2-unit-per-channel difference, inside
2824
+ screenshot/anti-aliasing noise, not a second real colour. Reusing the
2825
+ token (Lesson 3 — tokens, not raw px/hex) gets a correct,
2826
+ already-established dark-mode fill for free instead of a light-only
2827
+ literal; AUTHORING.md Lesson 29 is the case where that shortcut went
2828
+ wrong (a flat colour that stayed visible where the reference had
2829
+ none) — this is the opposite risk (a token that already flips per
2830
+ theme, applied to the closest measured match). */
2831
+ & .crisp-savedviews-trigger {
2832
+ box-sizing: border-box; display: inline-flex; align-items: center; gap: var(--crisp-space-1-5);
2833
+ height: var(--crisp-size-row); margin: 0; padding: var(--crisp-space-1) var(--crisp-space-1-5);
2834
+ border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-raised);
2835
+ font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary);
2836
+ cursor: pointer; white-space: nowrap; transition: background-color .12s ease;
2837
+ }
2838
+ & .crisp-savedviews-trigger:hover,
2839
+ & .crisp-savedviews-trigger[data-open] { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-raised)); }
2840
+ & .crisp-savedviews-trigger-icon { flex-shrink: 0; display: inline-flex; width: var(--crisp-size-icon); height: var(--crisp-size-icon); }
2841
+ & .crisp-savedviews-trigger-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
2842
+ & .crisp-savedviews-trigger-chevron { flex-shrink: 0; color: var(--crisp-fg-muted); }
2843
+ }
2844
+
2845
+ @media (prefers-reduced-motion: reduce) {
2846
+ .crisp-savedviews, .crisp-savedviews * {
2847
+ animation-duration: 0.01ms !important;
2848
+ animation-iteration-count: 1 !important;
2849
+ transition-duration: 0.01ms !important;
2850
+ }
2851
+ }
2852
+
2690
2853
  .crisp-settingssection {
2691
2854
  display: flex; flex-direction: column; box-sizing: border-box; font-family: var(--crisp-font-sans);
2692
2855
  & .crisp-settingssection-head { display: flex; align-items: flex-start; gap: var(--crisp-space-2); }
@@ -2809,6 +2972,58 @@
2809
2972
  }
2810
2973
  }
2811
2974
 
2975
+ .crisp-taskstable {
2976
+ display: flex; flex-direction: column; min-height: 0; box-sizing: border-box; font-family: var(--crisp-font-sans); color: var(--crisp-fg-primary); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
2977
+ & .crisp-taskstable-colhead { display: flex; align-items: center; gap: var(--crisp-space-1-5); min-height: 49px; max-height: 49px; padding: var(--crisp-space-2-5) var(--crisp-space-3); box-shadow: inset 0 -1px 0 var(--crisp-border-subtle); font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); }
2978
+ & .crisp-taskstable-colhead-cell { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; }
2979
+ & .crisp-taskstable-row { display: flex; align-items: center; gap: var(--crisp-space-1-5); }
2980
+ & .crisp-taskstable-cell { display: flex; align-items: center; min-width: 0; }
2981
+ & .crisp-taskstable-check { appearance: none; -webkit-appearance: none; box-sizing: border-box; flex-shrink: 0; margin: 0; width: 16px; height: 16px; border: none; border-radius: var(--crisp-radius-full); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 9%, transparent); cursor: pointer; transition: background-color .12s, box-shadow .12s; }
2982
+ & .crisp-taskstable-check:hover { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 30%, transparent); }
2983
+ & .crisp-taskstable-check:checked { background: var(--crisp-bg-brand-solid) center / 10px no-repeat; box-shadow: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 6.5 5 9l4.5-5'/%3E%3C/svg%3E"); }
2984
+ & .crisp-taskstable-check:focus-visible { outline: 2px solid var(--crisp-bg-brand-solid); outline-offset: 1px; }
2985
+ & .crisp-taskstable-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
2986
+ & .crisp-taskstable-due { font-size: var(--crisp-text-lg); color: var(--crisp-fg-muted); white-space: nowrap; }
2987
+ & .crisp-taskstable-due[data-overdue] { color: var(--crisp-fg-danger); }
2988
+ & .crisp-taskstable-empty { padding: var(--crisp-space-8) var(--crisp-space-4); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
2989
+ }
2990
+
2991
+ @media (prefers-reduced-motion: reduce) {
2992
+ .crisp-taskstable, .crisp-taskstable * {
2993
+ animation-duration: 0.01ms !important;
2994
+ animation-iteration-count: 1 !important;
2995
+ transition-duration: 0.01ms !important;
2996
+ }
2997
+ }
2998
+
2999
+ .crisp-themepicker {
3000
+ display: flex; gap: var(--crisp-space-2); font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
3001
+ & .crisp-themepicker-option { box-sizing: border-box; display: flex; flex-direction: column; align-items: center; gap: var(--crisp-space-1-5); width: 224px; padding: var(--crisp-space-1); border: 1px solid var(--crisp-border-subtle); border-radius: 16px; background: var(--crisp-bg-surface); cursor: pointer; font-family: inherit; }
3002
+ & .crisp-themepicker-option[data-selected] { border-color: var(--crisp-bg-brand-solid); }
3003
+ & .crisp-themepicker-preview { box-sizing: border-box; display: flex; width: 100%; height: 114px; padding: var(--crisp-space-2); gap: var(--crisp-space-1-5); border-radius: var(--crisp-radius-xl); overflow: hidden; }
3004
+ & .crisp-themepicker-preview-side { flex-shrink: 0; width: 28%; display: flex; flex-direction: column; gap: var(--crisp-space-1); }
3005
+ & .crisp-themepicker-preview-bar { height: 4px; border-radius: var(--crisp-radius-full); }
3006
+ & .crisp-themepicker-preview-bar:nth-child(1) { width: 70%; background: var(--crisp-bg-brand-solid); }
3007
+ & .crisp-themepicker-preview-bar:nth-child(2) { width: 90%; }
3008
+ & .crisp-themepicker-preview-bar:nth-child(3) { width: 60%; }
3009
+ & .crisp-themepicker-preview-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--crisp-space-1-5); padding: var(--crisp-space-1-5); border-radius: var(--crisp-radius-md); }
3010
+ /* Light / System (default) swatch colours. */
3011
+ & .crisp-themepicker-preview[data-swatch="light"], & .crisp-themepicker-preview[data-swatch="system"] { border: 1px solid #eeeff1; background: #fbfbfb; }
3012
+ & [data-swatch="light"] .crisp-themepicker-preview-bar:not(:nth-child(1)), & [data-swatch="system"] .crisp-themepicker-preview-bar:not(:nth-child(1)) { background: #eeeff1; }
3013
+ & [data-swatch="light"] .crisp-themepicker-preview-main, & [data-swatch="system"] .crisp-themepicker-preview-main { background: #ffffff; }
3014
+ & [data-swatch="light"] .crisp-themepicker-preview-main .crisp-themepicker-preview-bar, & [data-swatch="system"] .crisp-themepicker-preview-main .crisp-themepicker-preview-bar { background: #eeeff1; }
3015
+ /* Dark swatch colours -- always for "dark", and for "system" only when the OS itself reports dark. */
3016
+ & .crisp-themepicker-preview[data-swatch="dark"] { border: 1px solid #1c1d1f; background: #0e0f10; }
3017
+ & [data-swatch="dark"] .crisp-themepicker-preview-bar:not(:nth-child(1)) { background: #1c1d1f; }
3018
+ & [data-swatch="dark"] .crisp-themepicker-preview-main { background: #0a0a0a; }
3019
+ & [data-swatch="dark"] .crisp-themepicker-preview-main .crisp-themepicker-preview-bar { background: #1c1d1f; }
3020
+ @media (prefers-color-scheme: dark) { & .crisp-themepicker-preview[data-swatch="system"] { border: 1px solid #1c1d1f; background: #0e0f10; } & [data-swatch="system"] .crisp-themepicker-preview-bar:not(:nth-child(1)) { background: #1c1d1f; } & [data-swatch="system"] .crisp-themepicker-preview-main { background: #0a0a0a; } & [data-swatch="system"] .crisp-themepicker-preview-main .crisp-themepicker-preview-bar { background: #1c1d1f; } }
3021
+ & .crisp-themepicker-label { display: flex; align-items: center; gap: var(--crisp-space-1); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
3022
+ & .crisp-themepicker-option[data-selected] .crisp-themepicker-label { color: var(--crisp-fg-primary); }
3023
+ & .crisp-themepicker-radio { flex-shrink: 0; width: 14px; height: 14px; border-radius: var(--crisp-radius-full); border: 1px solid var(--crisp-border-default); box-sizing: border-box; }
3024
+ & .crisp-themepicker-option[data-selected] .crisp-themepicker-radio { border: 4px solid var(--crisp-bg-brand-solid); }
3025
+ }
3026
+
2812
3027
  .crisp-trialbanner {
2813
3028
  display: flex; align-items: center; gap: var(--crisp-space-1-5); box-sizing: border-box; min-height: 28px; padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-lg); font-family: var(--crisp-font-sans); font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
2814
3029
  & .crisp-trialbanner-icon { display: inline-flex; flex-shrink: 0; color: var(--crisp-fg-muted); }
package/dist/table.css CHANGED
@@ -1,15 +1,24 @@
1
1
  .crisp-table {
2
- display: block; box-sizing: border-box; background: var(--crisp-bg-surface);
3
- & .crisp-table-scroll { overflow-x: auto; }
2
+ display: block; box-sizing: border-box; background: var(--crisp-bg-surface); /* #554: both axes -- a consumer bounds the height via `scrollProps` (style/className on this element), and the header/footer below pin inside it exactly the way Attio's own grid does ("Both the header and
3
+ the summary row are sticky, on the scroll container rather than the
4
+ cells" -- docs/study/attio-table.md). Unbounded, `overflow: auto`
5
+ shows no vertical scrollbar and nothing sticks, so this is a no-op
6
+ for every existing consumer that never set a height. */
7
+ & .crisp-table-scroll { overflow: auto; }
4
8
  & table { width: 100%; border-collapse: separate; border-spacing: 0; font-family: var(--crisp-font-sans); font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
5
- /* #465: 12px, not crisp's old 8px -- measured on a live header cell
6
- (padding: 0 12px) and independently on a body cell's text inset (getBoundingClientRect delta from the cell edge). Matches ColumnCalc's own already-correct 12px trigger inset. */
9
+ /* #465: 12px, not crisp's old 8px -- measured on a live header cell (padding: 0 12px) and independently on a body cell's text inset
10
+ (getBoundingClientRect delta from the cell edge). Matches
11
+ ColumnCalc's own already-correct 12px trigger inset. */
7
12
  & th, & td { position: relative; height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-3); border-bottom: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); text-align: start; vertical-align: middle; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
8
- & th { height: var(--crisp-size-tableHeader); background: var(--crisp-bg-surface); border-top: 1px solid var(--crisp-border-subtle); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); letter-spacing: -0.14px; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); user-select: none; }
13
+ /* #554: sticky on the vertical axis, mirroring RecordsTable's own
14
+ `.crisp-recordstable-th`. z-index 2 sits above a plain body cell (auto)
15
+ and below a sticky-column corner cell (DataTable's `th[data-sticky]`, z-index 3), so the corner always wins. */
16
+ & th { position: sticky; top: 0; z-index: 2; height: var(--crisp-size-tableHeader); background: var(--crisp-bg-surface); border-top: 1px solid var(--crisp-border-subtle); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); letter-spacing: -0.14px; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); user-select: none; }
9
17
  & td { color: var(--crisp-fg-primary); background: var(--crisp-bg-surface); }
10
18
  & th:last-child, & td:last-child { border-inline-end: none; }
11
19
  & tbody tr:last-child td { border-bottom: none; }
12
- & tfoot td { border-top: 1px solid var(--crisp-border-subtle); border-bottom: 1px solid var(--crisp-border-subtle); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
20
+ /* #554: sticky to the bottom, mirroring `.crisp-recordstable-sum`. */
21
+ & tfoot td { position: sticky; bottom: 0; z-index: 2; border-top: 1px solid var(--crisp-border-subtle); border-bottom: 1px solid var(--crisp-border-subtle); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
13
22
  & caption { padding: var(--crisp-space-2) var(--crisp-space-2); text-align: start; font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); caption-side: bottom; }
14
23
  & td[data-align="right"], & th[data-align="right"] { text-align: end; }
15
24
  & td[data-align="center"], & th[data-align="center"] { text-align: center; }
@@ -1,16 +1,25 @@
1
1
  @layer crisp-components {
2
2
  .crisp-table {
3
- display: block; box-sizing: border-box; background: var(--crisp-bg-surface);
4
- & .crisp-table-scroll { overflow-x: auto; }
3
+ display: block; box-sizing: border-box; background: var(--crisp-bg-surface); /* #554: both axes -- a consumer bounds the height via `scrollProps` (style/className on this element), and the header/footer below pin inside it exactly the way Attio's own grid does ("Both the header and
4
+ the summary row are sticky, on the scroll container rather than the
5
+ cells" -- docs/study/attio-table.md). Unbounded, `overflow: auto`
6
+ shows no vertical scrollbar and nothing sticks, so this is a no-op
7
+ for every existing consumer that never set a height. */
8
+ & .crisp-table-scroll { overflow: auto; }
5
9
  & table { width: 100%; border-collapse: separate; border-spacing: 0; font-family: var(--crisp-font-sans); font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
6
- /* #465: 12px, not crisp's old 8px -- measured on a live header cell
7
- (padding: 0 12px) and independently on a body cell's text inset (getBoundingClientRect delta from the cell edge). Matches ColumnCalc's own already-correct 12px trigger inset. */
10
+ /* #465: 12px, not crisp's old 8px -- measured on a live header cell (padding: 0 12px) and independently on a body cell's text inset
11
+ (getBoundingClientRect delta from the cell edge). Matches
12
+ ColumnCalc's own already-correct 12px trigger inset. */
8
13
  & th, & td { position: relative; height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-3); border-bottom: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); text-align: start; vertical-align: middle; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
9
- & th { height: var(--crisp-size-tableHeader); background: var(--crisp-bg-surface); border-top: 1px solid var(--crisp-border-subtle); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); letter-spacing: -0.14px; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); user-select: none; }
14
+ /* #554: sticky on the vertical axis, mirroring RecordsTable's own
15
+ `.crisp-recordstable-th`. z-index 2 sits above a plain body cell (auto)
16
+ and below a sticky-column corner cell (DataTable's `th[data-sticky]`, z-index 3), so the corner always wins. */
17
+ & th { position: sticky; top: 0; z-index: 2; height: var(--crisp-size-tableHeader); background: var(--crisp-bg-surface); border-top: 1px solid var(--crisp-border-subtle); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); letter-spacing: -0.14px; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); user-select: none; }
10
18
  & td { color: var(--crisp-fg-primary); background: var(--crisp-bg-surface); }
11
19
  & th:last-child, & td:last-child { border-inline-end: none; }
12
20
  & tbody tr:last-child td { border-bottom: none; }
13
- & tfoot td { border-top: 1px solid var(--crisp-border-subtle); border-bottom: 1px solid var(--crisp-border-subtle); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
21
+ /* #554: sticky to the bottom, mirroring `.crisp-recordstable-sum`. */
22
+ & tfoot td { position: sticky; bottom: 0; z-index: 2; border-top: 1px solid var(--crisp-border-subtle); border-bottom: 1px solid var(--crisp-border-subtle); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
14
23
  & caption { padding: var(--crisp-space-2) var(--crisp-space-2); text-align: start; font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); caption-side: bottom; }
15
24
  & td[data-align="right"], & th[data-align="right"] { text-align: end; }
16
25
  & td[data-align="center"], & th[data-align="center"] { text-align: center; }
@@ -0,0 +1,23 @@
1
+ .crisp-taskstable {
2
+ display: flex; flex-direction: column; min-height: 0; box-sizing: border-box; font-family: var(--crisp-font-sans); color: var(--crisp-fg-primary); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
3
+ & .crisp-taskstable-colhead { display: flex; align-items: center; gap: var(--crisp-space-1-5); min-height: 49px; max-height: 49px; padding: var(--crisp-space-2-5) var(--crisp-space-3); box-shadow: inset 0 -1px 0 var(--crisp-border-subtle); font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); }
4
+ & .crisp-taskstable-colhead-cell { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; }
5
+ & .crisp-taskstable-row { display: flex; align-items: center; gap: var(--crisp-space-1-5); }
6
+ & .crisp-taskstable-cell { display: flex; align-items: center; min-width: 0; }
7
+ & .crisp-taskstable-check { appearance: none; -webkit-appearance: none; box-sizing: border-box; flex-shrink: 0; margin: 0; width: 16px; height: 16px; border: none; border-radius: var(--crisp-radius-full); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 9%, transparent); cursor: pointer; transition: background-color .12s, box-shadow .12s; }
8
+ & .crisp-taskstable-check:hover { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 30%, transparent); }
9
+ & .crisp-taskstable-check:checked { background: var(--crisp-bg-brand-solid) center / 10px no-repeat; box-shadow: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 6.5 5 9l4.5-5'/%3E%3C/svg%3E"); }
10
+ & .crisp-taskstable-check:focus-visible { outline: 2px solid var(--crisp-bg-brand-solid); outline-offset: 1px; }
11
+ & .crisp-taskstable-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
12
+ & .crisp-taskstable-due { font-size: var(--crisp-text-lg); color: var(--crisp-fg-muted); white-space: nowrap; }
13
+ & .crisp-taskstable-due[data-overdue] { color: var(--crisp-fg-danger); }
14
+ & .crisp-taskstable-empty { padding: var(--crisp-space-8) var(--crisp-space-4); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
15
+ }
16
+
17
+ @media (prefers-reduced-motion: reduce) {
18
+ .crisp-taskstable, .crisp-taskstable * {
19
+ animation-duration: 0.01ms !important;
20
+ animation-iteration-count: 1 !important;
21
+ transition-duration: 0.01ms !important;
22
+ }
23
+ }
@@ -0,0 +1,7 @@
1
+ import type { RecipeFn } from "../core/types";
2
+
3
+ export interface TaskstableVariants {
4
+
5
+ }
6
+
7
+ export declare const taskstableRecipe: RecipeFn<{ }>;
@@ -0,0 +1,25 @@
1
+ @layer crisp-components {
2
+ .crisp-taskstable {
3
+ display: flex; flex-direction: column; min-height: 0; box-sizing: border-box; font-family: var(--crisp-font-sans); color: var(--crisp-fg-primary); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
4
+ & .crisp-taskstable-colhead { display: flex; align-items: center; gap: var(--crisp-space-1-5); min-height: 49px; max-height: 49px; padding: var(--crisp-space-2-5) var(--crisp-space-3); box-shadow: inset 0 -1px 0 var(--crisp-border-subtle); font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); }
5
+ & .crisp-taskstable-colhead-cell { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; }
6
+ & .crisp-taskstable-row { display: flex; align-items: center; gap: var(--crisp-space-1-5); }
7
+ & .crisp-taskstable-cell { display: flex; align-items: center; min-width: 0; }
8
+ & .crisp-taskstable-check { appearance: none; -webkit-appearance: none; box-sizing: border-box; flex-shrink: 0; margin: 0; width: 16px; height: 16px; border: none; border-radius: var(--crisp-radius-full); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 9%, transparent); cursor: pointer; transition: background-color .12s, box-shadow .12s; }
9
+ & .crisp-taskstable-check:hover { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 30%, transparent); }
10
+ & .crisp-taskstable-check:checked { background: var(--crisp-bg-brand-solid) center / 10px no-repeat; box-shadow: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 6.5 5 9l4.5-5'/%3E%3C/svg%3E"); }
11
+ & .crisp-taskstable-check:focus-visible { outline: 2px solid var(--crisp-bg-brand-solid); outline-offset: 1px; }
12
+ & .crisp-taskstable-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
13
+ & .crisp-taskstable-due { font-size: var(--crisp-text-lg); color: var(--crisp-fg-muted); white-space: nowrap; }
14
+ & .crisp-taskstable-due[data-overdue] { color: var(--crisp-fg-danger); }
15
+ & .crisp-taskstable-empty { padding: var(--crisp-space-8) var(--crisp-space-4); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
16
+ }
17
+
18
+ @media (prefers-reduced-motion: reduce) {
19
+ .crisp-taskstable, .crisp-taskstable * {
20
+ animation-duration: 0.01ms !important;
21
+ animation-iteration-count: 1 !important;
22
+ transition-duration: 0.01ms !important;
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,27 @@
1
+ .crisp-themepicker {
2
+ display: flex; gap: var(--crisp-space-2); font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
3
+ & .crisp-themepicker-option { box-sizing: border-box; display: flex; flex-direction: column; align-items: center; gap: var(--crisp-space-1-5); width: 224px; padding: var(--crisp-space-1); border: 1px solid var(--crisp-border-subtle); border-radius: 16px; background: var(--crisp-bg-surface); cursor: pointer; font-family: inherit; }
4
+ & .crisp-themepicker-option[data-selected] { border-color: var(--crisp-bg-brand-solid); }
5
+ & .crisp-themepicker-preview { box-sizing: border-box; display: flex; width: 100%; height: 114px; padding: var(--crisp-space-2); gap: var(--crisp-space-1-5); border-radius: var(--crisp-radius-xl); overflow: hidden; }
6
+ & .crisp-themepicker-preview-side { flex-shrink: 0; width: 28%; display: flex; flex-direction: column; gap: var(--crisp-space-1); }
7
+ & .crisp-themepicker-preview-bar { height: 4px; border-radius: var(--crisp-radius-full); }
8
+ & .crisp-themepicker-preview-bar:nth-child(1) { width: 70%; background: var(--crisp-bg-brand-solid); }
9
+ & .crisp-themepicker-preview-bar:nth-child(2) { width: 90%; }
10
+ & .crisp-themepicker-preview-bar:nth-child(3) { width: 60%; }
11
+ & .crisp-themepicker-preview-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--crisp-space-1-5); padding: var(--crisp-space-1-5); border-radius: var(--crisp-radius-md); }
12
+ /* Light / System (default) swatch colours. */
13
+ & .crisp-themepicker-preview[data-swatch="light"], & .crisp-themepicker-preview[data-swatch="system"] { border: 1px solid #eeeff1; background: #fbfbfb; }
14
+ & [data-swatch="light"] .crisp-themepicker-preview-bar:not(:nth-child(1)), & [data-swatch="system"] .crisp-themepicker-preview-bar:not(:nth-child(1)) { background: #eeeff1; }
15
+ & [data-swatch="light"] .crisp-themepicker-preview-main, & [data-swatch="system"] .crisp-themepicker-preview-main { background: #ffffff; }
16
+ & [data-swatch="light"] .crisp-themepicker-preview-main .crisp-themepicker-preview-bar, & [data-swatch="system"] .crisp-themepicker-preview-main .crisp-themepicker-preview-bar { background: #eeeff1; }
17
+ /* Dark swatch colours -- always for "dark", and for "system" only when the OS itself reports dark. */
18
+ & .crisp-themepicker-preview[data-swatch="dark"] { border: 1px solid #1c1d1f; background: #0e0f10; }
19
+ & [data-swatch="dark"] .crisp-themepicker-preview-bar:not(:nth-child(1)) { background: #1c1d1f; }
20
+ & [data-swatch="dark"] .crisp-themepicker-preview-main { background: #0a0a0a; }
21
+ & [data-swatch="dark"] .crisp-themepicker-preview-main .crisp-themepicker-preview-bar { background: #1c1d1f; }
22
+ @media (prefers-color-scheme: dark) { & .crisp-themepicker-preview[data-swatch="system"] { border: 1px solid #1c1d1f; background: #0e0f10; } & [data-swatch="system"] .crisp-themepicker-preview-bar:not(:nth-child(1)) { background: #1c1d1f; } & [data-swatch="system"] .crisp-themepicker-preview-main { background: #0a0a0a; } & [data-swatch="system"] .crisp-themepicker-preview-main .crisp-themepicker-preview-bar { background: #1c1d1f; } }
23
+ & .crisp-themepicker-label { display: flex; align-items: center; gap: var(--crisp-space-1); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
24
+ & .crisp-themepicker-option[data-selected] .crisp-themepicker-label { color: var(--crisp-fg-primary); }
25
+ & .crisp-themepicker-radio { flex-shrink: 0; width: 14px; height: 14px; border-radius: var(--crisp-radius-full); border: 1px solid var(--crisp-border-default); box-sizing: border-box; }
26
+ & .crisp-themepicker-option[data-selected] .crisp-themepicker-radio { border: 4px solid var(--crisp-bg-brand-solid); }
27
+ }
@@ -0,0 +1,7 @@
1
+ import type { RecipeFn } from "../core/types";
2
+
3
+ export interface ThemepickerVariants {
4
+
5
+ }
6
+
7
+ export declare const themepickerRecipe: RecipeFn<{ }>;