@crisp-ui-kit/crisp 0.54.0 → 0.54.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/dist/activityfeed.css +12 -0
  2. package/dist/activityfeed.d.ts +7 -0
  3. package/dist/activityfeed.layered.css +14 -0
  4. package/dist/badge.css +3 -0
  5. package/dist/badge.d.ts +2 -2
  6. package/dist/badge.layered.css +3 -0
  7. package/dist/cjs/components/badge/badge.recipe.js +10 -0
  8. package/dist/cjs/components/datatable/datatable.js +2 -1
  9. package/dist/cjs/components/datatable/datatable.recipe.js +4 -0
  10. package/dist/cjs/components/mentionchip/index.js +7 -0
  11. package/dist/cjs/components/mentionchip/mentionchip.js +57 -0
  12. package/dist/cjs/components/mentionchip/mentionchip.recipe.js +38 -0
  13. package/dist/cjs/components/table/table.recipe.js +15 -3
  14. package/dist/cjs/core/floating-stack.js +18 -0
  15. package/dist/cjs/core/index.js +2 -1
  16. package/dist/cjs/index.js +7 -0
  17. package/dist/cjs/product/activityfeed/activityfeed.js +38 -0
  18. package/dist/cjs/product/activityfeed/activityfeed.recipe.js +35 -0
  19. package/dist/cjs/product/activityfeed/index.js +10 -0
  20. package/dist/cjs/product/formdialog/formdialog.js +171 -0
  21. package/dist/cjs/product/formdialog/formdialog.recipe.js +26 -0
  22. package/dist/cjs/product/formdialog/index.js +8 -0
  23. package/dist/cjs/product/importdialog/importdialog.js +134 -0
  24. package/dist/cjs/product/importdialog/importdialog.recipe.js +92 -0
  25. package/dist/cjs/product/importdialog/index.js +18 -0
  26. package/dist/cjs/product/richtext/richtext.js +43 -0
  27. package/dist/cjs/product/savedviews/index.js +7 -0
  28. package/dist/cjs/product/savedviews/savedviews.js +207 -0
  29. package/dist/cjs/product/savedviews/savedviews.recipe.js +103 -0
  30. package/dist/cjs/product/taskstable/index.js +7 -0
  31. package/dist/cjs/product/taskstable/taskstable.js +27 -0
  32. package/dist/cjs/product/taskstable/taskstable.recipe.js +47 -0
  33. package/dist/cjs/product/themepicker/index.js +17 -0
  34. package/dist/cjs/product/themepicker/themepicker.js +32 -0
  35. package/dist/cjs/product/themepicker/themepicker.recipe.js +98 -0
  36. package/dist/cjs/tokens/palette.js +31 -0
  37. package/dist/cjs/tokens/semantic.js +11 -0
  38. package/dist/datatable.css +20 -21
  39. package/dist/datatable.layered.css +20 -21
  40. package/dist/esm/components/badge/badge.recipe.js +10 -0
  41. package/dist/esm/components/datatable/datatable.js +2 -1
  42. package/dist/esm/components/datatable/datatable.recipe.js +4 -0
  43. package/dist/esm/components/mentionchip/index.js +2 -0
  44. package/dist/esm/components/mentionchip/mentionchip.js +21 -0
  45. package/dist/esm/components/mentionchip/mentionchip.recipe.js +35 -0
  46. package/dist/esm/components/table/table.recipe.js +15 -3
  47. package/dist/esm/core/floating-stack.js +17 -0
  48. package/dist/esm/core/index.js +1 -1
  49. package/dist/esm/index.js +7 -0
  50. package/dist/esm/product/activityfeed/activityfeed.js +32 -0
  51. package/dist/esm/product/activityfeed/activityfeed.recipe.js +32 -0
  52. package/dist/esm/product/activityfeed/index.js +2 -0
  53. package/dist/esm/product/formdialog/formdialog.js +134 -0
  54. package/dist/esm/product/formdialog/formdialog.recipe.js +23 -0
  55. package/dist/esm/product/formdialog/index.js +2 -0
  56. package/dist/esm/product/importdialog/importdialog.js +97 -0
  57. package/dist/esm/product/importdialog/importdialog.recipe.js +89 -0
  58. package/dist/esm/product/importdialog/index.js +2 -0
  59. package/dist/esm/product/richtext/richtext.js +43 -0
  60. package/dist/esm/product/savedviews/index.js +2 -0
  61. package/dist/esm/product/savedviews/savedviews.js +171 -0
  62. package/dist/esm/product/savedviews/savedviews.recipe.js +100 -0
  63. package/dist/esm/product/taskstable/index.js +2 -0
  64. package/dist/esm/product/taskstable/taskstable.js +24 -0
  65. package/dist/esm/product/taskstable/taskstable.recipe.js +44 -0
  66. package/dist/esm/product/themepicker/index.js +1 -0
  67. package/dist/esm/product/themepicker/themepicker.js +29 -0
  68. package/dist/esm/product/themepicker/themepicker.recipe.js +95 -0
  69. package/dist/esm/tokens/palette.js +31 -0
  70. package/dist/esm/tokens/semantic.js +11 -0
  71. package/dist/formdialog.css +6 -0
  72. package/dist/formdialog.d.ts +7 -0
  73. package/dist/formdialog.layered.css +8 -0
  74. package/dist/importdialog.css +38 -0
  75. package/dist/importdialog.d.ts +7 -0
  76. package/dist/importdialog.layered.css +40 -0
  77. package/dist/mentionchip.css +3 -0
  78. package/dist/mentionchip.d.ts +7 -0
  79. package/dist/mentionchip.layered.css +5 -0
  80. package/dist/native/tokens.d.ts +1 -1
  81. package/dist/native/tokens.js +24 -4
  82. package/dist/savedviews.css +78 -0
  83. package/dist/savedviews.d.ts +7 -0
  84. package/dist/savedviews.layered.css +80 -0
  85. package/dist/styles.css +242 -27
  86. package/dist/styles.layered.css +242 -27
  87. package/dist/table.css +15 -6
  88. package/dist/table.layered.css +15 -6
  89. package/dist/taskstable.css +23 -0
  90. package/dist/taskstable.d.ts +7 -0
  91. package/dist/taskstable.layered.css +25 -0
  92. package/dist/themepicker.css +27 -0
  93. package/dist/themepicker.d.ts +7 -0
  94. package/dist/themepicker.layered.css +29 -0
  95. package/dist/tokens.css +10 -0
  96. package/dist/tokens.json +24 -4
  97. package/dist/types/components/badge/badge.d.ts +2 -0
  98. package/dist/types/components/badge/badge.recipe.d.ts +8 -0
  99. package/dist/types/components/datatable/datatable.d.ts +12 -1
  100. package/dist/types/components/mentionchip/index.d.ts +2 -0
  101. package/dist/types/components/mentionchip/mentionchip.d.ts +20 -0
  102. package/dist/types/components/mentionchip/mentionchip.recipe.d.ts +18 -0
  103. package/dist/types/core/floating-stack.d.ts +14 -0
  104. package/dist/types/core/index.d.ts +1 -1
  105. package/dist/types/index.d.ts +7 -0
  106. package/dist/types/product/activityfeed/activityfeed.d.ts +57 -0
  107. package/dist/types/product/activityfeed/activityfeed.recipe.d.ts +3 -0
  108. package/dist/types/product/activityfeed/index.d.ts +2 -0
  109. package/dist/types/product/formdialog/formdialog.d.ts +57 -0
  110. package/dist/types/product/formdialog/formdialog.recipe.d.ts +3 -0
  111. package/dist/types/product/formdialog/index.d.ts +2 -0
  112. package/dist/types/product/importdialog/importdialog.d.ts +86 -0
  113. package/dist/types/product/importdialog/importdialog.recipe.d.ts +3 -0
  114. package/dist/types/product/importdialog/index.d.ts +2 -0
  115. package/dist/types/product/savedviews/index.d.ts +2 -0
  116. package/dist/types/product/savedviews/savedviews.d.ts +55 -0
  117. package/dist/types/product/savedviews/savedviews.recipe.d.ts +3 -0
  118. package/dist/types/product/taskstable/index.d.ts +2 -0
  119. package/dist/types/product/taskstable/taskstable.d.ts +54 -0
  120. package/dist/types/product/taskstable/taskstable.recipe.d.ts +3 -0
  121. package/dist/types/product/themepicker/index.d.ts +1 -0
  122. package/dist/types/product/themepicker/themepicker.d.ts +21 -0
  123. package/dist/types/product/themepicker/themepicker.recipe.d.ts +3 -0
  124. package/dist/types/tokens/contract.d.ts +5 -0
  125. package/dist/types/tokens/palette.d.ts +20 -0
  126. package/dist/types/tokens/semantic.d.ts +11 -0
  127. package/package.json +36 -1
@@ -12,6 +12,7 @@ export const tokens = {
12
12
  "bgRaised": "#f4f4f5",
13
13
  "borderDefault": "#e4e4e7",
14
14
  "borderSubtle": "#eeeff1",
15
+ "borderDropzone": "#e6e7ea",
15
16
  "ringNeutral": "transparent",
16
17
  "ringField": "rgba(0,0,0,0.06)",
17
18
  "ringSwitch": "#d9dade",
@@ -30,6 +31,7 @@ export const tokens = {
30
31
  "fgMuted": "#71717a",
31
32
  "bgDanger": "#e5484d",
32
33
  "bgDangerSolid": "#ba2525",
34
+ "fgDanger": "#eb3b3b",
33
35
  "strokeFieldFocus": "#1a1c20",
34
36
  "fgDisabled": "#d1d3d8",
35
37
  "bgNeutralWeak": "#f3f4f5",
@@ -49,7 +51,10 @@ export const tokens = {
49
51
  "fgSuccessSoft": "#186b3d",
50
52
  "fgWarningSoft": "#80520d",
51
53
  "fgDangerSoft": "#a33539",
52
- "fgNeutralSoft": "#686870"
54
+ "fgNeutralSoft": "#686870",
55
+ "bgPurpleSoft": "#f5f0ff",
56
+ "fgPurpleSoft": "#6238b5",
57
+ "ringPurpleSoft": "#e8ddfe"
53
58
  },
54
59
  "dark": {
55
60
  "bgBrandSolid": "#266df0",
@@ -60,6 +65,7 @@ export const tokens = {
60
65
  "bgRaised": "#101112",
61
66
  "borderDefault": "#212224",
62
67
  "borderSubtle": "#1c1d1f",
68
+ "borderDropzone": "#212224",
63
69
  "ringNeutral": "#212224",
64
70
  "ringField": "#212224",
65
71
  "ringSwitch": "#212224",
@@ -78,6 +84,7 @@ export const tokens = {
78
84
  "fgMuted": "#9a9aa2",
79
85
  "bgDanger": "#ff5a5f",
80
86
  "bgDangerSolid": "#ba2525",
87
+ "fgDanger": "#ff5a5f",
81
88
  "strokeFieldFocus": "#f3f4f5",
82
89
  "fgDisabled": "#5b606a",
83
90
  "bgNeutralWeak": "#1d2025",
@@ -97,7 +104,10 @@ export const tokens = {
97
104
  "fgSuccessSoft": "#2ea968",
98
105
  "fgWarningSoft": "#e0982a",
99
106
  "fgDangerSoft": "#ff5a5f",
100
- "fgNeutralSoft": "#9a9aa2"
107
+ "fgNeutralSoft": "#9a9aa2",
108
+ "bgPurpleSoft": "#2f1e5a",
109
+ "fgPurpleSoft": "#d8c4ff",
110
+ "ringPurpleSoft": "#45297d"
101
111
  }
102
112
  },
103
113
  "palette": {
@@ -109,6 +119,7 @@ export const tokens = {
109
119
  "gray900": "#101112",
110
120
  "line200": "#e4e4e7",
111
121
  "line100": "#eeeff1",
122
+ "line150": "#e6e7ea",
112
123
  "ringNeutral": "transparent",
113
124
  "ringField": "rgba(0,0,0,0.06)",
114
125
  "ringSwitch": "#d9dade",
@@ -128,6 +139,7 @@ export const tokens = {
128
139
  "brand700": "#1f5fd6",
129
140
  "red600": "#e5484d",
130
141
  "red700": "#ba2525",
142
+ "red500": "#eb3b3b",
131
143
  "fieldFocus": "#1a1c20",
132
144
  "disabledFg": "#d1d3d8",
133
145
  "neutralWeak": "#f3f4f5",
@@ -146,7 +158,10 @@ export const tokens = {
146
158
  "softSuccessText": "#186b3d",
147
159
  "softWarningText": "#80520d",
148
160
  "softDangerText": "#a33539",
149
- "softNeutralText": "#686870"
161
+ "softNeutralText": "#686870",
162
+ "purpleTint": "#f5f0ff",
163
+ "softPurpleText": "#6238b5",
164
+ "purpleRing": "#e8ddfe"
150
165
  },
151
166
  "dark": {
152
167
  "gray00": "#0a0a0a",
@@ -156,6 +171,7 @@ export const tokens = {
156
171
  "gray900": "#f5f5f5",
157
172
  "line200": "#212224",
158
173
  "line100": "#1c1d1f",
174
+ "line150": "#212224",
159
175
  "ringNeutral": "#212224",
160
176
  "ringField": "#212224",
161
177
  "ringSwitch": "#212224",
@@ -175,6 +191,7 @@ export const tokens = {
175
191
  "brand700": "#1f5fd6",
176
192
  "red600": "#ff5a5f",
177
193
  "red700": "#ba2525",
194
+ "red500": "#ff5a5f",
178
195
  "fieldFocus": "#f3f4f5",
179
196
  "disabledFg": "#5b606a",
180
197
  "neutralWeak": "#1d2025",
@@ -193,7 +210,10 @@ export const tokens = {
193
210
  "softSuccessText": "#2ea968",
194
211
  "softWarningText": "#e0982a",
195
212
  "softDangerText": "#ff5a5f",
196
- "softNeutralText": "#9a9aa2"
213
+ "softNeutralText": "#9a9aa2",
214
+ "purpleTint": "#2f1e5a",
215
+ "softPurpleText": "#d8c4ff",
216
+ "purpleRing": "#45297d"
197
217
  }
198
218
  },
199
219
  "space": {
@@ -0,0 +1,78 @@
1
+
2
+ /* pointer-events: auto (#375) — see Menu/MultiSelect's matching comment:
3
+ a modal Dialog sets pointer-events: none on document.body, and a
4
+ portaled layer outside Zag's knowledge inherits that lock. */
5
+ .crisp-savedviews-panel {
6
+ font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
7
+ position: fixed; z-index: 70; pointer-events: auto; box-sizing: border-box; display: flex; flex-direction: column; gap: var(--crisp-space-px);
8
+ min-width: 200px; max-height: 360px; overflow-y: auto; padding: var(--crisp-space-1);
9
+ border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover);
10
+ 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);
11
+ transform-origin: top left; opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease;
12
+ }
13
+ .crisp-savedviews-panel[data-up] { transform-origin: bottom left; }
14
+ .crisp-savedviews-panel { @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
15
+
16
+ .crisp-savedviews-row {
17
+ box-sizing: border-box; position: relative; display: flex; align-items: center; gap: var(--crisp-space-1-5);
18
+ height: var(--crisp-size-menuRow); flex-shrink: 0; padding: var(--crisp-space-1-5) var(--crisp-space-2);
19
+ border-radius: var(--crisp-radius-md); cursor: pointer; -webkit-user-select: none; user-select: none;
20
+ }
21
+ .crisp-savedviews-row:hover, .crisp-savedviews-row[data-highlighted] { background: var(--crisp-bg-raised); }
22
+ .crisp-savedviews-row-icon { flex-shrink: 0; display: inline-flex; width: var(--crisp-size-icon); height: var(--crisp-size-icon); color: var(--crisp-fg-muted); }
23
+ .crisp-savedviews-row-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
24
+ .crisp-savedviews-row[aria-selected="true"] .crisp-savedviews-row-label { font-weight: var(--crisp-weight-semibold); }
25
+ .crisp-savedviews-row-shared { flex-shrink: 0; display: inline-flex; color: var(--crisp-fg-muted); }
26
+
27
+ /* The kebab's own <Menu> is wrapped in a slot div (savedviews.tsx) that
28
+ stops a click from bubbling — through the REACT tree, which a portal
29
+ does not leave, even though the Menu's content is a DOM sibling under
30
+ document.body — into the row's own onClick. The slot, not the kebab
31
+ button itself, is what the row's flex layout pushes to the trailing
32
+ edge. */
33
+ .crisp-savedviews-kebab-slot { flex-shrink: 0; margin-inline-start: auto; }
34
+ /* 20px / 4px padding is a component-intrinsic size (AUTHORING.md §4b —
35
+ "a badge's 20px" is the named example), used once here: raw, not a
36
+ scale step. */
37
+ .crisp-savedviews-kebab {
38
+ box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center;
39
+ width: 20px; height: 20px; padding: var(--crisp-space-1); margin: 0;
40
+ border: none; border-radius: var(--crisp-radius-sm); background: none; color: var(--crisp-fg-muted); cursor: pointer;
41
+ opacity: 0; transition: opacity .1s ease, background-color .12s ease, color .12s ease;
42
+ }
43
+ .crisp-savedviews-row:hover .crisp-savedviews-kebab,
44
+ .crisp-savedviews-row:focus-within .crisp-savedviews-kebab,
45
+ .crisp-savedviews-kebab[data-open] { opacity: 1; }
46
+ .crisp-savedviews-kebab:hover, .crisp-savedviews-kebab[data-open] { background: var(--crisp-bg-surface); color: var(--crisp-fg-primary); }
47
+
48
+ .crisp-savedviews {
49
+ position: relative; display: inline-flex; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* Trigger fill measured rgb(246,247,247); bgRaised's light value is
50
+ #f4f4f5 (244,244,245) — a 2-unit-per-channel difference, inside
51
+ screenshot/anti-aliasing noise, not a second real colour. Reusing the
52
+ token (Lesson 3 — tokens, not raw px/hex) gets a correct,
53
+ already-established dark-mode fill for free instead of a light-only
54
+ literal; AUTHORING.md Lesson 29 is the case where that shortcut went
55
+ wrong (a flat colour that stayed visible where the reference had
56
+ none) — this is the opposite risk (a token that already flips per
57
+ theme, applied to the closest measured match). */
58
+ & .crisp-savedviews-trigger {
59
+ box-sizing: border-box; display: inline-flex; align-items: center; gap: var(--crisp-space-1-5);
60
+ height: var(--crisp-size-row); margin: 0; padding: var(--crisp-space-1) var(--crisp-space-1-5);
61
+ border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-raised);
62
+ font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary);
63
+ cursor: pointer; white-space: nowrap; transition: background-color .12s ease;
64
+ }
65
+ & .crisp-savedviews-trigger:hover,
66
+ & .crisp-savedviews-trigger[data-open] { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-raised)); }
67
+ & .crisp-savedviews-trigger-icon { flex-shrink: 0; display: inline-flex; width: var(--crisp-size-icon); height: var(--crisp-size-icon); }
68
+ & .crisp-savedviews-trigger-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
69
+ & .crisp-savedviews-trigger-chevron { flex-shrink: 0; color: var(--crisp-fg-muted); }
70
+ }
71
+
72
+ @media (prefers-reduced-motion: reduce) {
73
+ .crisp-savedviews, .crisp-savedviews * {
74
+ animation-duration: 0.01ms !important;
75
+ animation-iteration-count: 1 !important;
76
+ transition-duration: 0.01ms !important;
77
+ }
78
+ }
@@ -0,0 +1,7 @@
1
+ import type { RecipeFn } from "../core/types";
2
+
3
+ export interface SavedviewsVariants {
4
+
5
+ }
6
+
7
+ export declare const savedviewsRecipe: RecipeFn<{ }>;
@@ -0,0 +1,80 @@
1
+ @layer crisp-components {
2
+
3
+ /* pointer-events: auto (#375) — see Menu/MultiSelect's matching comment:
4
+ a modal Dialog sets pointer-events: none on document.body, and a
5
+ portaled layer outside Zag's knowledge inherits that lock. */
6
+ .crisp-savedviews-panel {
7
+ font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
8
+ position: fixed; z-index: 70; pointer-events: auto; box-sizing: border-box; display: flex; flex-direction: column; gap: var(--crisp-space-px);
9
+ min-width: 200px; max-height: 360px; overflow-y: auto; padding: var(--crisp-space-1);
10
+ border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover);
11
+ 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);
12
+ transform-origin: top left; opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease;
13
+ }
14
+ .crisp-savedviews-panel[data-up] { transform-origin: bottom left; }
15
+ .crisp-savedviews-panel { @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
16
+
17
+ .crisp-savedviews-row {
18
+ box-sizing: border-box; position: relative; display: flex; align-items: center; gap: var(--crisp-space-1-5);
19
+ height: var(--crisp-size-menuRow); flex-shrink: 0; padding: var(--crisp-space-1-5) var(--crisp-space-2);
20
+ border-radius: var(--crisp-radius-md); cursor: pointer; -webkit-user-select: none; user-select: none;
21
+ }
22
+ .crisp-savedviews-row:hover, .crisp-savedviews-row[data-highlighted] { background: var(--crisp-bg-raised); }
23
+ .crisp-savedviews-row-icon { flex-shrink: 0; display: inline-flex; width: var(--crisp-size-icon); height: var(--crisp-size-icon); color: var(--crisp-fg-muted); }
24
+ .crisp-savedviews-row-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
25
+ .crisp-savedviews-row[aria-selected="true"] .crisp-savedviews-row-label { font-weight: var(--crisp-weight-semibold); }
26
+ .crisp-savedviews-row-shared { flex-shrink: 0; display: inline-flex; color: var(--crisp-fg-muted); }
27
+
28
+ /* The kebab's own <Menu> is wrapped in a slot div (savedviews.tsx) that
29
+ stops a click from bubbling — through the REACT tree, which a portal
30
+ does not leave, even though the Menu's content is a DOM sibling under
31
+ document.body — into the row's own onClick. The slot, not the kebab
32
+ button itself, is what the row's flex layout pushes to the trailing
33
+ edge. */
34
+ .crisp-savedviews-kebab-slot { flex-shrink: 0; margin-inline-start: auto; }
35
+ /* 20px / 4px padding is a component-intrinsic size (AUTHORING.md §4b —
36
+ "a badge's 20px" is the named example), used once here: raw, not a
37
+ scale step. */
38
+ .crisp-savedviews-kebab {
39
+ box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center;
40
+ width: 20px; height: 20px; padding: var(--crisp-space-1); margin: 0;
41
+ border: none; border-radius: var(--crisp-radius-sm); background: none; color: var(--crisp-fg-muted); cursor: pointer;
42
+ opacity: 0; transition: opacity .1s ease, background-color .12s ease, color .12s ease;
43
+ }
44
+ .crisp-savedviews-row:hover .crisp-savedviews-kebab,
45
+ .crisp-savedviews-row:focus-within .crisp-savedviews-kebab,
46
+ .crisp-savedviews-kebab[data-open] { opacity: 1; }
47
+ .crisp-savedviews-kebab:hover, .crisp-savedviews-kebab[data-open] { background: var(--crisp-bg-surface); color: var(--crisp-fg-primary); }
48
+
49
+ .crisp-savedviews {
50
+ position: relative; display: inline-flex; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* Trigger fill measured rgb(246,247,247); bgRaised's light value is
51
+ #f4f4f5 (244,244,245) — a 2-unit-per-channel difference, inside
52
+ screenshot/anti-aliasing noise, not a second real colour. Reusing the
53
+ token (Lesson 3 — tokens, not raw px/hex) gets a correct,
54
+ already-established dark-mode fill for free instead of a light-only
55
+ literal; AUTHORING.md Lesson 29 is the case where that shortcut went
56
+ wrong (a flat colour that stayed visible where the reference had
57
+ none) — this is the opposite risk (a token that already flips per
58
+ theme, applied to the closest measured match). */
59
+ & .crisp-savedviews-trigger {
60
+ box-sizing: border-box; display: inline-flex; align-items: center; gap: var(--crisp-space-1-5);
61
+ height: var(--crisp-size-row); margin: 0; padding: var(--crisp-space-1) var(--crisp-space-1-5);
62
+ border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-raised);
63
+ font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary);
64
+ cursor: pointer; white-space: nowrap; transition: background-color .12s ease;
65
+ }
66
+ & .crisp-savedviews-trigger:hover,
67
+ & .crisp-savedviews-trigger[data-open] { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-raised)); }
68
+ & .crisp-savedviews-trigger-icon { flex-shrink: 0; display: inline-flex; width: var(--crisp-size-icon); height: var(--crisp-size-icon); }
69
+ & .crisp-savedviews-trigger-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
70
+ & .crisp-savedviews-trigger-chevron { flex-shrink: 0; color: var(--crisp-fg-muted); }
71
+ }
72
+
73
+ @media (prefers-reduced-motion: reduce) {
74
+ .crisp-savedviews, .crisp-savedviews * {
75
+ animation-duration: 0.01ms !important;
76
+ animation-iteration-count: 1 !important;
77
+ transition-duration: 0.01ms !important;
78
+ }
79
+ }
80
+ }