@crisp-ui-kit/crisp 0.50.0 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/cjs/components/composewindow/composewindow.js +144 -0
  2. package/dist/cjs/components/composewindow/composewindow.recipe.js +45 -0
  3. package/dist/cjs/components/composewindow/index.js +8 -0
  4. package/dist/cjs/components/datatable/datatable.js +224 -43
  5. package/dist/cjs/components/datatable/datatable.recipe.js +37 -3
  6. package/dist/cjs/components/datatable/index.js +6 -0
  7. package/dist/cjs/components/datepickerfield/datepickerfield.js +25 -15
  8. package/dist/cjs/components/datepickerfield/datepickerfield.recipe.js +25 -8
  9. package/dist/cjs/components/dialog/dialog.recipe.js +9 -1
  10. package/dist/cjs/components/menu/menu.js +4 -2
  11. package/dist/cjs/components/multiselect/multiselect.recipe.js +14 -8
  12. package/dist/cjs/components/select/select.js +2 -1
  13. package/dist/cjs/components/table/table.recipe.js +12 -3
  14. package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +1 -1
  15. package/dist/cjs/components/tabletoolbar/tabletoolbar.js +18 -7
  16. package/dist/cjs/core/cell-date.js +11 -0
  17. package/dist/cjs/core/index.js +2 -1
  18. package/dist/cjs/index.js +1 -0
  19. package/dist/cjs/product/recordpage/recordpage.js +88 -10
  20. package/dist/cjs/product/recordpage/recordpage.recipe.js +30 -0
  21. package/dist/cjs/product/recordpanel/recordpanel.js +54 -4
  22. package/dist/cjs/product/recordpanel/recordpanel.recipe.js +29 -0
  23. package/dist/cjs/product/recordstable/editable-field.js +110 -0
  24. package/dist/cjs/product/recordstable/index.js +4 -1
  25. package/dist/cjs/product/recordstable/recordstable.js +67 -11
  26. package/dist/cjs/product/recordstable/recordstable.recipe.js +9 -1
  27. package/dist/cjs/product/settingsshell/settingsshell.recipe.js +13 -4
  28. package/dist/cjs/product/sidebar/sidebar.js +15 -3
  29. package/dist/cjs/product/sidebar/sidebar.recipe.js +21 -2
  30. package/dist/composewindow.css +24 -0
  31. package/dist/composewindow.d.ts +7 -0
  32. package/dist/composewindow.layered.css +26 -0
  33. package/dist/datatable.css +33 -14
  34. package/dist/datatable.layered.css +33 -14
  35. package/dist/datepickerfield.css +9 -4
  36. package/dist/datepickerfield.layered.css +9 -4
  37. package/dist/dialog.css +2 -1
  38. package/dist/dialog.layered.css +2 -1
  39. package/dist/esm/components/composewindow/composewindow.js +107 -0
  40. package/dist/esm/components/composewindow/composewindow.recipe.js +42 -0
  41. package/dist/esm/components/composewindow/index.js +2 -0
  42. package/dist/esm/components/datatable/datatable.js +226 -45
  43. package/dist/esm/components/datatable/datatable.recipe.js +37 -3
  44. package/dist/esm/components/datatable/index.js +6 -0
  45. package/dist/esm/components/datepickerfield/datepickerfield.js +26 -16
  46. package/dist/esm/components/datepickerfield/datepickerfield.recipe.js +25 -8
  47. package/dist/esm/components/dialog/dialog.recipe.js +9 -1
  48. package/dist/esm/components/menu/menu.js +4 -2
  49. package/dist/esm/components/multiselect/multiselect.recipe.js +14 -8
  50. package/dist/esm/components/select/select.js +2 -1
  51. package/dist/esm/components/table/table.recipe.js +12 -3
  52. package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +1 -1
  53. package/dist/esm/components/tabletoolbar/tabletoolbar.js +18 -7
  54. package/dist/esm/core/cell-date.js +10 -0
  55. package/dist/esm/core/index.js +1 -1
  56. package/dist/esm/index.js +1 -0
  57. package/dist/esm/product/recordpage/recordpage.js +89 -11
  58. package/dist/esm/product/recordpage/recordpage.recipe.js +30 -0
  59. package/dist/esm/product/recordpanel/recordpanel.js +55 -5
  60. package/dist/esm/product/recordpanel/recordpanel.recipe.js +29 -0
  61. package/dist/esm/product/recordstable/editable-field.js +73 -0
  62. package/dist/esm/product/recordstable/index.js +1 -0
  63. package/dist/esm/product/recordstable/recordstable.js +69 -13
  64. package/dist/esm/product/recordstable/recordstable.recipe.js +9 -1
  65. package/dist/esm/product/settingsshell/settingsshell.recipe.js +13 -4
  66. package/dist/esm/product/sidebar/sidebar.js +15 -3
  67. package/dist/esm/product/sidebar/sidebar.recipe.js +21 -2
  68. package/dist/multiselect.css +8 -8
  69. package/dist/multiselect.layered.css +8 -8
  70. package/dist/recordpage.css +25 -13
  71. package/dist/recordpage.layered.css +25 -13
  72. package/dist/recordpanel.css +22 -5
  73. package/dist/recordpanel.layered.css +22 -5
  74. package/dist/recordstable.css +9 -2
  75. package/dist/recordstable.layered.css +9 -2
  76. package/dist/settingsshell.css +2 -2
  77. package/dist/settingsshell.layered.css +2 -2
  78. package/dist/sidebar.css +7 -2
  79. package/dist/sidebar.layered.css +7 -2
  80. package/dist/styles.css +147 -54
  81. package/dist/styles.layered.css +147 -54
  82. package/dist/table.css +4 -2
  83. package/dist/table.layered.css +4 -2
  84. package/dist/tabletoolbar.css +1 -1
  85. package/dist/tabletoolbar.layered.css +1 -1
  86. package/dist/types/components/composewindow/composewindow.d.ts +80 -0
  87. package/dist/types/components/composewindow/composewindow.recipe.d.ts +3 -0
  88. package/dist/types/components/composewindow/index.d.ts +2 -0
  89. package/dist/types/components/datatable/datatable.d.ts +58 -4
  90. package/dist/types/components/datatable/index.d.ts +1 -1
  91. package/dist/types/components/datepickerfield/datepickerfield.d.ts +18 -4
  92. package/dist/types/components/menu/menu.d.ts +10 -1
  93. package/dist/types/components/select/select.d.ts +6 -1
  94. package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +29 -5
  95. package/dist/types/core/cell-date.d.ts +17 -0
  96. package/dist/types/core/index.d.ts +1 -1
  97. package/dist/types/index.d.ts +1 -0
  98. package/dist/types/product/recordpage/recordpage.d.ts +59 -1
  99. package/dist/types/product/recordpanel/recordpanel.d.ts +11 -1
  100. package/dist/types/product/recordstable/editable-field.d.ts +45 -0
  101. package/dist/types/product/recordstable/index.d.ts +1 -0
  102. package/dist/types/product/recordstable/recordstable.d.ts +29 -0
  103. package/dist/types/product/sidebar/sidebar.d.ts +60 -4
  104. package/package.json +6 -1
@@ -487,6 +487,31 @@
487
487
  }
488
488
  }
489
489
 
490
+ .crisp-composewindow {
491
+ display: contents; font-family: var(--crisp-font-sans);
492
+ & .crisp-composewindow-backdrop { position: fixed; inset: 0; z-index: 60; background: transparent; pointer-events: none; }
493
+ & .crisp-composewindow-positioner { position: fixed; inset: 0; z-index: 61; display: flex; align-items: flex-start; justify-content: center; padding: 15vh var(--crisp-space-4) var(--crisp-space-4); pointer-events: none; }
494
+ & .crisp-composewindow-content { pointer-events: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; position: relative; display: flex; flex-direction: column; box-sizing: border-box; width: 90vw; max-height: 74vh; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-2xl); background: color-mix(in srgb, var(--crisp-bg-overlay-frost) 60%, transparent); backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px); box-shadow: 0 8px 28px -6px var(--crisp-shadow-overlay1), 0 18px 88px -4px var(--crisp-shadow-overlay2), 0 0 1px var(--crisp-shadow-overlay3); opacity: 1; transform: scale(1); transition: opacity 0.2s ease, transform 0.2s ease; @starting-style { opacity: 0; transform: scale(0.97); } }
495
+ & .crisp-composewindow-content[data-minimized] { visibility: hidden; opacity: 0; }
496
+ & .crisp-composewindow-card { display: flex; flex-direction: column; flex: 1; min-height: 0; box-sizing: border-box; border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); box-shadow: 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); overflow: hidden; }
497
+ & .crisp-composewindow-header { display: flex; align-items: center; justify-content: space-between; gap: var(--crisp-space-2); flex-shrink: 0; height: 52px; padding: 0 var(--crisp-space-2) 0 var(--crisp-space-4); border-bottom: 1px solid var(--crisp-border-subtle); }
498
+ & .crisp-composewindow-breadcrumb { display: flex; align-items: center; gap: var(--crisp-space-1); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
499
+ & .crisp-composewindow-actions { display: flex; align-items: center; gap: var(--crisp-space-0-5); flex-shrink: 0; }
500
+ & .crisp-composewindow-action-btn { 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; }
501
+ & .crisp-composewindow-action-btn:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: var(--crisp-fg-primary); }
502
+ & .crisp-composewindow-action-btn[data-state="on"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: var(--crisp-bg-brand-solid); }
503
+ & .crisp-composewindow-body { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; padding: var(--crisp-space-5) var(--crisp-space-4); }
504
+ & .crisp-composewindow-content-body { display: flex; flex-direction: column; gap: var(--crisp-space-4); }
505
+ }
506
+
507
+ @media (prefers-reduced-motion: reduce) {
508
+ .crisp-composewindow, .crisp-composewindow * {
509
+ animation-duration: 0.01ms !important;
510
+ animation-iteration-count: 1 !important;
511
+ transition-duration: 0.01ms !important;
512
+ }
513
+ }
514
+
490
515
 
491
516
  /* pointer-events: auto (#375): a modal Dialog sets pointer-events: none
492
517
  on document.body while open (Zag re-enables it only on layers IT
@@ -549,10 +574,13 @@
549
574
  & .crisp-datatable-th-rename:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
550
575
  & .crisp-datatable-th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
551
576
  & .crisp-datatable-sort { display: flex; align-items: center; gap: var(--crisp-space-1-5); width: 100%; min-width: 0; height: 100%; margin: 0; padding: 0 var(--crisp-space-2); border: none; background: none; font: inherit; letter-spacing: inherit; color: inherit; text-align: start; cursor: pointer; }
552
- & th[data-align="right"] .crisp-datatable-sort { justify-content: flex-end; padding-inline-end: 0; }
553
- & th[data-align="right"] .crisp-datatable-th-inner { justify-content: flex-end; }
577
+ /* A right-aligned column's header keeps its field-icon + label packed at
578
+ the START, matching its own values only in that the VALUES right-align
579
+ -- Attio's own right-aligned header (measured live: "Twitter follower
580
+ count") keeps the icon+label left and only the trailing column-menu icon sits pinned to the right edge, independent of the label's width
581
+ (#406, reversing #393's own justify-content: flex-end here). The chevron's own margin-inline-start: auto below already pins IT to the
582
+ end of a flex-start row with no override needed -- that's what pins the trailing icon on Attio too. */
554
583
  & .crisp-datatable-chevron { margin-inline-start: auto; flex-shrink: 0; color: var(--crisp-fg-muted); opacity: 0; transition: opacity .12s; }
555
- & th[data-align="right"] .crisp-datatable-chevron { margin-inline-start: 0; order: -1; }
556
584
  & .crisp-datatable-sort:hover .crisp-datatable-chevron { opacity: 0.6; }
557
585
  & .crisp-datatable-sort[data-sorted] .crisp-datatable-chevron { opacity: 1; color: var(--crisp-fg-primary); }
558
586
  /* sticky first column(s) + horizontal scroll shadow — RecordsTable's feel */
@@ -575,6 +603,28 @@
575
603
  & .crisp-datatable-editable:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); cursor: text; }
576
604
  & .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; }
577
605
  & .crisp-datatable-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
606
+ /* An async onEdit's in-flight state (#385) -- the field/picker dims and
607
+ stops accepting input rather than disappearing, so the just-typed or
608
+ just-chosen value stays visible while its commit is pending. Same
609
+ treatment Input already gives its own disabled state. */
610
+ & .crisp-datatable-edit:disabled { opacity: 0.5; cursor: not-allowed; }
611
+ & .crisp-datatable-edit-pending { flex-shrink: 0; margin-inline-start: var(--crisp-space-1); color: var(--crisp-fg-muted); vertical-align: middle; }
612
+ /* The rejection's message, beside the cell's own content -- a sibling in
613
+ 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
614
+ it. Block-level: the row grows to fit it rather than floating over
615
+ the row below, so it can never end up clipped by the scroll
616
+ container's overflow the way a position:fixed escape would need guarding against. */
617
+ & .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); }
618
+ /* 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
619
+ shares RecordsTable's grid, Golden Rule 0). */
620
+ & .crisp-datatable-td--picker { padding: 0; }
621
+ & .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); }
622
+ & .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; }
623
+ & .crisp-datatable-td--picker .crisp-datatable-edit-error { padding-inline-start: var(--crisp-space-2); }
624
+ /* 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*. */
625
+ & .crisp-datatable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
626
+ & .crisp-datatable-refoption-avatar { flex-shrink: 0; }
627
+ & .crisp-datatable-refoption--create { color: var(--crisp-fg-muted); }
578
628
  & .crisp-datatable-empty { padding: var(--crisp-space-8) var(--crisp-space-3); text-align: center; color: var(--crisp-fg-muted); font-size: var(--crisp-text-lg); }
579
629
  /* fixed layout so column widths (and resize) are exact — like RecordsTable */
580
630
  & table { table-layout: fixed; }
@@ -586,12 +636,7 @@
586
636
  & .crisp-datatable-entity { display: flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; color: var(--crisp-fg-primary); font-weight: var(--crisp-weight-medium); }
587
637
  & .crisp-datatable-entity-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
588
638
  & .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); }
589
- & .crisp-datatable-avatar[data-tone="success"] { background: var(--crisp-bg-success); }
590
- & .crisp-datatable-avatar[data-tone="warning"] { background: var(--crisp-bg-warning); }
591
- & .crisp-datatable-avatar[data-tone="danger"] { background: var(--crisp-bg-danger); }
592
- & .crisp-datatable-avatar[data-tone="purple"] { background: var(--crisp-bg-purple); }
593
- & .crisp-datatable-avatar[data-tone="cyan"] { background: var(--crisp-bg-cyan); }
594
- & .crisp-datatable-avatar[data-tone="orange"] { background: var(--crisp-bg-orange); }
639
+ & .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); }
595
640
  & .crisp-datatable-avatar img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }
596
641
  & .crisp-datatable-tags { display: flex; align-items: center; gap: var(--crisp-space-1); overflow: hidden; }
597
642
  & .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); }
@@ -604,11 +649,10 @@
604
649
  & .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)); }
605
650
  & .crisp-datatable-num { font-variant-numeric: tabular-nums; }
606
651
  & .crisp-datatable-muted { color: var(--crisp-fg-muted); }
607
- /* row drag-to-reorder -- a Settings > Objects > Attributes screen measures a leading 20px grip column, a 16px grip icon, and the row's own
608
- hairline doubling as the drop indicator (it tints toward the brand
609
- colour as the active drop target). The affordance + geometry are
610
- 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
611
- pointer-events implementation. */
652
+ /* row drag-to-reorder -- a Settings > Objects > Attributes screen measures
653
+ 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
654
+ draggable + dataTransfer, the same one column reorder already uses
655
+ (RecordsTable's reorderColumn) -- not a proprietary pointer-events implementation. */
612
656
  & .crisp-datatable-col-grip { width: 20px; padding: 0; text-align: center; }
613
657
  & .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; }
614
658
  & .crisp-datatable-grip:active { cursor: grabbing; }
@@ -739,11 +783,16 @@
739
783
 
740
784
  .crisp-datepickerfield {
741
785
  display: inline-flex; font-family: var(--crisp-font-sans);
742
- & .crisp-datepickerfield-trigger { display: inline-flex; align-items: center; gap: var(--crisp-space-2); box-sizing: border-box; height: 32px; padding: 0 var(--crisp-space-2-5); margin: 0; border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 7%, transparent); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-lg); white-space: nowrap; cursor: pointer; }
743
- & .crisp-datepickerfield-trigger[data-ghost] { background: transparent; box-shadow: none; }
744
- & .crisp-datepickerfield-trigger[data-ghost]:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); }
745
- & .crisp-datepickerfield-trigger[data-placeholder] { color: var(--crisp-fg-muted); }
786
+ & .crisp-datepickerfield-box { display: inline-flex; align-items: center; box-sizing: border-box; height: 32px; margin: 0; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 7%, transparent); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-lg); }
787
+ & .crisp-datepickerfield-box[data-ghost] { background: transparent; box-shadow: none; }
788
+ & .crisp-datepickerfield-box[data-ghost]:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); }
789
+ & .crisp-datepickerfield-trigger { display: inline-flex; align-items: center; gap: var(--crisp-space-2); height: 100%; padding: 0 var(--crisp-space-2-5); margin: 0; border: none; background: none; color: inherit; font-family: inherit; font-size: inherit; white-space: nowrap; cursor: pointer; }
790
+ & .crisp-datepickerfield-box[data-placeholder] .crisp-datepickerfield-trigger { color: var(--crisp-fg-muted); }
746
791
  & .crisp-datepickerfield-trigger svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
792
+ /* Reuses TableToolbar's measured filter-chip remove button
793
+ (tabletoolbar.chrome.ts's .crisp-tabletoolbar-fchip-x) -- the same small inline "clear this value" affordance, not a freshly-measured one: no live Attio composition for a DatePickerField-equivalent clear was reachable this round (#394). */
794
+ & .crisp-datepickerfield-clear { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin-inline-end: var(--crisp-space-1); padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; color: var(--crisp-fg-muted); font-family: inherit; cursor: pointer; }
795
+ & .crisp-datepickerfield-clear:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 10%, transparent); color: var(--crisp-fg-primary); }
747
796
  & .crisp-datepickerfield-panel { padding: var(--crisp-space-2); width: 300px; }
748
797
  & .crisp-datepickerfield-presets { display: flex; flex-wrap: wrap; gap: var(--crisp-space-1); margin-top: var(--crisp-space-2); }
749
798
  & .crisp-datepickerfield-preset { height: var(--crisp-size-chip); padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-chip); background: var(--crisp-bg-raised); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-sm); cursor: pointer; }
@@ -767,7 +816,8 @@
767
816
  & .crisp-dialog-field-label { font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 50%, transparent); }
768
817
  & .crisp-dialog-more { display: inline-flex; align-items: center; gap: var(--crisp-space-2); margin-inline-end: auto; border: none; background: none; padding: 0; font-family: inherit; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); cursor: pointer; }
769
818
  & .crisp-dialog-submit { display: inline-flex; align-items: center; gap: var(--crisp-space-2); height: 28px; padding: 0 var(--crisp-space-1) 0 var(--crisp-space-2-5); border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-brand-solid); color: var(--crisp-fg-on-brand); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; }
770
- & .crisp-dialog-submit-key { display: inline-flex; align-items: center; justify-content: center; height: 18px; padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-sm); background: rgba(255,255,255,0.22); font-size: var(--crisp-text-xs); }
819
+ & .crisp-dialog-submit-key { display: inline-flex; align-items: center; gap: var(--crisp-space-1); }
820
+ & .crisp-dialog-submit-key kbd { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; padding: 0 3px; border-radius: 4px; background: transparent; color: var(--crisp-fg-on-brand); font-family: inherit; font-style: normal; font-size: 10px; }
771
821
  }
772
822
 
773
823
  @media (prefers-reduced-motion: reduce) {
@@ -1104,14 +1154,14 @@
1104
1154
  .crisp-multiselect-option[aria-selected="true"] .crisp-multiselect-check { background: var(--crisp-bg-brand-solid); box-shadow: none; color: #fff; }
1105
1155
  .crisp-multiselect-empty { padding: var(--crisp-space-3) var(--crisp-space-2); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
1106
1156
 
1107
- .crisp-recordstable-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; overflow: hidden; text-overflow: ellipsis; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); }
1108
- .crisp-recordstable-tag[data-tone="brand"] { 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)); }
1109
- .crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); }
1110
- .crisp-recordstable-tag[data-tone="warning"] { background: color-mix(in srgb, var(--crisp-bg-warning) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-warning) 82%, var(--crisp-fg-primary)); }
1111
- .crisp-recordstable-tag[data-tone="danger"] { background: color-mix(in srgb, var(--crisp-bg-danger) 15%, transparent); color: color-mix(in srgb, var(--crisp-bg-danger) 80%, var(--crisp-fg-primary)); }
1112
- .crisp-recordstable-tag[data-tone="purple"] { background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); }
1113
- .crisp-recordstable-tag[data-tone="cyan"] { background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); }
1114
- .crisp-recordstable-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)); }
1157
+ .crisp-recordstable-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; overflow: hidden; text-overflow: ellipsis; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); }
1158
+ .crisp-recordstable-tag[data-tone="brand"] { 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)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent); }
1159
+ .crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-success) 30%, transparent); }
1160
+ .crisp-recordstable-tag[data-tone="warning"] { background: color-mix(in srgb, var(--crisp-bg-warning) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-warning) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-warning) 30%, transparent); }
1161
+ .crisp-recordstable-tag[data-tone="danger"] { background: color-mix(in srgb, var(--crisp-bg-danger) 15%, transparent); color: color-mix(in srgb, var(--crisp-bg-danger) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-danger) 30%, transparent); }
1162
+ .crisp-recordstable-tag[data-tone="purple"] { background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-purple) 30%, transparent); }
1163
+ .crisp-recordstable-tag[data-tone="cyan"] { background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-cyan) 30%, transparent); }
1164
+ .crisp-recordstable-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)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent); }
1115
1165
 
1116
1166
  .crisp-multiselect {
1117
1167
  position: relative; display: inline-flex; width: 100%; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
@@ -1517,11 +1567,11 @@
1517
1567
  & .crisp-table-scroll { overflow-x: auto; }
1518
1568
  & 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); }
1519
1569
  & th, & td { position: relative; height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); 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; }
1520
- & th { height: var(--crisp-size-tableHeader); background: var(--crisp-bg-surface); 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; }
1570
+ & 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; }
1521
1571
  & td { color: var(--crisp-fg-primary); background: var(--crisp-bg-surface); }
1522
1572
  & th:last-child, & td:last-child { border-inline-end: none; }
1523
1573
  & tbody tr:last-child td { border-bottom: none; }
1524
- & tfoot td { border-top: 1px solid var(--crisp-border-subtle); border-bottom: none; font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
1574
+ & 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); }
1525
1575
  & 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; }
1526
1576
  & td[data-align="right"], & th[data-align="right"] { text-align: end; }
1527
1577
  & td[data-align="center"], & th[data-align="center"] { text-align: center; }
@@ -1535,6 +1585,8 @@
1535
1585
  }
1536
1586
  .crisp-table--surface_card {
1537
1587
  border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-xl); overflow: hidden;
1588
+ & th { border-top: none; }
1589
+ & tfoot td { border-bottom: none; }
1538
1590
  }
1539
1591
  .crisp-table--surface_bleed {
1540
1592
  border: none; border-radius: 0;
@@ -1557,7 +1609,7 @@
1557
1609
  & .crisp-tabletoolbar-search svg { flex-shrink: 0; }
1558
1610
  & .crisp-tabletoolbar-search input { border: none; outline: none; background: transparent; font-family: inherit; font-size: var(--crisp-text-md); color: var(--crisp-fg-primary); width: 180px; }
1559
1611
  & .crisp-tabletoolbar-search input::placeholder { color: var(--crisp-fg-muted); }
1560
- & .crisp-tabletoolbar-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; transition: background-color .12s; }
1612
+ & .crisp-tabletoolbar-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); 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; }
1561
1613
  & .crisp-tabletoolbar-tool:hover { background: var(--crisp-bg-raised); }
1562
1614
  & .crisp-tabletoolbar-tool svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
1563
1615
  & .crisp-tabletoolbar-tool--active { background: var(--crisp-bg-raised); }
@@ -2089,27 +2141,46 @@
2089
2141
  & .crisp-recordpage-field-label svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
2090
2142
  & .crisp-recordpage-field-label-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2091
2143
  & .crisp-recordpage-field-value { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); padding-top: 2px; line-height: 20px; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
2144
+ & .crisp-recordpage-field-value[data-editable] { cursor: pointer; }
2145
+ /* the click-to-edit trigger is a real <button> (keyboard-operable),
2146
+ reset back to plain inline text and made a flex-wrap container of its
2147
+ own -- FieldValue can render several chips (tags), which still need
2148
+ to wrap the way they did before this had a button around them at
2149
+ all. It wraps only FieldValue, never the error slot beside it (see
2150
+ the component's own comment) -- NOT `display: contents`, which drops a button's accessible semantics in some engines. */
2151
+ & .crisp-recordpage-edit-trigger { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); margin: 0; padding: 0; border: none; background: none; text-align: start; font: inherit; color: inherit; cursor: pointer; }
2092
2152
  & .crisp-recordpage-empty { color: var(--crisp-fg-muted); }
2153
+
2154
+ /* #431: measured live on app.attio.com's record page Details column -- clicking a field's value opens a plain, borderless field exactly
2155
+ filling the value's own box (no border, no background, no box-shadow), same font as the value it replaces (hence `font: inherit`, not a restated size/weight). A field row's own hover tint
2156
+ above already carries the "this is interactive" affordance; the
2157
+ pending/error treatment isn't Attio-measured -- it reuses the same tokens DataTable's identical states already use (opacity 0.5,
2158
+ `bgDanger`), per #385/#430. */
2159
+ & .crisp-recordpage-edit { display: block; width: 100%; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; box-shadow: none; outline: none; font: inherit; color: inherit; }
2160
+ /* not Attio-measured (its own field shows no focus ring either, caret
2161
+ only) -- kept for real keyboard users, the same brand ring every
2162
+ other crisp field already shows on focus (DataTable's identical .crisp-datatable-edit:focus, e.g.). */
2163
+ & .crisp-recordpage-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
2164
+ & .crisp-recordpage-edit:disabled { opacity: 0.5; cursor: not-allowed; }
2165
+ & .crisp-recordpage-edit-pending { flex-shrink: 0; color: var(--crisp-fg-muted); }
2166
+ & .crisp-recordpage-edit-error { flex-basis: 100%; margin-top: var(--crisp-space-0-5); font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
2167
+ & .crisp-recordpage-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; }
2168
+ & .crisp-recordpage-edit-picker .crisp-select-trigger { flex: 1; min-width: 0; }
2093
2169
  & .crisp-recordpage-link { color: var(--crisp-fg-primary); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
2094
2170
  & .crisp-recordpage-link:hover { text-decoration: underline; }
2095
2171
  & .crisp-recordpage-emptystate { padding: var(--crisp-space-2) var(--crisp-space-1); font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
2096
-
2097
2172
  & .crisp-recordpage-main { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; overflow-y: auto; padding: var(--crisp-space-3) var(--crisp-space-5); }
2098
-
2099
2173
  & .crisp-recordpage-panel { padding-top: var(--crisp-space-4); display: flex; flex-direction: column; gap: var(--crisp-space-4); }
2100
2174
  & .crisp-recordpage-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); background: var(--crisp-bg-surface); overflow: hidden; }
2101
2175
  & .crisp-recordpage-card-title { font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-semibold); letter-spacing: -0.14px; color: var(--crisp-fg-primary); padding: var(--crisp-space-3) var(--crisp-space-3) var(--crisp-space-2); }
2102
2176
  & .crisp-recordpage-hl-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); overflow: hidden; }
2103
- /* gap-as-gridlines: a 1px gap over the border colour draws dividers at any
2104
- column count, so the grid stays responsive (auto-fit) without per-cell
2105
- nth-child border hacks that break when the column count changes. */
2177
+ /* gap-as-gridlines: a 1px gap over the border colour draws dividers at any column count, so the grid stays responsive (auto-fit) without per-cell nth-child border hacks that break when the column count changes. */
2106
2178
  & .crisp-recordpage-hl-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1px; background: var(--crisp-border-subtle); }
2107
2179
  & .crisp-recordpage-hl-cell { position: relative; min-height: 84px; padding: var(--crisp-space-2-5) var(--crisp-space-3); background: var(--crisp-bg-surface); }
2108
2180
  & .crisp-recordpage-hl-icon { position: absolute; top: var(--crisp-space-2-5); inset-inline-end: var(--crisp-space-3); color: var(--crisp-fg-muted); }
2109
2181
  & .crisp-recordpage-hl-label { font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); margin-bottom: var(--crisp-space-2-5); padding-inline-end: var(--crisp-space-4); }
2110
2182
  & .crisp-recordpage-hl-value { display: flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
2111
2183
  & .crisp-recordpage-hl-value--empty { color: var(--crisp-fg-muted); font-weight: var(--crisp-weight-regular); }
2112
-
2113
2184
  & .crisp-recordpage-feed { display: flex; flex-direction: column; }
2114
2185
  & .crisp-recordpage-feed-item { display: flex; align-items: flex-start; gap: var(--crisp-space-2-5); padding: var(--crisp-space-2) 0; }
2115
2186
  & .crisp-recordpage-feed-dot { position: relative; display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; flex-shrink: 0; border-radius: var(--crisp-radius-full); background: var(--crisp-bg-raised); color: var(--crisp-fg-muted); }
@@ -2118,7 +2189,6 @@
2118
2189
  & .crisp-recordpage-feed-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); margin-top: 2px; }
2119
2190
  & .crisp-recordpage-feed-more { align-self: flex-start; margin-top: var(--crisp-space-1); border: none; background: none; padding: var(--crisp-space-1) 0; color: var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; }
2120
2191
  & .crisp-recordpage-feed-more:hover { text-decoration: underline; }
2121
-
2122
2192
  & .crisp-recordpage-section-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-1); }
2123
2193
  & .crisp-recordpage-section-head .crisp-recordpage-section-title { padding: 0; }
2124
2194
  & .crisp-recordpage-section-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) 6%, transparent); font-size: var(--crisp-text-xs); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
@@ -2126,7 +2196,6 @@
2126
2196
  & .crisp-recordpage-addbtn { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: 26px; padding: 0 var(--crisp-space-1-5); margin: 0; border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-ring-neutral), 0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; }
2127
2197
  & .crisp-recordpage-addbtn:hover { background: var(--crisp-bg-raised); }
2128
2198
  & .crisp-recordpage-addbtn svg { flex-shrink: 0; }
2129
-
2130
2199
  & .crisp-recordpage-composer { display: flex; flex-direction: column; gap: var(--crisp-space-2); padding: var(--crisp-space-2); border: 1px solid var(--crisp-border-default); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); margin-bottom: var(--crisp-space-2); }
2131
2200
  & .crisp-recordpage-composer textarea { width: 100%; min-height: 56px; resize: vertical; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
2132
2201
  & .crisp-recordpage-composer textarea:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); border-radius: var(--crisp-radius-md); }
@@ -2136,23 +2205,18 @@
2136
2205
  & .crisp-recordpage-btn:hover { background: var(--crisp-bg-raised); }
2137
2206
  & .crisp-recordpage-btn--primary { box-shadow: none; background: var(--crisp-bg-brand-solid); color: var(--crisp-fg-on-brand); }
2138
2207
  & .crisp-recordpage-btn--primary:disabled { opacity: 0.5; cursor: not-allowed; }
2139
-
2140
2208
  & .crisp-recordpage-note { display: flex; gap: var(--crisp-space-2-5); padding: var(--crisp-space-2-5) 0; border-top: 1px solid var(--crisp-border-subtle); }
2141
2209
  & .crisp-recordpage-note-body { flex: 1; min-width: 0; }
2142
2210
  & .crisp-recordpage-note-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); margin-bottom: var(--crisp-space-0-5); }
2143
2211
  & .crisp-recordpage-note-author { font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
2144
2212
  & .crisp-recordpage-note-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); }
2145
2213
  & .crisp-recordpage-note-text { font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); white-space: pre-wrap; word-break: break-word; }
2146
-
2147
2214
  & .crisp-recordpage-task { display: flex; align-items: flex-start; gap: var(--crisp-space-2); padding: var(--crisp-space-1-5) 0; border-top: 1px solid var(--crisp-border-subtle); }
2148
2215
  & .crisp-recordpage-task-text { flex: 1; min-width: 0; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); padding-top: 1px; }
2149
2216
  & .crisp-recordpage-task[data-done] .crisp-recordpage-task-text { text-decoration: line-through; color: var(--crisp-fg-muted); }
2150
-
2151
2217
  & .crisp-recordpage-emptycard { display: flex; flex-direction: column; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-6) var(--crisp-space-3); border: 1px dashed var(--crisp-border-default); border-radius: var(--crisp-radius-xl); color: var(--crisp-fg-muted); font-size: var(--crisp-text-md); text-align: center; }
2152
2218
  & .crisp-recordpage-emptycard svg { color: var(--crisp-fg-muted); opacity: 0.7; }
2153
-
2154
2219
  & .crisp-recordpage-action[data-active] svg { color: #f5b83d; fill: #f5b83d; }
2155
-
2156
2220
  & .crisp-recordstable-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); }
2157
2221
  & .crisp-recordstable-tag[data-tone="brand"] { 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)); }
2158
2222
  & .crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); }
@@ -2187,7 +2251,26 @@
2187
2251
  & .crisp-recordpanel-field-label { display: flex; align-items: center; gap: var(--crisp-space-1-5); width: 132px; flex-shrink: 0; padding-top: 3px; color: var(--crisp-fg-muted); font-size: var(--crisp-text-md); }
2188
2252
  & .crisp-recordpanel-field-label svg { flex-shrink: 0; }
2189
2253
  & .crisp-recordpanel-field-value { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); padding-top: 3px; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
2254
+ & .crisp-recordpanel-field-value[data-editable] { cursor: pointer; }
2255
+ /* the click-to-edit trigger is a real <button> (keyboard-operable), reset back to plain inline text and made a flex-wrap container of its own -- FieldValue can render several chips (tags), which still need to wrap the way they did before this had a button around them at all. It wraps only FieldValue, never the error slot beside it (see the component's own comment) -- NOT `display: contents`, which
2256
+ drops a button's accessible semantics in some engines. */
2257
+ & .crisp-recordpanel-edit-trigger { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); margin: 0; padding: 0; border: none; background: none; text-align: start; font: inherit; color: inherit; cursor: pointer; }
2190
2258
  & .crisp-recordpanel-empty { color: var(--crisp-fg-muted); }
2259
+ /* #431: measured live on app.attio.com's record side panel -- clicking a
2260
+ field's value opens a plain, borderless field exactly filling the value's own box (no border, no background, no box-shadow), same font
2261
+ as the value it replaces (hence `font: inherit`, not a restated
2262
+ size/weight). A field row's own hover tint above already carries the "this is interactive" affordance; the pending/error treatment isn't
2263
+ Attio-measured -- it reuses the same tokens DataTable's identical states already use (opacity 0.5, `bgDanger`), per #385/#430. */
2264
+ & .crisp-recordpanel-edit { display: block; width: 100%; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; box-shadow: none; outline: none; font: inherit; color: inherit; }
2265
+ /* not Attio-measured (its own field shows no focus ring either, caret only) -- kept for real keyboard users, the same brand ring every other crisp field already shows on focus (DataTable's identical
2266
+ .crisp-datatable-edit:focus, e.g.). */
2267
+ & .crisp-recordpanel-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
2268
+ & .crisp-recordpanel-edit:disabled { opacity: 0.5; cursor: not-allowed; }
2269
+ & .crisp-recordpanel-edit-pending { flex-shrink: 0; color: var(--crisp-fg-muted); }
2270
+ & .crisp-recordpanel-edit-error { flex-basis: 100%; margin-top: var(--crisp-space-0-5); font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
2271
+ & .crisp-recordpanel-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; }
2272
+ & .crisp-recordpanel-edit-picker .crisp-select-trigger { flex: 1; min-width: 0; }
2273
+
2191
2274
  & .crisp-recordstable-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); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); }
2192
2275
  & .crisp-recordstable-tag[data-tone="brand"] { 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)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent); }
2193
2276
  & .crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-success) 30%, transparent); }
@@ -2198,11 +2281,9 @@
2198
2281
  & .crisp-recordstable-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)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent); }
2199
2282
  & .crisp-recordpanel-link { color: var(--crisp-bg-brand-solid); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
2200
2283
  & .crisp-recordpanel-link:hover { text-decoration: underline; }
2201
- /* #329: an optional slot for record actions (e.g. Edit). Reuses the header's own measured values rather than inventing new ones -- the
2202
- same horizontal inset (space.3), the same hairline border token
2203
- (borderSubtle, flipped to border-top since this sits at the opposite
2204
- edge), and the header/body gap (space.2) for its own vertical padding
2205
- and for spacing between whatever it's given. */
2284
+
2285
+ /* #329: an optional slot for record actions (e.g. Edit). Reuses the
2286
+ header's own measured values rather than inventing new ones -- the same horizontal inset (space.3), the same hairline border token (borderSubtle, flipped to border-top since this sits at the opposite edge), and the header/body gap (space.2) for its own vertical padding and for spacing between whatever it's given. */
2206
2287
  & .crisp-recordpanel-footer { flex-shrink: 0; display: flex; align-items: center; gap: var(--crisp-space-2); padding: var(--crisp-space-2) var(--crisp-space-3); border-top: 1px solid var(--crisp-border-subtle); }
2207
2288
  }
2208
2289
 
@@ -2224,7 +2305,7 @@
2224
2305
  & .crisp-recordstable-search svg { flex-shrink: 0; }
2225
2306
  & .crisp-recordstable-search input { border: none; outline: none; background: transparent; font-family: inherit; font-size: var(--crisp-text-md); color: var(--crisp-fg-primary); width: 180px; }
2226
2307
  & .crisp-recordstable-search input::placeholder { color: var(--crisp-fg-muted); }
2227
- & .crisp-recordstable-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; transition: background-color .12s; }
2308
+ & .crisp-recordstable-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); 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; }
2228
2309
  & .crisp-recordstable-tool:hover { background: var(--crisp-bg-raised); }
2229
2310
  & .crisp-recordstable-tool svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
2230
2311
  & .crisp-recordstable-tool--active { background: var(--crisp-bg-raised); }
@@ -2328,6 +2409,13 @@
2328
2409
  & .crisp-recordstable-td--picker .crisp-multiselect-chips .crisp-recordstable-tag { flex-shrink: 0; max-width: none; }
2329
2410
  & .crisp-recordstable-td--picker .crisp-multiselect-chevron { display: none; }
2330
2411
  & .crisp-recordstable-td--picker .crisp-multiselect-placeholder { color: var(--crisp-fg-muted); }
2412
+ /* reference picker: a leading 16px avatar per option, plus a trailing
2413
+ "Create X" row when the consumer supplies one (#449) -- measured live
2414
+ against Attio's own picker (16px circular avatar, 16px plain icon for the create row, both sitting in the option's existing 8px gap, no new
2415
+ gap value invented). */
2416
+ & .crisp-recordstable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
2417
+ & .crisp-recordstable-refoption-avatar { flex-shrink: 0; }
2418
+ & .crisp-recordstable-refoption--create { color: var(--crisp-fg-muted); }
2331
2419
  & .crisp-recordstable-status { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; }
2332
2420
  & .crisp-recordstable-status-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: var(--crisp-radius-full); }
2333
2421
  & .crisp-recordstable-cell { display: flex; align-items: center; gap: var(--crisp-space-2); height: 100%; min-width: 0; }
@@ -2393,7 +2481,7 @@
2393
2481
  & .crisp-recordstable-empty { display: flex; align-items: center; justify-content: center; min-height: 320px; padding: var(--crisp-space-8) var(--crisp-space-4); }
2394
2482
 
2395
2483
  /* summary footer — per-column aggregation, sticky to the bottom */
2396
- & .crisp-recordstable-sum { position: sticky; bottom: 0; z-index: 2; height: var(--crisp-size-tableRow); padding: 0; border-top: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); background: var(--crisp-bg-surface); }
2484
+ & .crisp-recordstable-sum { position: sticky; bottom: 0; z-index: 2; height: var(--crisp-size-tableRow); padding: 0; border-top: 1px solid var(--crisp-border-subtle); border-bottom: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); background: var(--crisp-bg-surface); }
2397
2485
  & tfoot .crisp-recordstable-col-check, & tfoot .crisp-recordstable-col-entity { position: sticky; bottom: 0; z-index: 3; }
2398
2486
  & .crisp-recordstable-sum:last-child { border-inline-end: none; }
2399
2487
  & .crisp-recordstable-sum-btn { display: flex; align-items: center; justify-content: flex-end; gap: var(--crisp-space-1-5); width: 100%; height: 100%; margin: 0; padding: 0 var(--crisp-space-3); border: none; background: none; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); cursor: pointer; white-space: nowrap; overflow: hidden; }
@@ -2471,8 +2559,8 @@
2471
2559
  }
2472
2560
 
2473
2561
  .crisp-settingsshell {
2474
- display: flex; 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;
2475
- & .crisp-settingsshell-nav { display: flex; flex-direction: column; width: 256px; flex-shrink: 0; min-height: 0; padding: var(--crisp-space-3); border-inline-end: 1px solid var(--crisp-border-subtle); }
2562
+ display: flex; height: 100%; 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;
2563
+ & .crisp-settingsshell-nav { display: flex; flex-direction: column; width: 275px; flex-shrink: 0; min-height: 0; padding: var(--crisp-space-3); border-inline-end: 1px solid var(--crisp-border-subtle); }
2476
2564
  & .crisp-settingsshell-back { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: 28px; padding: 0 var(--crisp-space-1); margin: 0 0 var(--crisp-space-2); border: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-semibold); color: var(--crisp-fg-primary); cursor: pointer; border-radius: var(--crisp-radius-md); }
2477
2565
  & .crisp-settingsshell-back svg { color: var(--crisp-fg-muted); }
2478
2566
  & .crisp-settingsshell-back:hover svg { color: var(--crisp-fg-primary); }
@@ -2508,6 +2596,9 @@
2508
2596
  }
2509
2597
  }
2510
2598
 
2599
+
2600
+ .crisp-sidebar-ws-menu-content { width: 280px; }
2601
+
2511
2602
  .crisp-sidebar {
2512
2603
  box-sizing: border-box; display: flex; flex-direction: column; width: 275px; height: 100%; background: var(--crisp-bg-sidebar); border-inline-end: 1px solid var(--crisp-border-subtle); padding: var(--crisp-space-2); font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; overflow-y: auto;
2513
2604
  & .crisp-sidebar-section { display: flex; flex-direction: column; gap: var(--crisp-space-px); margin-top: var(--crisp-space-2); }
@@ -2516,10 +2607,12 @@
2516
2607
  & .crisp-sidebar-section-header { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; margin: 0; border: none; background: none; padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-0-5); font-family: var(--crisp-font-sans); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); cursor: pointer; }
2517
2608
  & .crisp-sidebar-section-header svg { flex-shrink: 0; transition: transform .15s ease; }
2518
2609
  & .crisp-sidebar-section-header[data-collapsed] svg { transform: rotate(-90deg); }
2519
- & .crisp-sidebar-ws { display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-header); padding: 0 var(--crisp-space-2); border-radius: var(--crisp-radius-lg); cursor: pointer; transition: background-color 0.16s; }
2610
+ & .crisp-sidebar-ws-row { display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-header); padding: 0 var(--crisp-space-2); }
2611
+ & .crisp-sidebar-ws-menuroot { display: flex; flex: 1; min-width: 0; }
2612
+ & .crisp-sidebar-ws { box-sizing: border-box; display: flex; align-items: center; gap: var(--crisp-space-2); flex: 1; min-width: 0; height: 100%; margin: 0; padding: 0; border: none; background: none; border-radius: var(--crisp-radius-lg); font-family: inherit; font-size: inherit; color: inherit; text-align: start; cursor: pointer; transition: background-color 0.16s; }
2520
2613
  & .crisp-sidebar-ws:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 5%, transparent); }
2521
2614
  & .crisp-sidebar-ws-name { font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-semibold); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2522
- & .crisp-sidebar-ws-collapse { margin-inline-start: auto; }
2615
+ & .crisp-sidebar-ws-collapse { flex-shrink: 0; }
2523
2616
  & .crisp-sidebar-searchrow { display: flex; align-items: center; gap: var(--crisp-space-1-5); margin-top: var(--crisp-space-2-5); padding-inline-end: var(--crisp-space-2); }
2524
2617
  & .crisp-sidebar-footer { margin-top: auto; display: flex; flex-direction: column; gap: var(--crisp-space-0-5); }
2525
2618
  & .crisp-sidebar-trial { display: flex; align-items: center; justify-content: space-between; gap: var(--crisp-space-2); padding: var(--crisp-space-1-5) var(--crisp-space-2); font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); }
package/dist/table.css CHANGED
@@ -3,11 +3,11 @@
3
3
  & .crisp-table-scroll { overflow-x: auto; }
4
4
  & 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
5
  & th, & td { position: relative; height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); 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; }
6
- & th { height: var(--crisp-size-tableHeader); background: var(--crisp-bg-surface); 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; }
6
+ & 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; }
7
7
  & td { color: var(--crisp-fg-primary); background: var(--crisp-bg-surface); }
8
8
  & th:last-child, & td:last-child { border-inline-end: none; }
9
9
  & tbody tr:last-child td { border-bottom: none; }
10
- & tfoot td { border-top: 1px solid var(--crisp-border-subtle); border-bottom: none; font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
10
+ & 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); }
11
11
  & 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; }
12
12
  & td[data-align="right"], & th[data-align="right"] { text-align: end; }
13
13
  & td[data-align="center"], & th[data-align="center"] { text-align: center; }
@@ -21,6 +21,8 @@
21
21
  }
22
22
  .crisp-table--surface_card {
23
23
  border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-xl); overflow: hidden;
24
+ & th { border-top: none; }
25
+ & tfoot td { border-bottom: none; }
24
26
  }
25
27
  .crisp-table--surface_bleed {
26
28
  border: none; border-radius: 0;
@@ -4,11 +4,11 @@
4
4
  & .crisp-table-scroll { overflow-x: auto; }
5
5
  & 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
6
  & th, & td { position: relative; height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); 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; }
7
- & th { height: var(--crisp-size-tableHeader); background: var(--crisp-bg-surface); 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; }
7
+ & 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; }
8
8
  & td { color: var(--crisp-fg-primary); background: var(--crisp-bg-surface); }
9
9
  & th:last-child, & td:last-child { border-inline-end: none; }
10
10
  & tbody tr:last-child td { border-bottom: none; }
11
- & tfoot td { border-top: 1px solid var(--crisp-border-subtle); border-bottom: none; font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
11
+ & 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); }
12
12
  & 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; }
13
13
  & td[data-align="right"], & th[data-align="right"] { text-align: end; }
14
14
  & td[data-align="center"], & th[data-align="center"] { text-align: center; }
@@ -22,6 +22,8 @@
22
22
  }
23
23
  .crisp-table--surface_card {
24
24
  border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-xl); overflow: hidden;
25
+ & th { border-top: none; }
26
+ & tfoot td { border-bottom: none; }
25
27
  }
26
28
  .crisp-table--surface_bleed {
27
29
  border: none; border-radius: 0;
@@ -7,7 +7,7 @@
7
7
  & .crisp-tabletoolbar-search svg { flex-shrink: 0; }
8
8
  & .crisp-tabletoolbar-search input { border: none; outline: none; background: transparent; font-family: inherit; font-size: var(--crisp-text-md); color: var(--crisp-fg-primary); width: 180px; }
9
9
  & .crisp-tabletoolbar-search input::placeholder { color: var(--crisp-fg-muted); }
10
- & .crisp-tabletoolbar-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; transition: background-color .12s; }
10
+ & .crisp-tabletoolbar-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); 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
11
  & .crisp-tabletoolbar-tool:hover { background: var(--crisp-bg-raised); }
12
12
  & .crisp-tabletoolbar-tool svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
13
13
  & .crisp-tabletoolbar-tool--active { background: var(--crisp-bg-raised); }
@@ -8,7 +8,7 @@
8
8
  & .crisp-tabletoolbar-search svg { flex-shrink: 0; }
9
9
  & .crisp-tabletoolbar-search input { border: none; outline: none; background: transparent; font-family: inherit; font-size: var(--crisp-text-md); color: var(--crisp-fg-primary); width: 180px; }
10
10
  & .crisp-tabletoolbar-search input::placeholder { color: var(--crisp-fg-muted); }
11
- & .crisp-tabletoolbar-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; transition: background-color .12s; }
11
+ & .crisp-tabletoolbar-tool { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px var(--crisp-border-default); 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-tabletoolbar-tool:hover { background: var(--crisp-bg-raised); }
13
13
  & .crisp-tabletoolbar-tool svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
14
14
  & .crisp-tabletoolbar-tool--active { background: var(--crisp-bg-raised); }
@@ -0,0 +1,80 @@
1
+ import * as React from "react";
2
+ export type ComposeWindowProps = Omit<React.ComponentPropsWithoutRef<"div">, "children"> & {
3
+ /** Controlled open state — `ComposeWindow` never manages this itself, the
4
+ * same controlled-only shape as `Dialog`/`Drawer`/`Command`. This is
5
+ * deliberate: crisp has no router dependency, so making the window fully
6
+ * controlled (this, and `minimized`/`pinned` below) is what lets a
7
+ * consumer sync it to a URL itself — the way Attio's own note window is
8
+ * addressable via `?id=…&modal=note` — without crisp owning any routing. */
9
+ open: boolean;
10
+ onOpenChange: (open: boolean) => void;
11
+ /** The header's leading area — typically a link to whatever record this
12
+ * window is attached to. Rendered as-is; crisp does not style its
13
+ * contents beyond spacing, since the exact breadcrumb chip inside it
14
+ * wasn't independently re-measured (see the component's own doc comment). */
15
+ breadcrumb?: React.ReactNode;
16
+ /** Minimized state. Omit for uncontrolled (see `defaultMinimized`). */
17
+ minimized?: boolean;
18
+ defaultMinimized?: boolean;
19
+ onMinimizedChange?: (minimized: boolean) => void;
20
+ /** Pinned state. While pinned, clicking outside the window does not close
21
+ * it. Omit for uncontrolled (see `defaultPinned`). */
22
+ pinned?: boolean;
23
+ defaultPinned?: boolean;
24
+ onPinnedChange?: (pinned: boolean) => void;
25
+ /** Content width in px (clamped to 90vw), matching `Dialog`'s own knob.
26
+ * Default 968 — Attio's own measured note window width. */
27
+ width?: number;
28
+ "aria-label"?: string;
29
+ minimizeLabel?: string;
30
+ pinLabel?: string;
31
+ closeLabel?: string;
32
+ children?: React.ReactNode;
33
+ };
34
+ /**
35
+ * A floating, minimizable, pinnable window — Attio's own note "compose
36
+ * window" chrome (measured live, read-only, 2026-09-24; see HANDOFF), not a
37
+ * new visual recipe: it reuses `Dialog`'s exact measured frosted-glass panel
38
+ * (`bgOverlayFrost` 60% + `blur(15px)`, `elevation.modal`'s 3-layer shadow,
39
+ * 16px outer radius) — those numbers matched Attio's compose window exactly
40
+ * when re-checked against it, panel-for-panel. What's actually different
41
+ * from `Dialog` is the header (a breadcrumb plus minimize/pin/close, not a
42
+ * title plus close) and two extra pieces of state Dialog has no concept of.
43
+ *
44
+ * `minimized` is measured, not guessed — the FIRST version of this file built
45
+ * an invented "minimized bar" (a Gmail-style dock, since a bar was never
46
+ * actually exercised against Attio). Re-measured properly: minimizing an
47
+ * existing note does not produce any bar, tray, dock, or badge anywhere on
48
+ * screen. Confirmed four independent ways, both with synthetic and real
49
+ * CDP-dispatched trusted clicks — the element count under the note's own
50
+ * subtree drops by ~110 nodes, `[role="dialog"]` stops matching it, its
51
+ * `data-hidden="true"` ancestor computes `visibility: hidden; opacity: 0`,
52
+ * and the URL drops the `?id=…&modal=note` query exactly like Close does —
53
+ * but the subtree is NOT removed: `document.querySelectorAll('[aria-label=
54
+ * "Minimize"]')` still finds it afterward, `visibility: hidden` (not
55
+ * `display: none`) preserves layout, and nothing in localStorage or the DOM
56
+ * suggests state was discarded. So: minimized hides the panel — mounted,
57
+ * `visibility: hidden; opacity: 0` — rather than unmounting or closing it,
58
+ * and crisp renders no restore affordance of its own (Attio has none
59
+ * either); reopening is the consumer's own UI, driven by `minimized`/
60
+ * `onMinimizedChange` the same way `open` already works.
61
+ *
62
+ * "Pinned" is implemented as the one directly-supported behavior that
63
+ * matches its name (Zag's `closeOnInteractOutside`, off while pinned) —
64
+ * Attio's own multi-instance stacking/docking when pinned was not exercised,
65
+ * so nothing here repositions the window when pinned.
66
+ *
67
+ * Not modal: Attio's own compose window dims nothing behind it (`Dialog`'s
68
+ * backdrop is `background: transparent` too — the blur alone does the
69
+ * separation), and the page behind stays visibly interactive in the
70
+ * measured screenshot. `trapFocus` follows the same call — a picture-in-
71
+ * picture window, not a modal, so Tab is not caught inside it.
72
+ */
73
+ export declare function ComposeWindow({ open, onOpenChange, breadcrumb, minimized: minimizedProp, defaultMinimized, onMinimizedChange, pinned: pinnedProp, defaultPinned, onPinnedChange, width, "aria-label": ariaLabel, minimizeLabel, pinLabel, closeLabel, children, className, style, "aria-describedby": describedBy, ...rest }: ComposeWindowProps): React.JSX.Element | null;
74
+ export declare namespace ComposeWindow {
75
+ var displayName: string;
76
+ }
77
+ export declare function ComposeWindowBody({ children, className, }: {
78
+ children?: React.ReactNode;
79
+ className?: string;
80
+ }): React.JSX.Element;
@@ -0,0 +1,3 @@
1
+ declare const config: import("../..").RecipeConfig<{}>;
2
+ export declare const composewindowRecipe: import("../..").RecipeFn<{}>;
3
+ export default config;
@@ -0,0 +1,2 @@
1
+ export { ComposeWindow, ComposeWindowBody, type ComposeWindowProps, } from "./composewindow";
2
+ export { composewindowRecipe } from "./composewindow.recipe";