@crisp-ui-kit/crisp 0.53.5 → 0.54.1

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 (124) 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/bulkbar/bulkbar.js +5 -1
  9. package/dist/cjs/components/fileupload/fileupload.js +19 -3
  10. package/dist/cjs/components/formfield/formfield.js +8 -1
  11. package/dist/cjs/components/heatmapchart/heatmapchart.js +14 -2
  12. package/dist/cjs/components/skiplink/index.js +17 -0
  13. package/dist/cjs/components/skiplink/skiplink.js +16 -0
  14. package/dist/cjs/components/skiplink/skiplink.recipe.js +33 -0
  15. package/dist/cjs/components/textlink/index.js +7 -0
  16. package/dist/cjs/components/textlink/textlink.js +16 -0
  17. package/dist/cjs/components/textlink/textlink.recipe.js +35 -0
  18. package/dist/cjs/components/visuallyhidden/index.js +17 -0
  19. package/dist/cjs/components/visuallyhidden/visuallyhidden.js +16 -0
  20. package/dist/cjs/components/visuallyhidden/visuallyhidden.recipe.js +20 -0
  21. package/dist/cjs/index.js +5 -0
  22. package/dist/cjs/product/activityfeed/activityfeed.js +38 -0
  23. package/dist/cjs/product/activityfeed/activityfeed.recipe.js +35 -0
  24. package/dist/cjs/product/activityfeed/index.js +10 -0
  25. package/dist/cjs/product/board/board.js +11 -2
  26. package/dist/cjs/product/command/command.js +13 -1
  27. package/dist/cjs/product/flowcanvas/flowcanvas.js +9 -2
  28. package/dist/cjs/product/headerbar/headerbar.js +15 -0
  29. package/dist/cjs/product/headerbar/headerbar.recipe.js +35 -0
  30. package/dist/cjs/product/headerbar/index.js +17 -0
  31. package/dist/cjs/product/inbox/inbox.js +13 -1
  32. package/dist/cjs/product/onboarding/onboarding.js +22 -1
  33. package/dist/cjs/product/recordpage/index.js +2 -1
  34. package/dist/cjs/product/recordpage/recordpage.js +197 -123
  35. package/dist/cjs/product/recordpage/recordpage.recipe.js +5 -0
  36. package/dist/cjs/product/richtext/richtext.js +43 -0
  37. package/dist/cjs/product/tasklist/tasklist.js +8 -1
  38. package/dist/cjs/tokens/palette.js +14 -0
  39. package/dist/cjs/tokens/semantic.js +5 -0
  40. package/dist/esm/components/badge/badge.recipe.js +10 -0
  41. package/dist/esm/components/bulkbar/bulkbar.js +5 -1
  42. package/dist/esm/components/fileupload/fileupload.js +20 -4
  43. package/dist/esm/components/formfield/formfield.js +8 -1
  44. package/dist/esm/components/heatmapchart/heatmapchart.js +14 -2
  45. package/dist/esm/components/skiplink/index.js +1 -0
  46. package/dist/esm/components/skiplink/skiplink.js +13 -0
  47. package/dist/esm/components/skiplink/skiplink.recipe.js +30 -0
  48. package/dist/esm/components/textlink/index.js +2 -0
  49. package/dist/esm/components/textlink/textlink.js +13 -0
  50. package/dist/esm/components/textlink/textlink.recipe.js +32 -0
  51. package/dist/esm/components/visuallyhidden/index.js +1 -0
  52. package/dist/esm/components/visuallyhidden/visuallyhidden.js +13 -0
  53. package/dist/esm/components/visuallyhidden/visuallyhidden.recipe.js +17 -0
  54. package/dist/esm/index.js +5 -0
  55. package/dist/esm/product/activityfeed/activityfeed.js +32 -0
  56. package/dist/esm/product/activityfeed/activityfeed.recipe.js +32 -0
  57. package/dist/esm/product/activityfeed/index.js +2 -0
  58. package/dist/esm/product/board/board.js +12 -3
  59. package/dist/esm/product/command/command.js +14 -2
  60. package/dist/esm/product/flowcanvas/flowcanvas.js +9 -2
  61. package/dist/esm/product/headerbar/headerbar.js +12 -0
  62. package/dist/esm/product/headerbar/headerbar.recipe.js +32 -0
  63. package/dist/esm/product/headerbar/index.js +1 -0
  64. package/dist/esm/product/inbox/inbox.js +13 -1
  65. package/dist/esm/product/onboarding/onboarding.js +22 -1
  66. package/dist/esm/product/recordpage/index.js +1 -1
  67. package/dist/esm/product/recordpage/recordpage.js +197 -124
  68. package/dist/esm/product/recordpage/recordpage.recipe.js +5 -0
  69. package/dist/esm/product/richtext/richtext.js +43 -0
  70. package/dist/esm/product/tasklist/tasklist.js +8 -1
  71. package/dist/esm/tokens/palette.js +14 -0
  72. package/dist/esm/tokens/semantic.js +5 -0
  73. package/dist/headerbar.css +7 -0
  74. package/dist/headerbar.d.ts +7 -0
  75. package/dist/headerbar.layered.css +9 -0
  76. package/dist/native/tokens.d.ts +1 -1
  77. package/dist/native/tokens.js +16 -4
  78. package/dist/recordpage.css +17 -31
  79. package/dist/recordpage.layered.css +17 -31
  80. package/dist/skiplink.css +5 -0
  81. package/dist/skiplink.d.ts +7 -0
  82. package/dist/skiplink.layered.css +7 -0
  83. package/dist/styles.css +69 -31
  84. package/dist/styles.layered.css +69 -31
  85. package/dist/textlink.css +11 -0
  86. package/dist/textlink.d.ts +7 -0
  87. package/dist/textlink.layered.css +13 -0
  88. package/dist/tokens.css +6 -0
  89. package/dist/tokens.json +16 -4
  90. package/dist/types/components/badge/badge.d.ts +2 -0
  91. package/dist/types/components/badge/badge.recipe.d.ts +8 -0
  92. package/dist/types/components/bulkbar/bulkbar.d.ts +1 -1
  93. package/dist/types/components/heatmapchart/heatmapchart.d.ts +1 -1
  94. package/dist/types/components/skiplink/index.d.ts +1 -0
  95. package/dist/types/components/skiplink/skiplink.d.ts +18 -0
  96. package/dist/types/components/skiplink/skiplink.recipe.d.ts +3 -0
  97. package/dist/types/components/textlink/index.d.ts +2 -0
  98. package/dist/types/components/textlink/textlink.d.ts +19 -0
  99. package/dist/types/components/textlink/textlink.recipe.d.ts +13 -0
  100. package/dist/types/components/visuallyhidden/index.d.ts +1 -0
  101. package/dist/types/components/visuallyhidden/visuallyhidden.d.ts +15 -0
  102. package/dist/types/components/visuallyhidden/visuallyhidden.recipe.d.ts +3 -0
  103. package/dist/types/index.d.ts +5 -0
  104. package/dist/types/product/activityfeed/activityfeed.d.ts +57 -0
  105. package/dist/types/product/activityfeed/activityfeed.recipe.d.ts +3 -0
  106. package/dist/types/product/activityfeed/index.d.ts +2 -0
  107. package/dist/types/product/board/board.d.ts +1 -1
  108. package/dist/types/product/command/command.d.ts +1 -1
  109. package/dist/types/product/flowcanvas/flowcanvas.d.ts +1 -1
  110. package/dist/types/product/headerbar/headerbar.d.ts +27 -0
  111. package/dist/types/product/headerbar/headerbar.recipe.d.ts +3 -0
  112. package/dist/types/product/headerbar/index.d.ts +1 -0
  113. package/dist/types/product/inbox/inbox.d.ts +1 -1
  114. package/dist/types/product/onboarding/onboarding.d.ts +1 -1
  115. package/dist/types/product/recordpage/index.d.ts +1 -1
  116. package/dist/types/product/recordpage/recordpage.d.ts +90 -1
  117. package/dist/types/product/tasklist/tasklist.d.ts +1 -1
  118. package/dist/types/tokens/contract.d.ts +3 -0
  119. package/dist/types/tokens/palette.d.ts +12 -0
  120. package/dist/types/tokens/semantic.d.ts +5 -0
  121. package/dist/visuallyhidden.css +3 -0
  122. package/dist/visuallyhidden.d.ts +7 -0
  123. package/dist/visuallyhidden.layered.css +5 -0
  124. package/package.json +26 -1
package/dist/styles.css CHANGED
@@ -45,6 +45,9 @@
45
45
  --crisp-fg-warning-soft: #80520d;
46
46
  --crisp-fg-danger-soft: #a33539;
47
47
  --crisp-fg-neutral-soft: #686870;
48
+ --crisp-bg-purple-soft: #f5f0ff;
49
+ --crisp-fg-purple-soft: #6238b5;
50
+ --crisp-ring-purple-soft: #e8ddfe;
48
51
  }
49
52
 
50
53
  [data-theme="dark"] {
@@ -94,6 +97,9 @@
94
97
  --crisp-fg-warning-soft: #e0982a;
95
98
  --crisp-fg-danger-soft: #ff5a5f;
96
99
  --crisp-fg-neutral-soft: #9a9aa2;
100
+ --crisp-bg-purple-soft: #f5f0ff;
101
+ --crisp-fg-purple-soft: #6238b5;
102
+ --crisp-ring-purple-soft: #e8ddfe;
97
103
  }
98
104
 
99
105
  :root {
@@ -224,6 +230,9 @@
224
230
  .crisp-badge--tone_danger {
225
231
  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);
226
232
  }
233
+ .crisp-badge--tone_purple {
234
+ background: var(--crisp-bg-purple-soft); color: var(--crisp-fg-purple-soft); box-shadow: inset 0 0 0 1px var(--crisp-ring-purple-soft);
235
+ }
227
236
  .crisp-badge--size_small {
228
237
  height: 16px; padding-inline: var(--crisp-space-1-5); font-size: var(--crisp-text-xs); border-radius: var(--crisp-radius-sm);
229
238
  }
@@ -1490,6 +1499,12 @@
1490
1499
  }
1491
1500
  }
1492
1501
 
1502
+ .crisp-skiplink {
1503
+ position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; text-decoration: none; font-family: var(--crisp-font-sans); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary);
1504
+ &:focus { position: fixed; top: var(--crisp-space-3); inset-inline-start: var(--crisp-space-3); z-index: 90; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; white-space: normal; padding: var(--crisp-space-2) var(--crisp-space-3); border-radius: var(--crisp-radius-md); background: var(--crisp-bg-popover); 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); }
1505
+ &:focus-visible { outline: 2px solid var(--crisp-bg-brand-solid); outline-offset: 1px; }
1506
+ }
1507
+
1493
1508
  .crisp-slider {
1494
1509
  display: flex; flex-direction: column; align-items: stretch; width: 100%; min-width: 0; gap: var(--crisp-space-0-5); font-family: var(--crisp-font-sans); user-select: none; touch-action: none; /* the position words ("minimum"/"maximum") that ARIA concatenates onto a thumb's name — read, never drawn */
1495
1510
  & .crisp-slider-thumblabel {
@@ -1784,6 +1799,18 @@
1784
1799
  }
1785
1800
  }
1786
1801
 
1802
+ .crisp-textlink {
1803
+ display: inline; font-family: var(--crisp-font-sans); text-decoration: none; cursor: pointer;
1804
+ &:hover { text-decoration: underline; }
1805
+ }
1806
+ .crisp-textlink--tone_brand {
1807
+ font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-bg-brand-solid);
1808
+ }
1809
+ .crisp-textlink--tone_muted {
1810
+ font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-regular); color: var(--crisp-fg-muted);
1811
+ &:hover { color: var(--crisp-bg-brand-solid); }
1812
+ }
1813
+
1787
1814
  .crisp-toast {
1788
1815
  display: contents; font-family: var(--crisp-font-sans);
1789
1816
  & .crisp-toast-viewport { position: fixed; z-index: 80; inset-inline-end: var(--crisp-space-4); top: var(--crisp-space-4); display: flex; flex-direction: column; gap: var(--crisp-space-2); width: 360px; max-width: calc(100vw - var(--crisp-space-8)); pointer-events: none; }
@@ -1823,6 +1850,10 @@
1823
1850
  }
1824
1851
  }
1825
1852
 
1853
+ .crisp-visuallyhidden {
1854
+ position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
1855
+ }
1856
+
1826
1857
  .crisp-wheelpicker {
1827
1858
  position: relative; box-sizing: border-box; width: 100%; overflow: hidden; background: var(--crisp-bg-surface); font-family: var(--crisp-font-sans); /* the band the selected row sits in; behind the items, never hit-tested */
1828
1859
  & .crisp-wheelpicker-indicator { position: absolute; z-index: 0; inset-inline: var(--crisp-space-4); top: 50%; transform: translateY(-50%); border-radius: var(--crisp-radius-md); background: var(--crisp-bg-neutral-weak); pointer-events: none; }
@@ -1847,6 +1878,19 @@
1847
1878
  & .crisp-wheelpicker-item { height: 44px; min-height: 44px; font-size: 26px; line-height: 35px; }
1848
1879
  }
1849
1880
 
1881
+ .crisp-activityfeed {
1882
+ 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);
1883
+ & .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); }
1884
+ & .crisp-activityfeed-row:last-of-type { border-bottom: none; padding-bottom: 0; }
1885
+ & .crisp-activityfeed-row-head { display: flex; align-items: center; gap: var(--crisp-space-2); }
1886
+ & .crisp-activityfeed-row-spacer { flex: 1; }
1887
+ & .crisp-activityfeed-row-when { font-size: var(--crisp-text-xs); color: var(--crisp-fg-muted); white-space: nowrap; }
1888
+ & .crisp-activityfeed-diff { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--crisp-space-1); }
1889
+ & .crisp-activityfeed-diff-item { padding-inline-start: var(--crisp-space-8); font-size: var(--crisp-text-md); }
1890
+ & .crisp-activityfeed-diff-field { color: var(--crisp-fg-muted); }
1891
+ & .crisp-activityfeed-diff-before { color: var(--crisp-fg-muted); text-decoration: line-through; }
1892
+ }
1893
+
1850
1894
  .crisp-appshell {
1851
1895
  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;
1852
1896
  & .crisp-appshell-side { position: relative; flex-shrink: 0; overflow: hidden; }
@@ -2019,6 +2063,14 @@
2019
2063
  & .crisp-flowcanvas-tool-sep { width: 1px; height: 18px; background: var(--crisp-border-subtle); }
2020
2064
  }
2021
2065
 
2066
+ .crisp-headerbar {
2067
+ 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;
2068
+ &[data-bordered] { border-bottom: 1px solid var(--crisp-border-subtle); }
2069
+ & .crisp-headerbar-leading { display: flex; align-items: center; gap: var(--crisp-space-2); flex-shrink: 0; min-width: 0; }
2070
+ & .crisp-headerbar-title { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--crisp-space-2); overflow: hidden; }
2071
+ & .crisp-headerbar-trailing { display: flex; align-items: center; gap: var(--crisp-space-2); flex-shrink: 0; }
2072
+ }
2073
+
2022
2074
  .crisp-inbox {
2023
2075
  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;
2024
2076
  & .crisp-inbox-head { padding: var(--crisp-space-3) var(--crisp-space-3) 0; }
@@ -2179,6 +2231,10 @@
2179
2231
  & .crisp-recordpage-detailsearch { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: var(--crisp-size-chip); flex-shrink: 0; padding: 0; margin: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; color: var(--crisp-fg-muted); font-family: inherit; cursor: pointer; transition: background-color .12s, color .12s; }
2180
2232
  & .crisp-recordpage-detailsearch:hover, & .crisp-recordpage-detailsearch[data-active] { background: var(--crisp-bg-raised); color: var(--crisp-fg-primary); }
2181
2233
  & .crisp-recordpage-noresults { padding: var(--crisp-space-1-5) var(--crisp-space-1); font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
2234
+ /* A caller-supplied `sections` grouping (#528) is not an Attio-measured
2235
+ shape (its own Details column is flat) -- this heading reuses
2236
+ .crisp-recordpage-section-title's own type treatment verbatim, just spaced from the group above it. */
2237
+ & .crisp-recordpage-fieldsection-title { margin-top: var(--crisp-space-3); }
2182
2238
  & .crisp-recordpage-morevalues { display: inline-flex; align-items: center; padding: 0; margin: 0; border: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-muted); cursor: pointer; }
2183
2239
  & .crisp-recordpage-morevalues:hover { color: var(--crisp-fg-primary); }
2184
2240
  & .crisp-recordpage-viewall { flex-basis: 100%; margin-top: var(--crisp-space-0-5); border: none; background: none; padding: 0; color: color-mix(in srgb, var(--crisp-fg-primary) 55%, transparent); font-family: inherit; font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-regular); cursor: pointer; text-align: start; }
@@ -2193,31 +2249,25 @@
2193
2249
  & .crisp-recordpage-field-label-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2194
2250
  & .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); }
2195
2251
  & .crisp-recordpage-field-value[data-editable] { cursor: pointer; }
2196
- /* the click-to-edit trigger is a real <button> (keyboard-operable),
2197
- reset back to plain inline text and made a flex-wrap container of its
2198
- own -- FieldValue can render several chips (tags), which still need
2199
- to wrap the way they did before this had a button around them at
2200
- all. It wraps only FieldValue, never the error slot beside it (see
2201
- the component's own comment) -- NOT `display: contents`, which drops a button's accessible semantics in some engines. */
2252
+ /* 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
2253
+ drops a button's accessible semantics in some engines. */
2202
2254
  & .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; }
2203
2255
  & .crisp-recordpage-empty { color: var(--crisp-fg-muted); }
2204
-
2205
- /* #431: measured live on app.attio.com's record page Details column -- clicking a field's value opens a plain, borderless field exactly
2206
- 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
2207
- above already carries the "this is interactive" affordance; the
2208
- pending/error treatment isn't Attio-measured -- it reuses the same tokens DataTable's identical states already use (opacity 0.5,
2209
- `bgDanger`), per #385/#430. */
2256
+ /* #431: measured live on app.attio.com's record page Details column --
2257
+ clicking a field's value opens a plain, borderless field exactly filling the value's own box (no border, no background, no
2258
+ box-shadow), same font as the value it replaces (hence `font:
2259
+ inherit`, not a restated size/weight). A field row's own hover tint above already carries the "this is interactive" affordance; the pending/error treatment isn't Attio-measured -- it reuses the same
2260
+ tokens DataTable's identical states already use (opacity 0.5, `bgDanger`), per #385/#430. */
2210
2261
  & .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; }
2211
- /* not Attio-measured (its own field shows no focus ring either, caret
2212
- only) -- kept for real keyboard users, the same brand ring every
2213
- other crisp field already shows on focus (DataTable's identical .crisp-datatable-edit:focus, e.g.). */
2262
+ /* 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
2263
+ .crisp-datatable-edit:focus, e.g.). */
2214
2264
  & .crisp-recordpage-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
2215
2265
  & .crisp-recordpage-edit:disabled { opacity: 0.5; cursor: not-allowed; }
2216
2266
  & .crisp-recordpage-edit-pending { flex-shrink: 0; color: var(--crisp-fg-muted); }
2217
2267
  & .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); }
2218
- /* #457: an `editor: "select"` field's at-rest chip -- same shape as
2219
- RecordsTable's own `.crisp-recordstable-status[-dot]` (already measured against Attio there), but its own classes: that pair is scoped under `.crisp-recordstable`'s own recipe root, so reusing the
2220
- classnames verbatim here would resolve to nothing. */
2268
+ /* #457: an `editor: "select"` field's at-rest chip -- same shape as RecordsTable's own `.crisp-recordstable-status[-dot]` (already
2269
+ measured against Attio there), but its own classes: that pair is
2270
+ scoped under `.crisp-recordstable`'s own recipe root, so reusing the classnames verbatim here would resolve to nothing. */
2221
2271
  & .crisp-recordpage-status { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; }
2222
2272
  & .crisp-recordpage-status-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: var(--crisp-radius-full); }
2223
2273
  & .crisp-recordpage-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; }
@@ -2225,23 +2275,18 @@
2225
2275
  & .crisp-recordpage-link { color: var(--crisp-fg-primary); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
2226
2276
  & .crisp-recordpage-link:hover { text-decoration: underline; }
2227
2277
  & .crisp-recordpage-emptystate { padding: var(--crisp-space-2) var(--crisp-space-1); font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
2228
-
2229
2278
  & .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); }
2230
-
2231
2279
  & .crisp-recordpage-panel { padding-top: var(--crisp-space-4); display: flex; flex-direction: column; gap: var(--crisp-space-4); }
2232
2280
  & .crisp-recordpage-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); background: var(--crisp-bg-surface); overflow: hidden; }
2233
2281
  & .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); }
2234
2282
  & .crisp-recordpage-hl-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); overflow: hidden; }
2235
- /* gap-as-gridlines: a 1px gap over the border colour draws dividers at any
2236
- column count, so the grid stays responsive (auto-fit) without per-cell
2237
- nth-child border hacks that break when the column count changes. */
2283
+ /* 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. */
2238
2284
  & .crisp-recordpage-hl-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1px; background: var(--crisp-border-subtle); }
2239
2285
  & .crisp-recordpage-hl-cell { position: relative; min-height: 84px; padding: var(--crisp-space-2-5) var(--crisp-space-3); background: var(--crisp-bg-surface); }
2240
2286
  & .crisp-recordpage-hl-icon { position: absolute; top: var(--crisp-space-2-5); inset-inline-end: var(--crisp-space-3); color: var(--crisp-fg-muted); }
2241
2287
  & .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); }
2242
2288
  & .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); }
2243
2289
  & .crisp-recordpage-hl-value--empty { color: var(--crisp-fg-muted); font-weight: var(--crisp-weight-regular); }
2244
-
2245
2290
  & .crisp-recordpage-feed { display: flex; flex-direction: column; }
2246
2291
  & .crisp-recordpage-feed-item { display: flex; align-items: flex-start; gap: var(--crisp-space-2-5); padding: var(--crisp-space-2) 0; }
2247
2292
  & .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); }
@@ -2250,7 +2295,6 @@
2250
2295
  & .crisp-recordpage-feed-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); margin-top: 2px; }
2251
2296
  & .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; }
2252
2297
  & .crisp-recordpage-feed-more:hover { text-decoration: underline; }
2253
-
2254
2298
  & .crisp-recordpage-section-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-1); }
2255
2299
  & .crisp-recordpage-section-head .crisp-recordpage-section-title { padding: 0; }
2256
2300
  & .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); }
@@ -2258,7 +2302,6 @@
2258
2302
  & .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; }
2259
2303
  & .crisp-recordpage-addbtn:hover { background: var(--crisp-bg-raised); }
2260
2304
  & .crisp-recordpage-addbtn svg { flex-shrink: 0; }
2261
-
2262
2305
  & .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); }
2263
2306
  & .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); }
2264
2307
  & .crisp-recordpage-composer textarea:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); border-radius: var(--crisp-radius-md); }
@@ -2268,23 +2311,18 @@
2268
2311
  & .crisp-recordpage-btn:hover { background: var(--crisp-bg-raised); }
2269
2312
  & .crisp-recordpage-btn--primary { box-shadow: none; background: var(--crisp-bg-brand-solid); color: var(--crisp-fg-on-brand); }
2270
2313
  & .crisp-recordpage-btn--primary:disabled { opacity: 0.5; cursor: not-allowed; }
2271
-
2272
2314
  & .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); }
2273
2315
  & .crisp-recordpage-note-body { flex: 1; min-width: 0; }
2274
2316
  & .crisp-recordpage-note-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); margin-bottom: var(--crisp-space-0-5); }
2275
2317
  & .crisp-recordpage-note-author { font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
2276
2318
  & .crisp-recordpage-note-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); }
2277
2319
  & .crisp-recordpage-note-text { font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); white-space: pre-wrap; word-break: break-word; }
2278
-
2279
2320
  & .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); }
2280
2321
  & .crisp-recordpage-task-text { flex: 1; min-width: 0; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); padding-top: 1px; }
2281
2322
  & .crisp-recordpage-task[data-done] .crisp-recordpage-task-text { text-decoration: line-through; color: var(--crisp-fg-muted); }
2282
-
2283
2323
  & .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; }
2284
2324
  & .crisp-recordpage-emptycard svg { color: var(--crisp-fg-muted); opacity: 0.7; }
2285
-
2286
2325
  & .crisp-recordpage-action[data-active] svg { color: #f5b83d; fill: #f5b83d; }
2287
-
2288
2326
  & .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); }
2289
2327
  & .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)); }
2290
2328
  & .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)); }
@@ -45,6 +45,9 @@
45
45
  --crisp-fg-warning-soft: #80520d;
46
46
  --crisp-fg-danger-soft: #a33539;
47
47
  --crisp-fg-neutral-soft: #686870;
48
+ --crisp-bg-purple-soft: #f5f0ff;
49
+ --crisp-fg-purple-soft: #6238b5;
50
+ --crisp-ring-purple-soft: #e8ddfe;
48
51
  }
49
52
 
50
53
  [data-theme="dark"] {
@@ -94,6 +97,9 @@
94
97
  --crisp-fg-warning-soft: #e0982a;
95
98
  --crisp-fg-danger-soft: #ff5a5f;
96
99
  --crisp-fg-neutral-soft: #9a9aa2;
100
+ --crisp-bg-purple-soft: #f5f0ff;
101
+ --crisp-fg-purple-soft: #6238b5;
102
+ --crisp-ring-purple-soft: #e8ddfe;
97
103
  }
98
104
 
99
105
  :root {
@@ -225,6 +231,9 @@
225
231
  .crisp-badge--tone_danger {
226
232
  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
233
  }
234
+ .crisp-badge--tone_purple {
235
+ background: var(--crisp-bg-purple-soft); color: var(--crisp-fg-purple-soft); box-shadow: inset 0 0 0 1px var(--crisp-ring-purple-soft);
236
+ }
228
237
  .crisp-badge--size_small {
229
238
  height: 16px; padding-inline: var(--crisp-space-1-5); font-size: var(--crisp-text-xs); border-radius: var(--crisp-radius-sm);
230
239
  }
@@ -1491,6 +1500,12 @@
1491
1500
  }
1492
1501
  }
1493
1502
 
1503
+ .crisp-skiplink {
1504
+ position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; text-decoration: none; font-family: var(--crisp-font-sans); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary);
1505
+ &:focus { position: fixed; top: var(--crisp-space-3); inset-inline-start: var(--crisp-space-3); z-index: 90; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; white-space: normal; padding: var(--crisp-space-2) var(--crisp-space-3); border-radius: var(--crisp-radius-md); background: var(--crisp-bg-popover); 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); }
1506
+ &:focus-visible { outline: 2px solid var(--crisp-bg-brand-solid); outline-offset: 1px; }
1507
+ }
1508
+
1494
1509
  .crisp-slider {
1495
1510
  display: flex; flex-direction: column; align-items: stretch; width: 100%; min-width: 0; gap: var(--crisp-space-0-5); font-family: var(--crisp-font-sans); user-select: none; touch-action: none; /* the position words ("minimum"/"maximum") that ARIA concatenates onto a thumb's name — read, never drawn */
1496
1511
  & .crisp-slider-thumblabel {
@@ -1785,6 +1800,18 @@
1785
1800
  }
1786
1801
  }
1787
1802
 
1803
+ .crisp-textlink {
1804
+ display: inline; font-family: var(--crisp-font-sans); text-decoration: none; cursor: pointer;
1805
+ &:hover { text-decoration: underline; }
1806
+ }
1807
+ .crisp-textlink--tone_brand {
1808
+ font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-bg-brand-solid);
1809
+ }
1810
+ .crisp-textlink--tone_muted {
1811
+ font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-regular); color: var(--crisp-fg-muted);
1812
+ &:hover { color: var(--crisp-bg-brand-solid); }
1813
+ }
1814
+
1788
1815
  .crisp-toast {
1789
1816
  display: contents; font-family: var(--crisp-font-sans);
1790
1817
  & .crisp-toast-viewport { position: fixed; z-index: 80; inset-inline-end: var(--crisp-space-4); top: var(--crisp-space-4); display: flex; flex-direction: column; gap: var(--crisp-space-2); width: 360px; max-width: calc(100vw - var(--crisp-space-8)); pointer-events: none; }
@@ -1824,6 +1851,10 @@
1824
1851
  }
1825
1852
  }
1826
1853
 
1854
+ .crisp-visuallyhidden {
1855
+ position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
1856
+ }
1857
+
1827
1858
  .crisp-wheelpicker {
1828
1859
  position: relative; box-sizing: border-box; width: 100%; overflow: hidden; background: var(--crisp-bg-surface); font-family: var(--crisp-font-sans); /* the band the selected row sits in; behind the items, never hit-tested */
1829
1860
  & .crisp-wheelpicker-indicator { position: absolute; z-index: 0; inset-inline: var(--crisp-space-4); top: 50%; transform: translateY(-50%); border-radius: var(--crisp-radius-md); background: var(--crisp-bg-neutral-weak); pointer-events: none; }
@@ -1848,6 +1879,19 @@
1848
1879
  & .crisp-wheelpicker-item { height: 44px; min-height: 44px; font-size: 26px; line-height: 35px; }
1849
1880
  }
1850
1881
 
1882
+ .crisp-activityfeed {
1883
+ 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);
1884
+ & .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); }
1885
+ & .crisp-activityfeed-row:last-of-type { border-bottom: none; padding-bottom: 0; }
1886
+ & .crisp-activityfeed-row-head { display: flex; align-items: center; gap: var(--crisp-space-2); }
1887
+ & .crisp-activityfeed-row-spacer { flex: 1; }
1888
+ & .crisp-activityfeed-row-when { font-size: var(--crisp-text-xs); color: var(--crisp-fg-muted); white-space: nowrap; }
1889
+ & .crisp-activityfeed-diff { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--crisp-space-1); }
1890
+ & .crisp-activityfeed-diff-item { padding-inline-start: var(--crisp-space-8); font-size: var(--crisp-text-md); }
1891
+ & .crisp-activityfeed-diff-field { color: var(--crisp-fg-muted); }
1892
+ & .crisp-activityfeed-diff-before { color: var(--crisp-fg-muted); text-decoration: line-through; }
1893
+ }
1894
+
1851
1895
  .crisp-appshell {
1852
1896
  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;
1853
1897
  & .crisp-appshell-side { position: relative; flex-shrink: 0; overflow: hidden; }
@@ -2020,6 +2064,14 @@
2020
2064
  & .crisp-flowcanvas-tool-sep { width: 1px; height: 18px; background: var(--crisp-border-subtle); }
2021
2065
  }
2022
2066
 
2067
+ .crisp-headerbar {
2068
+ 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;
2069
+ &[data-bordered] { border-bottom: 1px solid var(--crisp-border-subtle); }
2070
+ & .crisp-headerbar-leading { display: flex; align-items: center; gap: var(--crisp-space-2); flex-shrink: 0; min-width: 0; }
2071
+ & .crisp-headerbar-title { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--crisp-space-2); overflow: hidden; }
2072
+ & .crisp-headerbar-trailing { display: flex; align-items: center; gap: var(--crisp-space-2); flex-shrink: 0; }
2073
+ }
2074
+
2023
2075
  .crisp-inbox {
2024
2076
  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;
2025
2077
  & .crisp-inbox-head { padding: var(--crisp-space-3) var(--crisp-space-3) 0; }
@@ -2180,6 +2232,10 @@
2180
2232
  & .crisp-recordpage-detailsearch { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: var(--crisp-size-chip); flex-shrink: 0; padding: 0; margin: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; color: var(--crisp-fg-muted); font-family: inherit; cursor: pointer; transition: background-color .12s, color .12s; }
2181
2233
  & .crisp-recordpage-detailsearch:hover, & .crisp-recordpage-detailsearch[data-active] { background: var(--crisp-bg-raised); color: var(--crisp-fg-primary); }
2182
2234
  & .crisp-recordpage-noresults { padding: var(--crisp-space-1-5) var(--crisp-space-1); font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
2235
+ /* A caller-supplied `sections` grouping (#528) is not an Attio-measured
2236
+ shape (its own Details column is flat) -- this heading reuses
2237
+ .crisp-recordpage-section-title's own type treatment verbatim, just spaced from the group above it. */
2238
+ & .crisp-recordpage-fieldsection-title { margin-top: var(--crisp-space-3); }
2183
2239
  & .crisp-recordpage-morevalues { display: inline-flex; align-items: center; padding: 0; margin: 0; border: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-muted); cursor: pointer; }
2184
2240
  & .crisp-recordpage-morevalues:hover { color: var(--crisp-fg-primary); }
2185
2241
  & .crisp-recordpage-viewall { flex-basis: 100%; margin-top: var(--crisp-space-0-5); border: none; background: none; padding: 0; color: color-mix(in srgb, var(--crisp-fg-primary) 55%, transparent); font-family: inherit; font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-regular); cursor: pointer; text-align: start; }
@@ -2194,31 +2250,25 @@
2194
2250
  & .crisp-recordpage-field-label-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2195
2251
  & .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); }
2196
2252
  & .crisp-recordpage-field-value[data-editable] { cursor: pointer; }
2197
- /* the click-to-edit trigger is a real <button> (keyboard-operable),
2198
- reset back to plain inline text and made a flex-wrap container of its
2199
- own -- FieldValue can render several chips (tags), which still need
2200
- to wrap the way they did before this had a button around them at
2201
- all. It wraps only FieldValue, never the error slot beside it (see
2202
- the component's own comment) -- NOT `display: contents`, which drops a button's accessible semantics in some engines. */
2253
+ /* 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
2254
+ drops a button's accessible semantics in some engines. */
2203
2255
  & .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; }
2204
2256
  & .crisp-recordpage-empty { color: var(--crisp-fg-muted); }
2205
-
2206
- /* #431: measured live on app.attio.com's record page Details column -- clicking a field's value opens a plain, borderless field exactly
2207
- 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
2208
- above already carries the "this is interactive" affordance; the
2209
- pending/error treatment isn't Attio-measured -- it reuses the same tokens DataTable's identical states already use (opacity 0.5,
2210
- `bgDanger`), per #385/#430. */
2257
+ /* #431: measured live on app.attio.com's record page Details column --
2258
+ clicking a field's value opens a plain, borderless field exactly filling the value's own box (no border, no background, no
2259
+ box-shadow), same font as the value it replaces (hence `font:
2260
+ inherit`, not a restated size/weight). A field row's own hover tint above already carries the "this is interactive" affordance; the pending/error treatment isn't Attio-measured -- it reuses the same
2261
+ tokens DataTable's identical states already use (opacity 0.5, `bgDanger`), per #385/#430. */
2211
2262
  & .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; }
2212
- /* not Attio-measured (its own field shows no focus ring either, caret
2213
- only) -- kept for real keyboard users, the same brand ring every
2214
- other crisp field already shows on focus (DataTable's identical .crisp-datatable-edit:focus, e.g.). */
2263
+ /* 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
2264
+ .crisp-datatable-edit:focus, e.g.). */
2215
2265
  & .crisp-recordpage-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
2216
2266
  & .crisp-recordpage-edit:disabled { opacity: 0.5; cursor: not-allowed; }
2217
2267
  & .crisp-recordpage-edit-pending { flex-shrink: 0; color: var(--crisp-fg-muted); }
2218
2268
  & .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); }
2219
- /* #457: an `editor: "select"` field's at-rest chip -- same shape as
2220
- RecordsTable's own `.crisp-recordstable-status[-dot]` (already measured against Attio there), but its own classes: that pair is scoped under `.crisp-recordstable`'s own recipe root, so reusing the
2221
- classnames verbatim here would resolve to nothing. */
2269
+ /* #457: an `editor: "select"` field's at-rest chip -- same shape as RecordsTable's own `.crisp-recordstable-status[-dot]` (already
2270
+ measured against Attio there), but its own classes: that pair is
2271
+ scoped under `.crisp-recordstable`'s own recipe root, so reusing the classnames verbatim here would resolve to nothing. */
2222
2272
  & .crisp-recordpage-status { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; }
2223
2273
  & .crisp-recordpage-status-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: var(--crisp-radius-full); }
2224
2274
  & .crisp-recordpage-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; }
@@ -2226,23 +2276,18 @@
2226
2276
  & .crisp-recordpage-link { color: var(--crisp-fg-primary); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
2227
2277
  & .crisp-recordpage-link:hover { text-decoration: underline; }
2228
2278
  & .crisp-recordpage-emptystate { padding: var(--crisp-space-2) var(--crisp-space-1); font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
2229
-
2230
2279
  & .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); }
2231
-
2232
2280
  & .crisp-recordpage-panel { padding-top: var(--crisp-space-4); display: flex; flex-direction: column; gap: var(--crisp-space-4); }
2233
2281
  & .crisp-recordpage-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); background: var(--crisp-bg-surface); overflow: hidden; }
2234
2282
  & .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); }
2235
2283
  & .crisp-recordpage-hl-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); overflow: hidden; }
2236
- /* gap-as-gridlines: a 1px gap over the border colour draws dividers at any
2237
- column count, so the grid stays responsive (auto-fit) without per-cell
2238
- nth-child border hacks that break when the column count changes. */
2284
+ /* 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. */
2239
2285
  & .crisp-recordpage-hl-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1px; background: var(--crisp-border-subtle); }
2240
2286
  & .crisp-recordpage-hl-cell { position: relative; min-height: 84px; padding: var(--crisp-space-2-5) var(--crisp-space-3); background: var(--crisp-bg-surface); }
2241
2287
  & .crisp-recordpage-hl-icon { position: absolute; top: var(--crisp-space-2-5); inset-inline-end: var(--crisp-space-3); color: var(--crisp-fg-muted); }
2242
2288
  & .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); }
2243
2289
  & .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); }
2244
2290
  & .crisp-recordpage-hl-value--empty { color: var(--crisp-fg-muted); font-weight: var(--crisp-weight-regular); }
2245
-
2246
2291
  & .crisp-recordpage-feed { display: flex; flex-direction: column; }
2247
2292
  & .crisp-recordpage-feed-item { display: flex; align-items: flex-start; gap: var(--crisp-space-2-5); padding: var(--crisp-space-2) 0; }
2248
2293
  & .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); }
@@ -2251,7 +2296,6 @@
2251
2296
  & .crisp-recordpage-feed-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); margin-top: 2px; }
2252
2297
  & .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; }
2253
2298
  & .crisp-recordpage-feed-more:hover { text-decoration: underline; }
2254
-
2255
2299
  & .crisp-recordpage-section-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-1); }
2256
2300
  & .crisp-recordpage-section-head .crisp-recordpage-section-title { padding: 0; }
2257
2301
  & .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); }
@@ -2259,7 +2303,6 @@
2259
2303
  & .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; }
2260
2304
  & .crisp-recordpage-addbtn:hover { background: var(--crisp-bg-raised); }
2261
2305
  & .crisp-recordpage-addbtn svg { flex-shrink: 0; }
2262
-
2263
2306
  & .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); }
2264
2307
  & .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); }
2265
2308
  & .crisp-recordpage-composer textarea:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); border-radius: var(--crisp-radius-md); }
@@ -2269,23 +2312,18 @@
2269
2312
  & .crisp-recordpage-btn:hover { background: var(--crisp-bg-raised); }
2270
2313
  & .crisp-recordpage-btn--primary { box-shadow: none; background: var(--crisp-bg-brand-solid); color: var(--crisp-fg-on-brand); }
2271
2314
  & .crisp-recordpage-btn--primary:disabled { opacity: 0.5; cursor: not-allowed; }
2272
-
2273
2315
  & .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); }
2274
2316
  & .crisp-recordpage-note-body { flex: 1; min-width: 0; }
2275
2317
  & .crisp-recordpage-note-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); margin-bottom: var(--crisp-space-0-5); }
2276
2318
  & .crisp-recordpage-note-author { font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
2277
2319
  & .crisp-recordpage-note-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); }
2278
2320
  & .crisp-recordpage-note-text { font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); white-space: pre-wrap; word-break: break-word; }
2279
-
2280
2321
  & .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); }
2281
2322
  & .crisp-recordpage-task-text { flex: 1; min-width: 0; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); padding-top: 1px; }
2282
2323
  & .crisp-recordpage-task[data-done] .crisp-recordpage-task-text { text-decoration: line-through; color: var(--crisp-fg-muted); }
2283
-
2284
2324
  & .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; }
2285
2325
  & .crisp-recordpage-emptycard svg { color: var(--crisp-fg-muted); opacity: 0.7; }
2286
-
2287
2326
  & .crisp-recordpage-action[data-active] svg { color: #f5b83d; fill: #f5b83d; }
2288
-
2289
2327
  & .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); }
2290
2328
  & .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)); }
2291
2329
  & .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)); }
@@ -0,0 +1,11 @@
1
+ .crisp-textlink {
2
+ display: inline; font-family: var(--crisp-font-sans); text-decoration: none; cursor: pointer;
3
+ &:hover { text-decoration: underline; }
4
+ }
5
+ .crisp-textlink--tone_brand {
6
+ font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-bg-brand-solid);
7
+ }
8
+ .crisp-textlink--tone_muted {
9
+ font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-regular); color: var(--crisp-fg-muted);
10
+ &:hover { color: var(--crisp-bg-brand-solid); }
11
+ }
@@ -0,0 +1,7 @@
1
+ import type { RecipeFn } from "../core/types";
2
+
3
+ export interface TextlinkVariants {
4
+ tone?: "brand" | "muted";
5
+ }
6
+
7
+ export declare const textlinkRecipe: RecipeFn<{ tone: { brand: string; muted: string } }>;
@@ -0,0 +1,13 @@
1
+ @layer crisp-components {
2
+ .crisp-textlink {
3
+ display: inline; font-family: var(--crisp-font-sans); text-decoration: none; cursor: pointer;
4
+ &:hover { text-decoration: underline; }
5
+ }
6
+ .crisp-textlink--tone_brand {
7
+ font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-bg-brand-solid);
8
+ }
9
+ .crisp-textlink--tone_muted {
10
+ font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-regular); color: var(--crisp-fg-muted);
11
+ &:hover { color: var(--crisp-bg-brand-solid); }
12
+ }
13
+ }
package/dist/tokens.css CHANGED
@@ -45,6 +45,9 @@
45
45
  --crisp-fg-warning-soft: #80520d;
46
46
  --crisp-fg-danger-soft: #a33539;
47
47
  --crisp-fg-neutral-soft: #686870;
48
+ --crisp-bg-purple-soft: #f5f0ff;
49
+ --crisp-fg-purple-soft: #6238b5;
50
+ --crisp-ring-purple-soft: #e8ddfe;
48
51
  }
49
52
 
50
53
  [data-theme="dark"] {
@@ -94,6 +97,9 @@
94
97
  --crisp-fg-warning-soft: #e0982a;
95
98
  --crisp-fg-danger-soft: #ff5a5f;
96
99
  --crisp-fg-neutral-soft: #9a9aa2;
100
+ --crisp-bg-purple-soft: #f5f0ff;
101
+ --crisp-fg-purple-soft: #6238b5;
102
+ --crisp-ring-purple-soft: #e8ddfe;
97
103
  }
98
104
 
99
105
  :root {
package/dist/tokens.json CHANGED
@@ -46,7 +46,10 @@
46
46
  "fgSuccessSoft": "#186b3d",
47
47
  "fgWarningSoft": "#80520d",
48
48
  "fgDangerSoft": "#a33539",
49
- "fgNeutralSoft": "#686870"
49
+ "fgNeutralSoft": "#686870",
50
+ "bgPurpleSoft": "#f5f0ff",
51
+ "fgPurpleSoft": "#6238b5",
52
+ "ringPurpleSoft": "#e8ddfe"
50
53
  },
51
54
  "dark": {
52
55
  "bgBrandSolid": "#266df0",
@@ -94,7 +97,10 @@
94
97
  "fgSuccessSoft": "#2ea968",
95
98
  "fgWarningSoft": "#e0982a",
96
99
  "fgDangerSoft": "#ff5a5f",
97
- "fgNeutralSoft": "#9a9aa2"
100
+ "fgNeutralSoft": "#9a9aa2",
101
+ "bgPurpleSoft": "#f5f0ff",
102
+ "fgPurpleSoft": "#6238b5",
103
+ "ringPurpleSoft": "#e8ddfe"
98
104
  }
99
105
  },
100
106
  "palette": {
@@ -143,7 +149,10 @@
143
149
  "softSuccessText": "#186b3d",
144
150
  "softWarningText": "#80520d",
145
151
  "softDangerText": "#a33539",
146
- "softNeutralText": "#686870"
152
+ "softNeutralText": "#686870",
153
+ "purpleTint": "#f5f0ff",
154
+ "softPurpleText": "#6238b5",
155
+ "purpleRing": "#e8ddfe"
147
156
  },
148
157
  "dark": {
149
158
  "gray00": "#0a0a0a",
@@ -190,7 +199,10 @@
190
199
  "softSuccessText": "#2ea968",
191
200
  "softWarningText": "#e0982a",
192
201
  "softDangerText": "#ff5a5f",
193
- "softNeutralText": "#9a9aa2"
202
+ "softNeutralText": "#9a9aa2",
203
+ "purpleTint": "#f5f0ff",
204
+ "softPurpleText": "#6238b5",
205
+ "purpleRing": "#e8ddfe"
194
206
  }
195
207
  },
196
208
  "space": {
@@ -13,6 +13,7 @@ export declare const Badge: React.ForwardRefExoticComponent<Omit<React.DetailedH
13
13
  readonly success: string;
14
14
  readonly warning: string;
15
15
  readonly danger: string;
16
+ readonly purple: string;
16
17
  };
17
18
  readonly size: {
18
19
  readonly small: string;
@@ -31,6 +32,7 @@ export declare const Badge: React.ForwardRefExoticComponent<Omit<React.DetailedH
31
32
  readonly success: string;
32
33
  readonly warning: string;
33
34
  readonly danger: string;
35
+ readonly purple: string;
34
36
  };
35
37
  readonly size: {
36
38
  readonly small: string;
@@ -48,6 +48,11 @@ declare const spec: {
48
48
  color: `var(--${string})`;
49
49
  boxShadow: string;
50
50
  };
51
+ readonly purple: {
52
+ readonly background: `var(--${string})`;
53
+ readonly color: `var(--${string})`;
54
+ readonly boxShadow: `inset 0 0 0 1px var(--${string})`;
55
+ };
51
56
  };
52
57
  readonly size: {
53
58
  readonly small: {
@@ -128,6 +133,7 @@ declare const config: import("../..").RecipeConfig<{
128
133
  readonly success: string;
129
134
  readonly warning: string;
130
135
  readonly danger: string;
136
+ readonly purple: string;
131
137
  };
132
138
  readonly size: {
133
139
  readonly small: string;
@@ -146,6 +152,7 @@ export declare const badgeRecipe: import("../..").RecipeFn<{
146
152
  readonly success: string;
147
153
  readonly warning: string;
148
154
  readonly danger: string;
155
+ readonly purple: string;
149
156
  };
150
157
  readonly size: {
151
158
  readonly small: string;
@@ -164,6 +171,7 @@ export declare const badgeRecipe: import("../..").RecipeFn<{
164
171
  readonly success: string;
165
172
  readonly warning: string;
166
173
  readonly danger: string;
174
+ readonly purple: string;
167
175
  };
168
176
  readonly size: {
169
177
  readonly small: string;