@morscherlab/mint-sdk 1.0.44 → 1.0.46

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 (53) hide show
  1. package/dist/__tests__/components/SmartGroupFieldRecipe.groups.test.d.ts +1 -0
  2. package/dist/__tests__/components/SmartGroupManual.cohorts.test.d.ts +1 -0
  3. package/dist/components/AutoGroupModal.adapter.d.ts +42 -0
  4. package/dist/components/AutoGroupModal.vue.d.ts +1 -105
  5. package/dist/components/DataFrame.vue.d.ts +15 -0
  6. package/dist/components/SmartGroup.types.d.ts +71 -0
  7. package/dist/components/SmartGroupFieldRecipe.groups.d.ts +53 -0
  8. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +37 -0
  9. package/dist/components/SmartGroupManual.cohorts.d.ts +52 -0
  10. package/dist/components/SmartGroupManual.vue.d.ts +17 -0
  11. package/dist/components/SmartGroupModal.vue.d.ts +27 -0
  12. package/dist/components/index.d.ts +3 -0
  13. package/dist/components/index.js +2 -2
  14. package/dist/{components-BGVwavdd.js → components-C7UFkNIp.js} +3036 -2751
  15. package/dist/components-C7UFkNIp.js.map +1 -0
  16. package/dist/composables/index.js +2 -2
  17. package/dist/{composables-C_hPF0Gn.js → composables-CpBhNKHf.js} +7 -147
  18. package/dist/composables-CpBhNKHf.js.map +1 -0
  19. package/dist/index.js +4 -4
  20. package/dist/install.js +1 -1
  21. package/dist/styles.css +12824 -12195
  22. package/dist/{useProtocolTemplates-BbvlHoPD.js → useProtocolTemplates-C8-YlHj1.js} +206 -66
  23. package/dist/useProtocolTemplates-C8-YlHj1.js.map +1 -0
  24. package/package.json +1 -1
  25. package/src/__tests__/components/AutoGroupModal.adapter.test.ts +164 -0
  26. package/src/__tests__/components/DataFrame.test.ts +100 -0
  27. package/src/__tests__/components/SampleSelector.test.ts +176 -16
  28. package/src/__tests__/components/SmartGroupFieldRecipe.groups.test.ts +96 -0
  29. package/src/__tests__/components/SmartGroupManual.cohorts.test.ts +97 -0
  30. package/src/components/AutoGroupModal.adapter.ts +147 -0
  31. package/src/components/AutoGroupModal.vue +176 -1321
  32. package/src/components/DataFrame.vue +97 -5
  33. package/src/components/SampleSelector.vue +8 -23
  34. package/src/components/SmartGroup.types.ts +93 -0
  35. package/src/components/SmartGroupFieldRecipe.groups.ts +105 -0
  36. package/src/components/SmartGroupFieldRecipe.story.vue +58 -0
  37. package/src/components/SmartGroupFieldRecipe.vue +427 -0
  38. package/src/components/SmartGroupManual.cohorts.ts +112 -0
  39. package/src/components/SmartGroupManual.story.vue +55 -0
  40. package/src/components/SmartGroupManual.vue +398 -0
  41. package/src/components/SmartGroupModal.story.vue +61 -0
  42. package/src/components/SmartGroupModal.vue +61 -0
  43. package/src/components/index.ts +3 -0
  44. package/src/styles/components/dataframe.css +79 -0
  45. package/src/styles/components/sample-selector.css +1 -5
  46. package/src/styles/components/smart-group.css +708 -0
  47. package/src/styles/index.css +1 -1
  48. package/dist/components-BGVwavdd.js.map +0 -1
  49. package/dist/composables-C_hPF0Gn.js.map +0 -1
  50. package/dist/useProtocolTemplates-BbvlHoPD.js.map +0 -1
  51. package/src/__tests__/components/AutoGroupModal.preview.test.ts +0 -46
  52. package/src/styles/components/auto-group-modal.css +0 -1336
  53. /package/dist/__tests__/components/{AutoGroupModal.preview.test.d.ts → AutoGroupModal.adapter.test.d.ts} +0 -0
@@ -0,0 +1,708 @@
1
+ /* ==========================================================================
2
+ Smart Group — Full View modal (auto "Field Recipe" + manual cohort modes).
3
+ Ported from the MINT design-system project; all values resolve against the
4
+ SDK token set in styles/variables.css. Fira Sans for UI, Fira Code for
5
+ sample identifiers (data).
6
+
7
+ The curated group palette (--grp-*) is not part of the global token set, so
8
+ it is defined here scoped to the modal root — this resolves both the CSS
9
+ references below and the inline `var(--grp-*)` colour bindings in the
10
+ components, which inherit it via the cascade.
11
+ ========================================================================== */
12
+
13
+ .sg-modal {
14
+ --grp-1: #6366f1; /* indigo */
15
+ --grp-2: #0ea5a4; /* teal */
16
+ --grp-3: #f59e0b; /* amber */
17
+ --grp-4: #f43f5e; /* rose */
18
+ --grp-5: #8b5cf6; /* violet */
19
+ --grp-qc: #94a3b8; /* slate — QC stays neutral */
20
+
21
+ position: relative;
22
+ width: 100%;
23
+ height: 100%;
24
+ display: flex;
25
+ flex-direction: column;
26
+ background: var(--bg-secondary);
27
+ color: var(--text-primary);
28
+ font-family: 'Fira Sans', system-ui, sans-serif;
29
+ border-radius: var(--radius-lg);
30
+ border: 1px solid var(--border-color);
31
+ box-shadow: var(--shadow-lg);
32
+ overflow: hidden;
33
+ }
34
+
35
+ /* ---- Header ---- */
36
+ .sg-head {
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 0.75rem;
40
+ padding: 0.875rem 1.25rem;
41
+ border-bottom: 1px solid var(--border-color);
42
+ flex-shrink: 0;
43
+ }
44
+ .sg-head__title {
45
+ font-size: 1.0625rem;
46
+ font-weight: 600;
47
+ letter-spacing: -0.01em;
48
+ white-space: nowrap;
49
+ }
50
+ .sg-head__sub {
51
+ font-size: 0.8125rem;
52
+ color: var(--text-muted);
53
+ font-weight: 400;
54
+ white-space: nowrap;
55
+ }
56
+ .sg-head__spacer { flex: 1; }
57
+ .sg-head__close {
58
+ display: flex; align-items: center; justify-content: center;
59
+ width: 1.75rem; height: 1.75rem;
60
+ border: none; background: none; cursor: pointer;
61
+ border-radius: var(--radius);
62
+ color: var(--text-muted);
63
+ font-size: 1.25rem; line-height: 1;
64
+ transition: background 0.15s ease, color 0.15s ease;
65
+ }
66
+ .sg-head__close:hover { background: var(--bg-hover); color: var(--text-primary); }
67
+
68
+ /* ---- Mode pill (Auto / Manual) — the single mode switch ---- */
69
+ .sg-mode {
70
+ display: inline-flex; padding: 0.1875rem; gap: 0.125rem;
71
+ background: var(--bg-tertiary); border-radius: var(--radius-md);
72
+ }
73
+ .sg-mode__btn {
74
+ border: none; background: none; cursor: pointer;
75
+ font: inherit; font-size: 0.8125rem; font-weight: 500;
76
+ color: var(--text-secondary);
77
+ padding: 0.25rem 0.625rem; border-radius: var(--radius);
78
+ transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
79
+ }
80
+ .sg-mode__btn:hover { color: var(--text-primary); }
81
+ .sg-mode__btn--on {
82
+ background: var(--bg-secondary); color: var(--text-primary);
83
+ box-shadow: var(--shadow-sm);
84
+ }
85
+ .sg-mode__btn--on:hover { color: var(--text-primary); }
86
+
87
+ /* ---- Body ---- */
88
+ .sg-body {
89
+ flex: 1; min-height: 0;
90
+ display: grid;
91
+ grid-template-columns: 1.15fr 0.85fr;
92
+ }
93
+ .sg-body__main {
94
+ padding: 1rem 1.25rem;
95
+ min-width: 0;
96
+ overflow: hidden;
97
+ display: flex; flex-direction: column; gap: 0.75rem;
98
+ }
99
+ .sg-body__side {
100
+ border-left: 1px solid var(--border-color);
101
+ background: var(--bg-primary);
102
+ padding: 1.125rem 1.25rem;
103
+ display: flex; flex-direction: column;
104
+ min-width: 0;
105
+ gap: 0.75rem;
106
+ }
107
+
108
+ /* Section lead */
109
+ .sg-lead { display: flex; flex-direction: column; gap: 0.25rem; }
110
+ .sg-lead__q {
111
+ font-size: 0.9375rem; font-weight: 600; color: var(--text-primary);
112
+ }
113
+ .sg-lead__hint {
114
+ font-size: 0.8125rem; color: var(--text-secondary); line-height: 1.45;
115
+ }
116
+
117
+ /* Plain-english summary callout */
118
+ .sg-summary {
119
+ display: flex; gap: 0.5rem; align-items: flex-start;
120
+ padding: 0.625rem 0.75rem;
121
+ background: var(--color-primary-soft);
122
+ border-radius: var(--radius-md);
123
+ font-size: 0.8125rem; line-height: 1.5; color: var(--text-primary);
124
+ }
125
+ .sg-summary b { font-weight: 600; }
126
+ .sg-summary__icon {
127
+ flex-shrink: 0; width: 1rem; height: 1rem; color: var(--color-primary);
128
+ margin-top: 0.0625rem;
129
+ }
130
+ .sg-summary--warn {
131
+ background: var(--mint-warning-bg);
132
+ box-shadow: inset 0 0 0 1px var(--mint-warning-border);
133
+ }
134
+ .sg-summary--warn .sg-summary__icon { color: var(--mint-warning); }
135
+
136
+ /* ==========================================================================
137
+ Field Recipe (auto mode) — field toggle list
138
+ ========================================================================== */
139
+ .sg-recipe { display: flex; flex-direction: column; gap: 0.25rem; }
140
+ .sg-field {
141
+ display: grid;
142
+ grid-template-columns: 1fr auto;
143
+ align-items: center;
144
+ gap: 0.5rem 0.75rem;
145
+ padding: 0.625rem 0.75rem;
146
+ border: 1px solid var(--border-color);
147
+ border-radius: var(--radius-md);
148
+ background: var(--bg-card);
149
+ transition: border-color 0.15s ease, background 0.15s ease;
150
+ }
151
+ .sg-field--on {
152
+ border-color: var(--color-primary);
153
+ background: var(--color-primary-soft);
154
+ }
155
+ .sg-field__name { font-size: 0.875rem; font-weight: 600; color: var(--text-primary); }
156
+ .sg-field__role {
157
+ font-size: 0.625rem; font-weight: 600; text-transform: uppercase;
158
+ letter-spacing: 0.04em; color: var(--text-muted);
159
+ padding: 0.0625rem 0.375rem; border-radius: 9999px;
160
+ background: var(--bg-tertiary); margin-left: 0.5rem;
161
+ }
162
+ .sg-field__role--rep { color: var(--mint-warning); background: var(--mint-warning-bg); }
163
+ .sg-field__vals {
164
+ grid-column: 1 / 2;
165
+ font-family: 'Fira Code', monospace; font-size: 0.75rem;
166
+ color: var(--text-muted);
167
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
168
+ }
169
+ .sg-field__toggle { grid-row: 1 / 3; grid-column: 2; align-self: center; }
170
+
171
+ /* toggle switch */
172
+ .sg-switch {
173
+ position: relative; width: 1.65rem; height: 0.95rem;
174
+ border-radius: 9999px; background: var(--bg-tertiary);
175
+ border: none; cursor: pointer; flex-shrink: 0;
176
+ transition: background 0.15s ease;
177
+ }
178
+ .sg-switch.on { background: var(--color-primary); }
179
+ .sg-switch::after {
180
+ content: ''; position: absolute; top: 0.125rem; left: 0.125rem;
181
+ width: 0.7rem; height: 0.7rem; border-radius: 9999px;
182
+ background: #fff; box-shadow: 0 1px 2px rgb(0 0 0 / 0.25);
183
+ transition: transform 0.15s ease;
184
+ }
185
+ .sg-switch.on::after { transform: translateX(0.7rem); }
186
+
187
+ /* ==========================================================================
188
+ Shared — live group preview (right rail)
189
+ ========================================================================== */
190
+ .sg-preview__head {
191
+ display: flex; align-items: center; gap: 0.5rem;
192
+ font-size: 0.6875rem; font-weight: 600; text-transform: uppercase;
193
+ letter-spacing: 0.05em; color: var(--text-secondary);
194
+ }
195
+ .sg-preview__count {
196
+ margin-left: auto; font-size: 0.6875rem; font-weight: 600;
197
+ color: var(--text-muted); font-variant-numeric: tabular-nums;
198
+ text-transform: none; letter-spacing: 0; white-space: nowrap;
199
+ }
200
+ .sg-grouplist { display: flex; flex-direction: column; gap: 0.25rem; }
201
+ .sg-group {
202
+ display: flex; align-items: center; gap: 0.625rem;
203
+ padding: 0.4375rem 0.5rem; border-radius: var(--radius);
204
+ transition: background 0.15s ease;
205
+ }
206
+ .sg-group:hover { background: var(--bg-hover); }
207
+ .sg-dot {
208
+ width: 0.6875rem; height: 0.6875rem; border-radius: 50%;
209
+ flex-shrink: 0; box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.12);
210
+ }
211
+ .sg-group__name {
212
+ flex: 1; min-width: 0;
213
+ font-family: 'Fira Code', monospace; font-size: 0.8125rem; font-weight: 500;
214
+ color: var(--text-primary);
215
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
216
+ }
217
+ .sg-group__count {
218
+ font-size: 0.6875rem; font-weight: 600; color: var(--text-secondary);
219
+ background: var(--bg-tertiary);
220
+ padding: 0.0625rem 0.4375rem; border-radius: 9999px;
221
+ font-variant-numeric: tabular-nums; flex-shrink: 0;
222
+ }
223
+ .sg-group__bar {
224
+ flex-shrink: 0; height: 0.25rem; border-radius: 9999px;
225
+ background: var(--g, var(--text-muted)); opacity: 0.85;
226
+ }
227
+
228
+ .sg-qc {
229
+ margin-top: 0.5rem; padding-top: 0.75rem;
230
+ border-top: 1px solid var(--border-color);
231
+ }
232
+ .sg-qc__head {
233
+ display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem;
234
+ }
235
+ .sg-qc__title {
236
+ font-size: 0.6875rem; font-weight: 600; text-transform: uppercase;
237
+ letter-spacing: 0.05em; color: var(--text-muted);
238
+ }
239
+ .sg-qc__route {
240
+ margin-left: auto;
241
+ font: inherit; font-size: 0.75rem; font-weight: 500;
242
+ color: var(--text-secondary);
243
+ padding: 0.1875rem 1.5rem 0.1875rem 0.5rem;
244
+ background: var(--bg-secondary);
245
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2394a3b8' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
246
+ background-position: right 0.25rem center; background-repeat: no-repeat;
247
+ background-size: 1.1em 1.1em;
248
+ border: 1px solid var(--border-color); border-radius: var(--radius-sm);
249
+ appearance: none; cursor: pointer;
250
+ }
251
+ .sg-qc__chip {
252
+ display: inline-flex; align-items: center; gap: 0.375rem;
253
+ padding: 0.25rem 0.5rem; border-radius: var(--radius);
254
+ background: var(--bg-tertiary);
255
+ font-family: 'Fira Code', monospace; font-size: 0.75rem;
256
+ color: var(--text-secondary);
257
+ }
258
+ .sg-qc__chip .sg-dot { width: 0.5rem; height: 0.5rem; }
259
+
260
+ /* ---- Footer ---- */
261
+ .sg-foot {
262
+ display: flex; align-items: center; gap: 0.625rem;
263
+ padding: 0.875rem 1.25rem;
264
+ border-top: 1px solid var(--border-color);
265
+ background: var(--bg-secondary);
266
+ flex-shrink: 0;
267
+ }
268
+ .sg-foot__spacer { flex: 1; }
269
+ .sg-foot__hint {
270
+ font-size: 0.75rem; color: var(--text-muted);
271
+ }
272
+ .sg-foot__link {
273
+ font: inherit; font-size: 0.8125rem; font-weight: 500;
274
+ color: var(--color-primary); background: none; border: none;
275
+ cursor: pointer; display: inline-flex; align-items: center; gap: 0.375rem;
276
+ padding: 0.3125rem 0.5rem; border-radius: var(--radius); white-space: nowrap;
277
+ transition: background 0.15s ease, color 0.15s ease;
278
+ }
279
+ .sg-foot__link:hover { background: var(--color-primary-soft); color: var(--color-primary-hover); }
280
+ .sg-btn {
281
+ font: inherit; font-size: 0.875rem; font-weight: 500; cursor: pointer;
282
+ padding: 0.5rem 1rem; border-radius: var(--radius-md);
283
+ border: 1px solid transparent; transition: all 0.15s ease;
284
+ display: inline-flex; align-items: center; gap: 0.4375rem;
285
+ }
286
+ .sg-btn--primary { background: var(--color-primary); color: #fff; }
287
+ .sg-btn--primary:hover { background: var(--color-primary-hover); }
288
+ .sg-btn--ghost {
289
+ background: var(--bg-secondary); color: var(--text-primary);
290
+ border-color: var(--border-color);
291
+ }
292
+ .sg-btn--ghost:hover { background: var(--bg-tertiary); }
293
+
294
+ /* ==========================================================================
295
+ Field Recipe refinements (layered on the shared chrome above)
296
+ ========================================================================== */
297
+ .fr .sg-field {
298
+ grid-template-columns: 1fr auto;
299
+ grid-template-rows: auto auto;
300
+ row-gap: 0.25rem;
301
+ padding: 0.5rem 0.75rem;
302
+ }
303
+ .fr-field__head { display: flex; align-items: center; gap: 0.5rem; }
304
+ .fr .sg-field__role { margin-left: 0; }
305
+ .fr .sg-field__vals { grid-column: 1 / 2; grid-row: 2; }
306
+ .fr-switch { grid-column: 2; grid-row: 1 / 3; align-self: center; }
307
+
308
+ /* Replicate-on: the field card itself warns instead of silently shattering. */
309
+ .fr-field--warn.sg-field--on {
310
+ border-color: var(--mint-warning-border);
311
+ background: var(--mint-warning-bg);
312
+ }
313
+ .fr-field--warn.sg-field--on .fr-switch.on { background: var(--mint-warning); }
314
+ .fr-field--warn.sg-field--on .sg-field__role--rep {
315
+ color: #fff; background: var(--mint-warning);
316
+ }
317
+
318
+ /* Neutral (no-selection) summary variant. */
319
+ .fr-summary--mute {
320
+ background: var(--bg-tertiary);
321
+ color: var(--text-secondary);
322
+ }
323
+ .fr-summary--mute .sg-summary__icon { color: var(--text-muted); }
324
+ .sg-summary code {
325
+ font-family: 'Fira Code', monospace; font-size: 0.78em;
326
+ background: rgba(0, 0, 0, 0.06); padding: 0 0.25rem; border-radius: 3px;
327
+ }
328
+ html.dark .sg-summary code { background: rgba(255, 255, 255, 0.1); }
329
+
330
+ /* Rail header: wrap the count under the label rather than clip it. */
331
+ .fr .sg-preview__head { flex-wrap: wrap; row-gap: 0.15rem; }
332
+
333
+ /* QC chip when excluded reads as struck-through / dimmed. */
334
+ .fr-qc__chip--off {
335
+ opacity: 0.5; text-decoration: line-through;
336
+ text-decoration-color: var(--text-muted);
337
+ }
338
+
339
+ .fr .sg-qc__chip { white-space: nowrap; }
340
+
341
+ .fr-empty {
342
+ font-size: 0.8125rem; color: var(--text-muted);
343
+ padding: 0.75rem 0.5rem; font-style: italic;
344
+ }
345
+
346
+ /* Disabled primary. */
347
+ .sg-btn--primary:disabled {
348
+ /* Disabled = opacity AND a visual cue: shift to a neutral surface (mirrors
349
+ the SDK button.css approach) so it reads as non-actionable, not just faded. */
350
+ background: var(--bg-tertiary); color: var(--text-muted); border-color: var(--border-color);
351
+ opacity: 0.7; cursor: not-allowed;
352
+ }
353
+ .sg-btn--primary:disabled:hover { background: var(--bg-tertiary); }
354
+
355
+ /* ==========================================================================
356
+ Manual grouping (manual mode) — selection-first layout
357
+ ========================================================================== */
358
+ .mg2-body {
359
+ flex: 1; min-height: 0;
360
+ display: grid;
361
+ grid-template-columns: 1.55fr 1fr;
362
+ }
363
+
364
+ /* ───────── LEFT · find & select ───────── */
365
+ .mg2-find {
366
+ display: flex; flex-direction: column; min-width: 0;
367
+ /* min-height:0 lets this grid item shrink below content so .mg2-list scrolls
368
+ inside the fixed modal height instead of growing the grid track. */
369
+ min-height: 0;
370
+ border-right: 1px solid var(--border-color);
371
+ }
372
+
373
+ .mg2-search {
374
+ position: relative; display: flex; align-items: center;
375
+ margin: 0.875rem 1rem 0.625rem;
376
+ }
377
+ .mg2-search > svg {
378
+ position: absolute; left: 0.6875rem; color: var(--text-muted); pointer-events: none;
379
+ }
380
+ .mg2-search input {
381
+ width: 100%; font: inherit; font-size: 0.8125rem;
382
+ padding: 0.5rem 2rem 0.5rem 2.125rem;
383
+ border: 1px solid var(--border-color); border-radius: var(--radius-md);
384
+ background: var(--bg-tertiary); color: var(--text-primary); outline: none;
385
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
386
+ }
387
+ .mg2-search input:focus {
388
+ border-color: var(--color-primary); background: var(--bg-secondary);
389
+ box-shadow: var(--focus-ring-soft);
390
+ }
391
+ .mg2-search__clr {
392
+ position: absolute; right: 0.5rem; display: flex; padding: 0.1875rem;
393
+ border: none; background: none; cursor: pointer; color: var(--text-muted);
394
+ border-radius: 9999px;
395
+ }
396
+ .mg2-search__clr:hover { background: var(--bg-hover); color: var(--text-primary); }
397
+
398
+ .mg2-chips {
399
+ display: flex; gap: 0.375rem; padding: 0 1rem 0.625rem;
400
+ }
401
+ .mg2-chip {
402
+ display: inline-flex; align-items: center; gap: 0.375rem;
403
+ font: inherit; font-size: 0.75rem; font-weight: 500; color: var(--text-secondary);
404
+ padding: 0.3125rem 0.625rem; cursor: pointer;
405
+ background: var(--bg-secondary);
406
+ border: 1px solid var(--border-color); border-radius: 9999px;
407
+ transition: all 0.13s ease;
408
+ }
409
+ .mg2-chip:hover { border-color: var(--text-muted); }
410
+ .mg2-chip--on {
411
+ background: var(--color-primary); border-color: var(--color-primary); color: #fff;
412
+ }
413
+ .mg2-chip__n {
414
+ font-variant-numeric: tabular-nums; font-weight: 600;
415
+ font-size: 0.6875rem; color: var(--text-muted);
416
+ }
417
+ .mg2-chip--on .mg2-chip__n { color: rgba(255, 255, 255, 0.8); }
418
+
419
+ .mg2-selbar {
420
+ display: flex; align-items: center; gap: 0.5rem;
421
+ padding: 0.5rem 0; margin: 0 1rem;
422
+ border-top: 1px solid var(--border-light);
423
+ border-bottom: 1px solid var(--border-light);
424
+ }
425
+ .mg2-check {
426
+ display: inline-flex; align-items: center; gap: 0.5rem; cursor: pointer;
427
+ font-size: 0.75rem; font-weight: 600; color: var(--text-secondary);
428
+ text-transform: uppercase; letter-spacing: 0.04em;
429
+ }
430
+ .mg2-check input { width: 0.9375rem; height: 0.9375rem; accent-color: var(--color-primary); cursor: pointer; }
431
+ .mg2-selbar__n {
432
+ margin-left: auto; font-size: 0.75rem; color: var(--text-muted);
433
+ font-variant-numeric: tabular-nums;
434
+ }
435
+
436
+ .mg2-list {
437
+ flex: 1; min-height: 0; overflow-y: auto;
438
+ padding: 0.375rem 0.5rem 0.5rem;
439
+ }
440
+ .mg2-list__empty {
441
+ padding: 1.5rem 0.75rem; font-size: 0.8125rem; color: var(--text-muted);
442
+ font-style: italic; text-align: center;
443
+ }
444
+ .mg2-row {
445
+ display: flex; align-items: center; gap: 0.625rem;
446
+ padding: 0.4375rem 0.5rem; border-radius: var(--radius);
447
+ cursor: pointer; transition: background 0.12s ease;
448
+ }
449
+ .mg2-row:hover { background: var(--bg-hover); }
450
+ .mg2-row--on { background: var(--color-primary-soft); }
451
+ .mg2-cb {
452
+ width: 0.9375rem; height: 0.9375rem; accent-color: var(--color-primary);
453
+ flex-shrink: 0; pointer-events: none;
454
+ }
455
+ .mg2-row__name {
456
+ flex: 1; min-width: 0;
457
+ font-family: 'Fira Code', monospace; font-size: 0.8125rem;
458
+ color: var(--text-primary);
459
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
460
+ }
461
+ .mg2-row__tag {
462
+ flex-shrink: 0; display: inline-flex; align-items: center; gap: 0.375rem;
463
+ font-size: 0.6875rem; font-weight: 600; color: var(--text-secondary);
464
+ padding: 0.125rem 0.5rem 0.125rem 0.375rem; border-radius: 9999px;
465
+ background: var(--bg-tertiary);
466
+ white-space: nowrap;
467
+ }
468
+ .mg2-row__tag .sg-dot { width: 0.5rem; height: 0.5rem; }
469
+ .mg2-row__tag--none {
470
+ background: none; color: var(--text-muted); font-weight: 400;
471
+ font-style: italic; padding-left: 0.5rem;
472
+ }
473
+
474
+ /* ───────── RIGHT · cohorts rail ───────── */
475
+ .mg2-cohorts {
476
+ display: flex; flex-direction: column; min-width: 0;
477
+ /* min-height:0 lets this grid item shrink so .mg2-tree scrolls within height. */
478
+ min-height: 0;
479
+ background: var(--bg-primary);
480
+ padding: 0.875rem 1.125rem 1rem;
481
+ gap: 0.75rem;
482
+ }
483
+ .mg2-cohorts__head { display: flex; align-items: baseline; gap: 0.5rem; }
484
+ .mg2-cohorts__t {
485
+ font-size: 0.6875rem; font-weight: 600; text-transform: uppercase;
486
+ letter-spacing: 0.05em; color: var(--text-secondary);
487
+ }
488
+ .mg2-cohorts__n {
489
+ margin-left: auto; font-size: 0.75rem; color: var(--text-muted);
490
+ font-variant-numeric: tabular-nums; white-space: nowrap;
491
+ }
492
+
493
+ .mg2-progress { display: flex; flex-direction: column; gap: 0.4375rem; }
494
+ .mg2-progress__top {
495
+ display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem;
496
+ font-size: 0.8125rem; color: var(--text-secondary); white-space: nowrap;
497
+ }
498
+ .mg2-progress__top b { color: var(--text-primary); font-weight: 600; }
499
+ .mg2-progress__pct {
500
+ font-weight: 600; color: var(--text-primary); font-variant-numeric: tabular-nums;
501
+ }
502
+ .mg2-progress__track {
503
+ height: 0.4375rem; border-radius: 9999px; background: var(--bg-tertiary); overflow: hidden;
504
+ }
505
+ .mg2-progress__fill {
506
+ height: 100%; border-radius: 9999px;
507
+ background: linear-gradient(90deg, var(--grp-2), var(--color-primary));
508
+ transition: width 0.3s cubic-bezier(0.2, 0.7, 0.3, 1);
509
+ }
510
+
511
+ .mg2-tree { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 0.5rem; }
512
+ .mg2-tree__empty {
513
+ font-size: 0.8125rem; color: var(--text-muted); line-height: 1.5;
514
+ padding: 0.5rem 0; font-style: italic;
515
+ }
516
+ .mg2-grp {
517
+ border: 1px solid var(--border-color); border-radius: var(--radius-md);
518
+ background: var(--bg-card); overflow: hidden;
519
+ }
520
+ .mg2-grp__row {
521
+ display: flex; align-items: center; gap: 0.5rem;
522
+ padding: 0.5rem 0.625rem;
523
+ }
524
+ .mg2-grp__name { flex: 1; min-width: 0; font-size: 0.8125rem; font-weight: 600; color: var(--text-primary); }
525
+ .mg2-grp__n {
526
+ font-size: 0.6875rem; font-weight: 600; color: var(--text-secondary);
527
+ background: var(--bg-tertiary); padding: 0.0625rem 0.4375rem; border-radius: 9999px;
528
+ font-variant-numeric: tabular-nums;
529
+ }
530
+ .mg2-sub {
531
+ display: flex; align-items: center; gap: 0.5rem;
532
+ padding: 0.3125rem 0.625rem 0.3125rem 1.625rem;
533
+ border-top: 1px solid var(--border-light);
534
+ font-size: 0.75rem; color: var(--text-secondary);
535
+ }
536
+ .mg2-sub__name { flex: 1; font-family: 'Fira Code', monospace; }
537
+ .mg2-sub__n { color: var(--text-muted); font-variant-numeric: tabular-nums; }
538
+ .mg2-sub2 {
539
+ display: flex; align-items: center; gap: 0.5rem;
540
+ padding: 0.25rem 0.625rem 0.25rem 2.625rem;
541
+ border-top: 1px solid var(--border-light);
542
+ font-size: 0.6875rem; color: var(--text-muted);
543
+ }
544
+ .mg2-sub2__name { flex: 1; font-family: 'Fira Code', monospace; }
545
+ .mg2-sub2__name::before { content: '└ '; color: var(--border-color); }
546
+ .mg2-sub2__n { font-variant-numeric: tabular-nums; }
547
+
548
+ .mg2-unassigned {
549
+ display: flex; align-items: center; gap: 0.5rem;
550
+ font: inherit; font-size: 0.8125rem; color: var(--text-secondary);
551
+ padding: 0.5625rem 0.625rem; cursor: pointer; text-align: left; width: 100%;
552
+ border: 1px dashed var(--border-color); border-radius: var(--radius-md);
553
+ background: none; transition: all 0.13s ease;
554
+ }
555
+ .mg2-unassigned:hover { border-color: var(--text-muted); background: var(--bg-hover); }
556
+ .mg2-unassigned--on { border-style: solid; border-color: var(--color-primary); background: var(--color-primary-soft); }
557
+ .mg2-unassigned b { color: var(--text-primary); font-weight: 600; }
558
+ .mg2-unassigned__act {
559
+ margin-left: auto; font-size: 0.6875rem; font-weight: 600; text-transform: uppercase;
560
+ letter-spacing: 0.04em; color: var(--color-primary);
561
+ }
562
+
563
+ /* ───────── contextual assignment bar ───────── */
564
+ .mg2-bar {
565
+ flex-shrink: 0; overflow: hidden;
566
+ max-height: 0; opacity: 0;
567
+ border-top: 1px solid transparent;
568
+ background: linear-gradient(0deg, var(--color-primary-soft), var(--color-primary-soft)), var(--bg-secondary);
569
+ transition: max-height 0.22s cubic-bezier(0.2, 0.7, 0.3, 1), opacity 0.18s ease, border-color 0.2s ease;
570
+ }
571
+ .mg2-bar--open {
572
+ max-height: 160px; opacity: 1;
573
+ border-top-color: var(--color-primary);
574
+ }
575
+ .mg2-bar__inner {
576
+ display: flex; align-items: flex-end; flex-wrap: wrap; gap: 0.625rem 0.75rem;
577
+ padding: 0.6875rem 1.25rem; color: var(--text-secondary);
578
+ }
579
+ .mg2-bar .sg-btn { white-space: nowrap; flex-shrink: 0; }
580
+ .mg2-bar__count {
581
+ display: inline-flex; align-items: center; white-space: nowrap;
582
+ font-size: 0.8125rem; color: var(--text-primary); padding-bottom: 0.4375rem;
583
+ }
584
+ .mg2-bar__count b { font-weight: 700; font-variant-numeric: tabular-nums; }
585
+ .mg2-bar__inner > svg { color: var(--color-primary); margin-bottom: 0.5rem; flex-shrink: 0; }
586
+
587
+ .mg2-field { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
588
+ .mg2-field--grow { flex: 1 1 7rem; }
589
+ .mg2-field__l {
590
+ font-size: 0.625rem; font-weight: 600; text-transform: uppercase;
591
+ letter-spacing: 0.04em; color: var(--text-muted);
592
+ }
593
+ .mg2-combo {
594
+ position: relative; display: flex; align-items: center; gap: 0.4375rem;
595
+ padding: 0 0.625rem; height: 2.125rem;
596
+ background: var(--bg-secondary);
597
+ border: 1px solid var(--border-color); border-radius: var(--radius);
598
+ }
599
+ .mg2-combo:focus-within { border-color: var(--color-primary); box-shadow: var(--focus-ring-soft); }
600
+ .mg2-combo input {
601
+ flex: 1; min-width: 4rem; border: none; background: none; outline: none;
602
+ font: inherit; font-size: 0.8125rem; color: var(--text-primary);
603
+ }
604
+ .mg2-combo__chev { color: var(--text-muted); pointer-events: none; display: flex; }
605
+
606
+ .mg2-swatches { display: flex; gap: 0.3125rem; align-items: center; height: 2.125rem; }
607
+ .mg2-swatch {
608
+ width: 1.125rem; height: 1.125rem; border-radius: 9999px; cursor: pointer;
609
+ border: 2px solid transparent; box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.12);
610
+ transition: transform 0.12s ease;
611
+ }
612
+ .mg2-swatch:hover { transform: scale(1.12); }
613
+ .mg2-swatch--on {
614
+ border-color: var(--bg-secondary);
615
+ box-shadow: 0 0 0 2px currentColor, inset 0 0 0 1px rgb(0 0 0 / 0.12);
616
+ }
617
+
618
+ .mg2-bar__spacer { flex: 1; }
619
+ .mg2-bar__clear {
620
+ font: inherit; font-size: 0.8125rem; font-weight: 500; color: var(--text-secondary);
621
+ background: none; border: none; cursor: pointer; padding: 0.5rem 0.625rem;
622
+ border-radius: var(--radius); margin-bottom: 0.0625rem;
623
+ }
624
+ .mg2-bar__clear:hover { background: var(--bg-hover); color: var(--text-primary); }
625
+
626
+ /* ==========================================================================
627
+ CSV upload control (Field Recipe header) + drag-and-drop zone
628
+ ========================================================================== */
629
+ .fr-upload {
630
+ display: inline-flex; align-items: center; gap: 0.3125rem;
631
+ font: inherit; font-size: 0.75rem; font-weight: 500;
632
+ color: var(--text-secondary); cursor: pointer;
633
+ padding: 0.25rem 0.5rem; border-radius: var(--radius);
634
+ background: var(--bg-secondary); border: 1px solid var(--border-color);
635
+ transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
636
+ }
637
+ .fr-upload:hover {
638
+ background: var(--bg-tertiary); color: var(--text-primary); border-color: var(--text-muted);
639
+ }
640
+ .fr-upload:focus-visible { outline: none; box-shadow: var(--focus-ring-soft); }
641
+ .fr-csv { position: relative; }
642
+ .fr-csv-menu {
643
+ position: absolute; top: calc(100% + 0.25rem); right: 0; z-index: 10;
644
+ min-width: 11rem; padding: 0.25rem;
645
+ display: flex; flex-direction: column; gap: 0.0625rem;
646
+ background: var(--bg-secondary);
647
+ border: 1px solid var(--border-color); border-radius: var(--radius-md);
648
+ box-shadow: var(--shadow-lg);
649
+ }
650
+ .fr-csv-item {
651
+ display: flex; align-items: center; gap: 0.5rem;
652
+ font: inherit; font-size: 0.8125rem; font-weight: 500; text-align: left;
653
+ color: var(--text-primary); cursor: pointer;
654
+ padding: 0.4375rem 0.5rem; border: none; border-radius: var(--radius);
655
+ background: none; transition: background 0.12s ease, color 0.12s ease;
656
+ }
657
+ .fr-csv-item:hover { background: var(--bg-hover); }
658
+ .fr-csv-item:disabled {
659
+ /* disabled cue: muted colour + struck label + not-allowed, not opacity alone */
660
+ color: var(--text-muted); cursor: not-allowed; opacity: 0.7;
661
+ text-decoration: line-through; text-decoration-color: var(--text-muted);
662
+ }
663
+ .fr-csv-item:disabled:hover { background: none; }
664
+ /* anchor the drop overlay to the main panel */
665
+ .sg-body__main { position: relative; }
666
+ .fr-dropzone {
667
+ position: absolute; inset: 0.5rem; z-index: 2;
668
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
669
+ gap: 0.5rem; pointer-events: none;
670
+ border: 2px dashed var(--color-primary); border-radius: var(--radius-md);
671
+ background: var(--color-primary-soft);
672
+ color: var(--color-primary-hover); font-size: 0.8125rem; font-weight: 600;
673
+ }
674
+ .fr-loading {
675
+ position: absolute; inset: 0; z-index: 3;
676
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
677
+ gap: 0.625rem;
678
+ background: var(--bg-secondary);
679
+ color: var(--text-secondary); font-size: 0.8125rem;
680
+ }
681
+
682
+ /* ==========================================================================
683
+ Host adapter — when AutoGroupModal renders the Smart Group card inside
684
+ BaseModal, strip BaseModal's own chrome/padding so the .sg-modal card is the
685
+ only visible frame, and size it to the design.
686
+ ========================================================================== */
687
+ /* Keyed on the presence of .sg-modal (not the fallthrough `.sg-host` class,
688
+ which doesn't reliably reach BaseModal's Teleport root) so the flatten always
689
+ applies under BaseModal, and never matches the bare-rendered standalone
690
+ stories (they have no .mint-modal ancestor). After this there is exactly one
691
+ card edge — the .sg-modal one. */
692
+ .mint-modal__container:has(.sg-modal) {
693
+ width: 980px;
694
+ max-width: calc(100vw - 2rem);
695
+ padding: 0;
696
+ background: transparent;
697
+ border: none;
698
+ border-radius: 0;
699
+ box-shadow: none;
700
+ }
701
+ .mint-modal__body:has(.sg-modal) {
702
+ padding: 0;
703
+ background: transparent;
704
+ }
705
+ .mint-modal__container:has(.sg-modal) .sg-modal {
706
+ height: min(640px, calc(100vh - 4rem));
707
+ }
708
+ .sg-host__error { margin: 0 0 0.75rem; }