@proveanything/smartlinks-utils-ui 0.4.2 → 0.6.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.
- package/dist/{chunk-76Y4UTYQ.js → chunk-WB775Z2I.js} +66 -60
- package/dist/chunk-WB775Z2I.js.map +1 -0
- package/dist/components/RecordsAdmin/index.d.ts +133 -86
- package/dist/components/RecordsAdmin/index.js +271 -226
- package/dist/components/RecordsAdmin/index.js.map +1 -1
- package/dist/records-JWS6LKJ2.js +3 -0
- package/dist/{records-AUJWCB7Q.js.map → records-JWS6LKJ2.js.map} +1 -1
- package/package.json +6 -6
- package/dist/chunk-76Y4UTYQ.js.map +0 -1
- package/dist/records-AUJWCB7Q.js +0 -3
|
@@ -2,8 +2,8 @@ import { styleInject } from '../../chunk-HXJLROC2.js';
|
|
|
2
2
|
import { FacetRuleEditor } from '../../chunk-JMCV6FOW.js';
|
|
3
3
|
import { useFacets } from '../../chunk-4LHF5JB7.js';
|
|
4
4
|
import { cn } from '../../chunk-L7FQ52F5.js';
|
|
5
|
-
import { listRecords,
|
|
6
|
-
export { bulkDelete, bulkUpsert,
|
|
5
|
+
import { listRecords, parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, getRecordById, updateRecord, upsertRecord, removeRecord } from '../../chunk-WB775Z2I.js';
|
|
6
|
+
export { bulkDelete, bulkUpsert, getRecordById, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, removeRecord, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-WB775Z2I.js';
|
|
7
7
|
import { createContext, useMemo, useState, useEffect, useCallback, useRef, useContext, createElement } from 'react';
|
|
8
8
|
import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Rows3, List, ChevronRight, Eraser, ClipboardPaste, Box, X, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, Search, CornerDownLeft, Circle, AlertCircle, Undo2, Save, Target, Settings2 } from 'lucide-react';
|
|
9
9
|
import { useQueryClient, useInfiniteQuery, useQuery } from '@tanstack/react-query';
|
|
@@ -138,7 +138,7 @@ var ALL_ITEM_VIEWS = ["table", "cards", "gallery"];
|
|
|
138
138
|
|
|
139
139
|
// src/components/RecordsAdmin/types/deepLink.ts
|
|
140
140
|
var DEFAULT_DEEP_LINK_PARAM_NAMES = {
|
|
141
|
-
|
|
141
|
+
recordId: "recordId",
|
|
142
142
|
scope: "scope",
|
|
143
143
|
view: "view"
|
|
144
144
|
};
|
|
@@ -150,11 +150,7 @@ var KIND_KEYS = {
|
|
|
150
150
|
variant: "variantId",
|
|
151
151
|
batch: "batchId",
|
|
152
152
|
proof: "proofId",
|
|
153
|
-
collection: "collectionId"
|
|
154
|
-
// `rule` records carry an opaque id under the `rule:` prefix; we expose
|
|
155
|
-
// the id via `productId`-equivalent slot to keep ParsedRef flat. Resolved
|
|
156
|
-
// refs use the `ruleId` field (added below) so callers can disambiguate.
|
|
157
|
-
rule: "ruleId"
|
|
153
|
+
collection: "collectionId"
|
|
158
154
|
};
|
|
159
155
|
var parseRef = (raw) => {
|
|
160
156
|
const parsed = { kind: "collection", raw };
|
|
@@ -174,11 +170,9 @@ var parseRef = (raw) => {
|
|
|
174
170
|
} else {
|
|
175
171
|
parsed.facetId = id;
|
|
176
172
|
}
|
|
177
|
-
} else if (k === "item") {
|
|
178
|
-
parsed.itemId = id;
|
|
179
|
-
continue;
|
|
180
173
|
} else if (k in KIND_KEYS) {
|
|
181
|
-
|
|
174
|
+
const slot = KIND_KEYS[k];
|
|
175
|
+
parsed[slot] = id;
|
|
182
176
|
}
|
|
183
177
|
if (k !== "collection") kind = k;
|
|
184
178
|
}
|
|
@@ -194,7 +188,6 @@ var buildRef = (a) => {
|
|
|
194
188
|
if (a.variantId) parts.push(`variant:${a.variantId}`);
|
|
195
189
|
if (a.batchId) parts.push(`batch:${a.batchId}`);
|
|
196
190
|
if (a.proofId) parts.push(`proof:${a.proofId}`);
|
|
197
|
-
if (a.itemId) parts.push(`item:${a.itemId}`);
|
|
198
191
|
return parts.join("/");
|
|
199
192
|
};
|
|
200
193
|
var resolutionChain = (target, supportedScopes) => {
|
|
@@ -216,35 +209,26 @@ var resolutionChain = (target, supportedScopes) => {
|
|
|
216
209
|
}
|
|
217
210
|
return Array.from(new Set(chain));
|
|
218
211
|
};
|
|
219
|
-
var splitItemRef = (raw) => {
|
|
220
|
-
if (!raw) return { scopeRef: "" };
|
|
221
|
-
const segs = raw.split("/").filter(Boolean);
|
|
222
|
-
const last = segs[segs.length - 1];
|
|
223
|
-
if (last && last.startsWith("item:")) {
|
|
224
|
-
return { scopeRef: segs.slice(0, -1).join("/"), itemId: last.slice("item:".length) };
|
|
225
|
-
}
|
|
226
|
-
return { scopeRef: raw };
|
|
227
|
-
};
|
|
228
|
-
var buildItemRef = (scopeRef, itemId) => {
|
|
229
|
-
return scopeRef ? `${scopeRef}/item:${itemId}` : `item:${itemId}`;
|
|
230
|
-
};
|
|
231
212
|
var defaultClassify = (r) => {
|
|
232
213
|
if (!r.data) return "empty";
|
|
233
214
|
const keys = Object.keys(r.data);
|
|
234
215
|
if (keys.length === 0) return "empty";
|
|
235
216
|
return "configured";
|
|
236
217
|
};
|
|
237
|
-
var matchesScope = (kind, rec,
|
|
238
|
-
const hasRule = !!rec.facetRule
|
|
218
|
+
var matchesScope = (kind, rec, _p) => {
|
|
219
|
+
const hasRule = !!rec.facetRule;
|
|
239
220
|
if (kind === "rule") return hasRule;
|
|
240
221
|
if (hasRule) return false;
|
|
222
|
+
const productId = rec.productId ?? void 0;
|
|
223
|
+
const variantId = rec.variantId ?? void 0;
|
|
224
|
+
const batchId = rec.batchId ?? void 0;
|
|
225
|
+
const proofId = rec.proofId ?? void 0;
|
|
241
226
|
if (kind === "collection") {
|
|
242
|
-
return !
|
|
227
|
+
return !productId && !variantId && !batchId && !proofId;
|
|
243
228
|
}
|
|
244
|
-
if (kind === "product") return !!
|
|
245
|
-
if (kind === "
|
|
246
|
-
if (kind === "
|
|
247
|
-
if (kind === "batch") return !!p.batchId;
|
|
229
|
+
if (kind === "product") return !!productId && !variantId && !batchId;
|
|
230
|
+
if (kind === "variant") return !!variantId;
|
|
231
|
+
if (kind === "batch") return !!batchId;
|
|
248
232
|
return false;
|
|
249
233
|
};
|
|
250
234
|
var matchesContext = (p, ctx) => {
|
|
@@ -256,10 +240,22 @@ var matchesContext = (p, ctx) => {
|
|
|
256
240
|
};
|
|
257
241
|
var toSummary = (rec) => {
|
|
258
242
|
const ref = rec.ref ?? "";
|
|
259
|
-
const
|
|
243
|
+
const productId = rec.productId ?? void 0;
|
|
244
|
+
const variantId = rec.variantId ?? void 0;
|
|
245
|
+
const batchId = rec.batchId ?? void 0;
|
|
246
|
+
const proofId = rec.proofId ?? void 0;
|
|
247
|
+
const scope = {
|
|
248
|
+
kind: batchId ? "batch" : variantId ? "variant" : productId ? "product" : "collection",
|
|
249
|
+
raw: ref,
|
|
250
|
+
productId,
|
|
251
|
+
variantId,
|
|
252
|
+
batchId,
|
|
253
|
+
proofId
|
|
254
|
+
};
|
|
260
255
|
const facetRule = rec.facetRule ?? null;
|
|
256
|
+
if (facetRule) scope.kind = "rule";
|
|
261
257
|
const ruleLabel = facetRule && facetRule.all && facetRule.all.length > 0 ? facetRule.all.length === 1 ? "Rule \xB7 1 facet" : `Rule \xB7 ${facetRule.all.length} facets` : null;
|
|
262
|
-
const fallbackLabel = scope.batchId ?? scope.variantId ?? scope.productId ??
|
|
258
|
+
const fallbackLabel = scope.batchId ?? scope.variantId ?? scope.productId ?? ruleLabel ?? (ref || "Global record");
|
|
263
259
|
return {
|
|
264
260
|
id: rec.id,
|
|
265
261
|
ref,
|
|
@@ -365,57 +361,65 @@ var useRecordList = (args) => {
|
|
|
365
361
|
|
|
366
362
|
// src/components/RecordsAdmin/data/resolveRecord.ts
|
|
367
363
|
var resolveRecord = async (args) => {
|
|
368
|
-
if (args.target.kind === "rule" && args.target.raw) {
|
|
369
|
-
const rec = await getRecordByRef(args.ctx, args.target.raw).catch(() => null);
|
|
370
|
-
if (!rec) return { data: null, source: "empty" };
|
|
371
|
-
const recFacetRule = rec.facetRule ?? null;
|
|
372
|
-
return {
|
|
373
|
-
data: rec.data,
|
|
374
|
-
source: "self",
|
|
375
|
-
sourceRef: rec.ref ?? args.target.raw,
|
|
376
|
-
facetRule: recFacetRule
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
364
|
const target = parsedRefToTarget(args.target);
|
|
380
365
|
const editingScope = parsedRefToScope(args.target);
|
|
381
366
|
const result = await matchRecords(args.ctx, target, { strategy: "all" }).catch(() => null);
|
|
382
|
-
const
|
|
367
|
+
const entries = result?.data ?? [];
|
|
383
368
|
console.info("[RecordsAdmin/resolveRecord]", {
|
|
384
369
|
editingScope,
|
|
385
370
|
target,
|
|
386
|
-
matchCount:
|
|
387
|
-
|
|
388
|
-
|
|
371
|
+
matchCount: entries.length,
|
|
372
|
+
winnerAnchors: entries[0] && {
|
|
373
|
+
productId: entries[0].productId,
|
|
374
|
+
variantId: entries[0].variantId,
|
|
375
|
+
batchId: entries[0].batchId,
|
|
376
|
+
proofId: entries[0].proofId
|
|
377
|
+
},
|
|
378
|
+
winnerRef: entries[0]?.ref
|
|
389
379
|
});
|
|
390
|
-
if (
|
|
380
|
+
if (entries.length === 0) {
|
|
391
381
|
return { data: null, source: "empty" };
|
|
392
382
|
}
|
|
393
|
-
const
|
|
394
|
-
const
|
|
395
|
-
|
|
383
|
+
const winner = entries[0];
|
|
384
|
+
const winnerIsSelf = scopesEqual(
|
|
385
|
+
{
|
|
386
|
+
productId: winner.productId,
|
|
387
|
+
variantId: winner.variantId,
|
|
388
|
+
batchId: winner.batchId,
|
|
389
|
+
proofId: winner.proofId
|
|
390
|
+
},
|
|
391
|
+
editingScope
|
|
392
|
+
);
|
|
396
393
|
console.info("[RecordsAdmin/resolveRecord] classification", {
|
|
397
394
|
winnerIsSelf,
|
|
398
|
-
|
|
395
|
+
winnerAnchors: {
|
|
396
|
+
productId: winner.productId,
|
|
397
|
+
variantId: winner.variantId,
|
|
398
|
+
batchId: winner.batchId,
|
|
399
|
+
proofId: winner.proofId
|
|
400
|
+
},
|
|
399
401
|
editingScope
|
|
400
402
|
});
|
|
401
403
|
if (winnerIsSelf) {
|
|
402
|
-
const parent =
|
|
404
|
+
const parent = entries[1];
|
|
403
405
|
return {
|
|
404
406
|
data: winner.data,
|
|
405
407
|
source: "self",
|
|
406
408
|
sourceRef: winner.ref ?? void 0,
|
|
409
|
+
recordId: winner.id,
|
|
407
410
|
parentValue: args.withParent && parent ? parent.data : void 0,
|
|
408
|
-
matchedAt:
|
|
409
|
-
matchedRule:
|
|
411
|
+
matchedAt: winner.matchedAt,
|
|
412
|
+
matchedRule: winner.matchedRule
|
|
410
413
|
};
|
|
411
414
|
}
|
|
412
415
|
return {
|
|
413
416
|
data: winner.data,
|
|
414
417
|
source: "inherited",
|
|
415
418
|
sourceRef: winner.ref ?? void 0,
|
|
419
|
+
recordId: winner.id,
|
|
416
420
|
parentValue: args.withParent ? winner.data : void 0,
|
|
417
|
-
matchedAt:
|
|
418
|
-
matchedRule:
|
|
421
|
+
matchedAt: winner.matchedAt,
|
|
422
|
+
matchedRule: winner.matchedRule
|
|
419
423
|
};
|
|
420
424
|
};
|
|
421
425
|
|
|
@@ -433,7 +437,7 @@ var resolvedRecordQueryKey = (args) => [
|
|
|
433
437
|
args.facetId ?? null,
|
|
434
438
|
args.facetValue ?? null,
|
|
435
439
|
args.proofId ?? null,
|
|
436
|
-
args.
|
|
440
|
+
args.recordId ?? null,
|
|
437
441
|
args.withParent ?? true
|
|
438
442
|
];
|
|
439
443
|
function useResolvedRecord(args) {
|
|
@@ -448,7 +452,7 @@ function useResolvedRecord(args) {
|
|
|
448
452
|
facetId,
|
|
449
453
|
facetValue,
|
|
450
454
|
proofId,
|
|
451
|
-
|
|
455
|
+
recordId,
|
|
452
456
|
supportedScopes = DEFAULT_SCOPES,
|
|
453
457
|
enabled = true,
|
|
454
458
|
withParent = true
|
|
@@ -464,19 +468,35 @@ function useResolvedRecord(args) {
|
|
|
464
468
|
facetId,
|
|
465
469
|
facetValue,
|
|
466
470
|
proofId,
|
|
467
|
-
|
|
471
|
+
recordId,
|
|
468
472
|
withParent
|
|
469
473
|
}),
|
|
470
474
|
enabled: enabled && !!collectionId && !!appId,
|
|
471
475
|
staleTime: 15e3,
|
|
472
476
|
queryFn: async () => {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
477
|
+
if (recordId) {
|
|
478
|
+
const rec = await getRecordById({ SL, collectionId, appId, recordType }, recordId);
|
|
479
|
+
if (!rec) return { data: null, source: "empty" };
|
|
480
|
+
const recFacetRule = rec.facetRule ?? null;
|
|
481
|
+
return {
|
|
482
|
+
data: rec.data,
|
|
483
|
+
source: "self",
|
|
484
|
+
sourceRef: rec.ref ?? void 0,
|
|
485
|
+
recordId: rec.id,
|
|
486
|
+
facetRule: recFacetRule
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
const target = {
|
|
490
|
+
kind: batchId ? "batch" : variantId ? "variant" : productId ? "product" : facetId ? "facet" : "collection",
|
|
491
|
+
raw: "",
|
|
492
|
+
collectionId,
|
|
493
|
+
productId,
|
|
494
|
+
variantId,
|
|
495
|
+
batchId,
|
|
496
|
+
facetId,
|
|
497
|
+
facetValue,
|
|
498
|
+
proofId
|
|
499
|
+
};
|
|
480
500
|
return resolveRecord({
|
|
481
501
|
ctx: { SL, collectionId, appId, recordType },
|
|
482
502
|
target,
|
|
@@ -527,8 +547,8 @@ function useRulePreview(args) {
|
|
|
527
547
|
})
|
|
528
548
|
});
|
|
529
549
|
return {
|
|
530
|
-
totalMatches: query.data?.
|
|
531
|
-
sampleProductIds: query.data?.
|
|
550
|
+
totalMatches: query.data?.total ?? null,
|
|
551
|
+
sampleProductIds: (query.data?.matchingProducts ?? []).map((p) => p.productId),
|
|
532
552
|
isLoading: query.isFetching,
|
|
533
553
|
isStale: rule !== debouncedRule,
|
|
534
554
|
error: query.error ?? null
|
|
@@ -594,7 +614,10 @@ function useRecordEditor(args) {
|
|
|
594
614
|
}, [scope.raw, resolved.source, resolved.sourceRef]);
|
|
595
615
|
const isDirty = !isEqual(value, savedSnapshot) || !isEqual(facetRule, savedFacetRule);
|
|
596
616
|
const save = useCallback(async () => {
|
|
597
|
-
|
|
617
|
+
const anchors = parsedRefToScope(scope);
|
|
618
|
+
const hasAnchors = !!(anchors.productId || anchors.variantId || anchors.batchId || anchors.proofId);
|
|
619
|
+
const hasRule = !!(facetRule && facetRule.all && facetRule.all.length > 0);
|
|
620
|
+
if (!hasAnchors && !hasRule && !scope.raw) return;
|
|
598
621
|
const previousSnapshot = savedSnapshot;
|
|
599
622
|
const previousRuleSnapshot = savedFacetRule;
|
|
600
623
|
resolved.source;
|
|
@@ -608,7 +631,7 @@ function useRecordEditor(args) {
|
|
|
608
631
|
facetId: scope.facetId,
|
|
609
632
|
facetValue: scope.facetValue,
|
|
610
633
|
proofId: scope.proofId,
|
|
611
|
-
|
|
634
|
+
recordId: resolved.recordId,
|
|
612
635
|
withParent: true
|
|
613
636
|
});
|
|
614
637
|
const previousCache = queryClient.getQueryData(cacheKey);
|
|
@@ -621,15 +644,26 @@ function useRecordEditor(args) {
|
|
|
621
644
|
data: value,
|
|
622
645
|
source: "self",
|
|
623
646
|
sourceRef: scope.raw,
|
|
647
|
+
recordId: resolved.recordId,
|
|
624
648
|
parentValue: previousCache?.parentValue ?? resolved.parentValue
|
|
625
649
|
});
|
|
626
650
|
try {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}
|
|
651
|
+
if (resolved.recordId && resolved.source === "self") {
|
|
652
|
+
await updateRecord(ctx, resolved.recordId, {
|
|
653
|
+
data: value,
|
|
654
|
+
facetRule
|
|
655
|
+
});
|
|
656
|
+
} else {
|
|
657
|
+
await upsertRecord(ctx, {
|
|
658
|
+
// External ref only when the underlying scope already carries
|
|
659
|
+
// one (e.g. rule:{id} for an existing rule record). Empty for
|
|
660
|
+
// anchor-only writes — server addresses by anchors.
|
|
661
|
+
ref: scope.kind === "rule" && scope.raw ? scope.raw : void 0,
|
|
662
|
+
scope: anchors,
|
|
663
|
+
data: value,
|
|
664
|
+
facetRule
|
|
665
|
+
});
|
|
666
|
+
}
|
|
633
667
|
onSaved?.();
|
|
634
668
|
} catch (err) {
|
|
635
669
|
setSavedSnapshot(previousSnapshot);
|
|
@@ -646,16 +680,17 @@ function useRecordEditor(args) {
|
|
|
646
680
|
} finally {
|
|
647
681
|
setIsSaving(false);
|
|
648
682
|
}
|
|
649
|
-
}, [scope.raw, value, savedSnapshot, facetRule, savedFacetRule, resolved.source, resolved.parentValue]);
|
|
683
|
+
}, [scope.raw, value, savedSnapshot, facetRule, savedFacetRule, resolved.source, resolved.parentValue, resolved.recordId]);
|
|
650
684
|
const reset = useCallback(() => {
|
|
651
685
|
setValue(savedSnapshot);
|
|
652
686
|
setFacetRule(savedFacetRule);
|
|
653
687
|
}, [savedSnapshot, savedFacetRule]);
|
|
654
688
|
const remove = useCallback(async () => {
|
|
655
|
-
if (resolved.source !== "self"
|
|
656
|
-
|
|
689
|
+
if (resolved.source !== "self") return;
|
|
690
|
+
if (!resolved.recordId) return;
|
|
691
|
+
await removeRecord(ctx, resolved.recordId);
|
|
657
692
|
onDeleted?.();
|
|
658
|
-
}, [resolved.source,
|
|
693
|
+
}, [resolved.source, resolved.recordId]);
|
|
659
694
|
const effectiveSource = optimisticSource ?? resolved.source;
|
|
660
695
|
const isRuleScope = scope.kind === "rule";
|
|
661
696
|
const ruleValid = !isRuleScope || isFacetRuleValid(facetRule);
|
|
@@ -1649,9 +1684,11 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
|
|
|
1649
1684
|
};
|
|
1650
1685
|
var RecordList = ({
|
|
1651
1686
|
items,
|
|
1652
|
-
|
|
1687
|
+
selectedId,
|
|
1688
|
+
selectedAnchorKey,
|
|
1653
1689
|
onSelect,
|
|
1654
|
-
|
|
1690
|
+
dirtyId,
|
|
1691
|
+
dirtyAnchorKey,
|
|
1655
1692
|
presentation = "list",
|
|
1656
1693
|
renderListRow,
|
|
1657
1694
|
groupBy,
|
|
@@ -1659,10 +1696,14 @@ var RecordList = ({
|
|
|
1659
1696
|
}) => {
|
|
1660
1697
|
const buildCtx = (item) => {
|
|
1661
1698
|
const cb = rowClipboard ? rowClipboard(item) : null;
|
|
1699
|
+
const idMatch = selectedId != null && item.id != null && item.id === selectedId;
|
|
1700
|
+
const anchorMatch = selectedAnchorKey != null && item.ref === selectedAnchorKey;
|
|
1701
|
+
const dirtyIdMatch = dirtyId != null && item.id != null && item.id === dirtyId;
|
|
1702
|
+
const dirtyAnchorMatch = dirtyAnchorKey != null && item.ref === dirtyAnchorKey;
|
|
1662
1703
|
return {
|
|
1663
|
-
selected:
|
|
1704
|
+
selected: idMatch || anchorMatch,
|
|
1664
1705
|
onSelect: () => onSelect(item),
|
|
1665
|
-
isDirty:
|
|
1706
|
+
isDirty: dirtyIdMatch || dirtyAnchorMatch,
|
|
1666
1707
|
...cb ?? {}
|
|
1667
1708
|
};
|
|
1668
1709
|
};
|
|
@@ -1684,7 +1725,7 @@ var RecordList = ({
|
|
|
1684
1725
|
const compact = presentation === "compact";
|
|
1685
1726
|
return /* @__PURE__ */ jsx("ul", { children: rows.map((item) => {
|
|
1686
1727
|
const ctx = buildCtx(item);
|
|
1687
|
-
return /* @__PURE__ */ jsx("li", { children: renderListRow ? renderListRow(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: item, ctx, compact }) }, item.ref);
|
|
1728
|
+
return /* @__PURE__ */ jsx("li", { children: renderListRow ? renderListRow(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: item, ctx, compact }) }, item.id ?? item.ref);
|
|
1688
1729
|
}) });
|
|
1689
1730
|
};
|
|
1690
1731
|
if (groups) {
|
|
@@ -2048,12 +2089,18 @@ function useItemViewPref(args) {
|
|
|
2048
2089
|
var QK_BASE2 = ["records-admin", "collection-items"];
|
|
2049
2090
|
var defaultToSummary = (rec, base) => {
|
|
2050
2091
|
const data = rec.data;
|
|
2092
|
+
const display = data?.display ?? void 0;
|
|
2051
2093
|
if (!data) return base;
|
|
2052
|
-
const label = data.title ?? data.name ?? data.label ?? data.question ?? base.label;
|
|
2053
|
-
const subtitle = data.subtitle ?? data.summary ?? data.description ?? base.subtitle;
|
|
2054
|
-
const thumbnail = data.thumbnail ?? data.image ?? data.cover ?? base.thumbnail;
|
|
2094
|
+
const label = data.title ?? display?.title ?? data.name ?? data.label ?? data.question ?? data.slug ?? base.label;
|
|
2095
|
+
const subtitle = data.subtitle ?? data.summary ?? display?.description ?? data.description ?? base.subtitle;
|
|
2096
|
+
const thumbnail = data.thumbnail ?? data.image ?? data.cover ?? data.home_image_url ?? base.thumbnail;
|
|
2055
2097
|
return { ...base, label, subtitle, thumbnail };
|
|
2056
2098
|
};
|
|
2099
|
+
var recordMatchesScope = (rec, scope) => {
|
|
2100
|
+
const facetRule = rec.facetRule ?? null;
|
|
2101
|
+
if (facetRule) return false;
|
|
2102
|
+
return (rec.productId ?? void 0) === scope.productId && (rec.variantId ?? void 0) === scope.variantId && (rec.batchId ?? void 0) === scope.batchId && (rec.proofId ?? void 0) === scope.proofId;
|
|
2103
|
+
};
|
|
2057
2104
|
function useCollectionItems(args) {
|
|
2058
2105
|
const {
|
|
2059
2106
|
ctx,
|
|
@@ -2064,7 +2111,6 @@ function useCollectionItems(args) {
|
|
|
2064
2111
|
} = args;
|
|
2065
2112
|
const queryClient = useQueryClient();
|
|
2066
2113
|
const scopeRef = scope?.raw ?? "";
|
|
2067
|
-
const refPrefix = scopeRef ? `${scopeRef}/item:` : "item:";
|
|
2068
2114
|
const queryKey = useMemo(
|
|
2069
2115
|
() => [...QK_BASE2, ctx.collectionId, ctx.appId, ctx.recordType, scopeRef],
|
|
2070
2116
|
[ctx.collectionId, ctx.appId, ctx.recordType, scopeRef]
|
|
@@ -2077,8 +2123,7 @@ function useCollectionItems(args) {
|
|
|
2077
2123
|
const offset = pageParam;
|
|
2078
2124
|
const { data, total, hasMore } = await listRecords(ctx, {
|
|
2079
2125
|
limit: pageSize,
|
|
2080
|
-
offset
|
|
2081
|
-
refPrefix
|
|
2126
|
+
offset
|
|
2082
2127
|
});
|
|
2083
2128
|
return { data, total, hasMore, nextOffset: offset + data.length };
|
|
2084
2129
|
},
|
|
@@ -2086,25 +2131,26 @@ function useCollectionItems(args) {
|
|
|
2086
2131
|
staleTime: 15e3
|
|
2087
2132
|
});
|
|
2088
2133
|
const items = useMemo(() => {
|
|
2134
|
+
if (!scope) return [];
|
|
2089
2135
|
const all = query.data?.pages.flatMap((p) => p.data) ?? [];
|
|
2090
|
-
|
|
2136
|
+
const relevant = all.filter((rec) => recordMatchesScope(rec, scope));
|
|
2137
|
+
return relevant.map((rec) => {
|
|
2091
2138
|
const ref = rec.ref ?? "";
|
|
2092
2139
|
const parsed = parseRef(ref);
|
|
2093
|
-
const
|
|
2094
|
-
if (!itemId) return null;
|
|
2140
|
+
const stableItemId = rec.id;
|
|
2095
2141
|
const base = {
|
|
2096
2142
|
id: rec.id,
|
|
2097
2143
|
ref,
|
|
2098
2144
|
scope: parsed,
|
|
2099
2145
|
data: rec.data ?? null,
|
|
2100
2146
|
status: rec.data ? "configured" : "empty",
|
|
2101
|
-
label:
|
|
2147
|
+
label: stableItemId,
|
|
2102
2148
|
updatedAt: rec.updatedAt,
|
|
2103
|
-
itemId
|
|
2149
|
+
itemId: stableItemId
|
|
2104
2150
|
};
|
|
2105
2151
|
return toSummary2(rec, base);
|
|
2106
2152
|
}).filter((x) => x !== null);
|
|
2107
|
-
}, [query.data, toSummary2]);
|
|
2153
|
+
}, [query.data, toSummary2, scope]);
|
|
2108
2154
|
const refetch = useCallback(() => {
|
|
2109
2155
|
queryClient.invalidateQueries({ queryKey });
|
|
2110
2156
|
}, [queryClient, queryKey]);
|
|
@@ -2146,7 +2192,7 @@ var createDefaultDeepLinkAdapter = (paramNames) => ({
|
|
|
2146
2192
|
if (typeof window === "undefined") return {};
|
|
2147
2193
|
const params = new URLSearchParams(getQueryString(window.location));
|
|
2148
2194
|
return {
|
|
2149
|
-
|
|
2195
|
+
recordId: params.get(paramNames.recordId),
|
|
2150
2196
|
scope: params.get(paramNames.scope),
|
|
2151
2197
|
view: params.get(paramNames.view)
|
|
2152
2198
|
};
|
|
@@ -2158,7 +2204,7 @@ var createDefaultDeepLinkAdapter = (paramNames) => ({
|
|
|
2158
2204
|
if (value == null || value === "") params.delete(key);
|
|
2159
2205
|
else params.set(key, value);
|
|
2160
2206
|
};
|
|
2161
|
-
if ("
|
|
2207
|
+
if ("recordId" in partial) apply(paramNames.recordId, partial.recordId);
|
|
2162
2208
|
if ("scope" in partial) apply(paramNames.scope, partial.scope);
|
|
2163
2209
|
if ("view" in partial) apply(paramNames.view, partial.view);
|
|
2164
2210
|
const nextUrl = buildUrl(window.location, params.toString());
|
|
@@ -2178,7 +2224,7 @@ var createDefaultDeepLinkAdapter = (paramNames) => ({
|
|
|
2178
2224
|
});
|
|
2179
2225
|
|
|
2180
2226
|
// src/components/RecordsAdmin/hooks/useDeepLinkState.ts
|
|
2181
|
-
var SMART_PUSH = ["
|
|
2227
|
+
var SMART_PUSH = ["record.open", "record.close", "scope"];
|
|
2182
2228
|
var classify = (mode, kind) => {
|
|
2183
2229
|
if (mode === "push") return "push";
|
|
2184
2230
|
if (mode === "replace") return "replace";
|
|
@@ -3831,19 +3877,10 @@ var downloadBlob = (blob, filename) => {
|
|
|
3831
3877
|
styleInject(':root {\n --ra-status-own: var(--ra-emerald, 142 71% 45%);\n --ra-status-shared: var(--ra-amber, 38 92% 50%);\n --ra-status-missing: var(--muted-foreground, 220 9% 46%);\n --ra-accent: var(--primary, 222 47% 11%);\n --ra-surface: var(--card, 0 0% 100%);\n --ra-border: var(--border, 220 13% 91%);\n --ra-text: var(--foreground, 222 47% 11%);\n --ra-muted: var(--muted, 220 14% 96%);\n --ra-muted-text: var(--muted-foreground, 220 9% 46%);\n --ra-radius: var(--radius, 0.625rem);\n --ra-dot-size: 0.5rem;\n --ra-page-bg: var(--background, 220 14% 98%);\n --ra-card-shadow: 0 1px 2px hsl(var(--ra-accent) / 0.04), 0 4px 12px hsl(var(--ra-accent) / 0.05);\n --ra-card-shadow-hover: 0 2px 4px hsl(var(--ra-accent) / 0.06), 0 8px 24px hsl(var(--ra-accent) / 0.08);\n --ra-row-hover: hsl(var(--ra-accent) / 0.05);\n --ra-row-active-bg: hsl(var(--ra-accent) / 0.10);\n --ra-row-active-bd: hsl(var(--ra-accent) / 0.45);\n --ra-focus-ring: hsl(var(--ra-accent) / 0.35);\n --ra-font-display: var(--font-display, var(--font-sans, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif));\n --ra-font-ui: var(--font-sans, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);\n --ra-title-weight: 600;\n --ra-display-weight: 700;\n --ra-info: var(--ra-blue, 214 95% 55%);\n --ra-success: var(--ra-emerald, 142 71% 45%);\n --ra-warning: var(--ra-amber, 38 92% 50%);\n --ra-danger: var(--destructive, 0 72% 51%);\n}\n:root {\n --sl-control-bg: var(--muted, 220 14% 96%);\n --sl-control-fg: var(--muted-foreground, 220 9% 40%);\n --sl-control-border: var(--border, 220 13% 88%);\n --sl-control-active-bg: var(--primary, 222 47% 11%);\n --sl-control-active-fg: var(--primary-foreground, 0 0% 100%);\n --sl-control-active-bd: var(--primary, 222 47% 11%);\n --sl-control-hover-bg: var(--sl-control-active-bg, 222 47% 11%);\n --sl-control-hover-fg: var(--foreground, 222 47% 11%);\n --sl-control-focus-ring: var(--sl-control-active-bg, 222 47% 11%);\n --sl-control-radius: var(--radius, 0.5rem);\n --sl-control-weight: 500;\n --sl-control-active-weight: 600;\n}\n.ra-status-dot {\n display: inline-block;\n width: var(--ra-dot-size);\n height: var(--ra-dot-size);\n border-radius: 9999px;\n flex-shrink: 0;\n}\n.ra-status-own {\n background: hsl(var(--ra-status-own));\n}\n.ra-status-shared {\n background: hsl(var(--ra-status-shared));\n}\n.ra-status-missing {\n background: hsl(var(--ra-status-missing) / 0.4);\n border: 1px solid hsl(var(--ra-status-missing) / 0.6);\n}\n.ra-row-active {\n background: var(--ra-row-active-bg);\n border-color: var(--ra-row-active-bd) !important;\n}\n');
|
|
3832
3878
|
|
|
3833
3879
|
// src/components/RecordsAdmin/shell/shell.css
|
|
3834
|
-
styleInject(".ra-shell {\n color: hsl(var(--ra-text));\n background: hsl(var(--ra-page-bg));\n font-family: var(--ra-font-ui);\n}\n.ra-shell *,\n.ra-shell *::before,\n.ra-shell *::after {\n box-sizing: border-box;\n}\n.ra-shell .ra-card {\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-card-hover {\n transition:\n box-shadow .18s ease,\n transform .18s ease,\n border-color .18s ease;\n}\n.ra-shell .ra-card-hover:hover {\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-display {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-title {\n font-weight: var(--ra-title-weight);\n}\n.ra-shell :where(button, [role=button], input, select, textarea, a):focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n border-radius: calc(var(--ra-radius) * 0.6);\n}\n.ra-shell .ra-header {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.65rem 0.9rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-accent) / 0.12);\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.08),\n hsl(var(--ra-accent) / 0.02) 60%,\n hsl(var(--ra-surface)) 100%);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-header__main {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 0.625rem;\n}\n.ra-shell .ra-header-aside {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-header-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: calc(var(--ra-radius) * 0.9);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.18);\n}\n.ra-shell .ra-header-text {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-header-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n letter-spacing: -0.01em;\n margin: 0;\n}\n.ra-shell .ra-header-subtitle {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-header-stats {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n padding: 0.15rem 0.4rem;\n border-radius: calc(var(--ra-radius) * 0.75);\n background: hsl(var(--ra-surface) / 0.7);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-header-stats--titled {\n flex-direction: column;\n align-items: stretch;\n padding: 0.4rem 0.55rem;\n gap: 0.3rem;\n}\n.ra-shell .ra-header-stats .ra-stats-items {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n}\n.ra-shell .ra-header-stats .ra-stats-heading {\n display: flex;\n align-items: center;\n gap: 0.35rem;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon {\n display: inline-flex;\n align-items: center;\n color: hsl(var(--ra-text));\n opacity: 0.75;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon > svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 0.15rem 0.45rem;\n min-width: 2.5rem;\n}\n.ra-shell .ra-stat-value {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n line-height: 1;\n}\n.ra-shell .ra-stat-label {\n font-size: 0.6rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-stat-divider {\n width: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-header-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.ra-shell .ra-tabs {\n display: flex;\n gap: 0.25rem;\n padding: 0.25rem;\n background: hsl(var(--sl-control-bg));\n border-radius: var(--sl-control-radius);\n border: 1px solid hsl(var(--sl-control-border));\n}\n.ra-shell .ra-tab {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.4rem 0.7rem;\n border-radius: calc(var(--sl-control-radius) - 2px);\n font-size: 0.78rem;\n font-weight: var(--sl-control-weight);\n color: hsl(var(--sl-control-fg));\n background: transparent;\n border: 0;\n cursor: pointer;\n transition:\n background .15s ease,\n color .15s ease,\n transform .15s ease;\n white-space: nowrap;\n}\n.ra-shell .ra-tab:hover {\n background: hsl(var(--sl-control-hover-bg) / 0.10);\n color: hsl(var(--sl-control-hover-fg));\n}\n.ra-shell .ra-tab:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px hsl(var(--sl-control-focus-ring) / 0.45);\n}\n.ra-shell .ra-tab[aria-selected=true] {\n background: hsl(var(--sl-control-active-bg));\n color: hsl(var(--sl-control-active-fg));\n border-color: hsl(var(--sl-control-active-bd));\n font-weight: var(--sl-control-active-weight);\n box-shadow: 0 1px 2px hsl(var(--sl-control-active-bg) / 0.25);\n}\n.ra-shell .ra-tab[aria-selected=true]:hover {\n background: hsl(var(--sl-control-active-bg) / 0.92);\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[aria-selected=true] .ra-tab-icon {\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[disabled] {\n opacity: .5;\n cursor: not-allowed;\n}\n.ra-shell .ra-tab-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n padding: 0 0.35rem;\n height: 1.1rem;\n border-radius: 999px;\n background: hsl(var(--sl-control-active-fg) / 0.20);\n color: hsl(var(--sl-control-active-fg));\n font-size: 0.625rem;\n font-weight: 600;\n line-height: 1;\n}\n.ra-shell .ra-tab[aria-selected=false] .ra-tab-count {\n background: hsl(var(--sl-control-fg) / 0.15);\n color: hsl(var(--sl-control-fg));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.4rem;\n}\n.ra-shell[data-density=compact] .ra-header {\n padding: 0.75rem 1rem;\n}\n.ra-shell[data-density=compact] .ra-header-icon {\n width: 2.25rem;\n height: 2.25rem;\n}\n.ra-shell .ra-row {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n text-align: left;\n padding: 0.45rem 0.75rem;\n border-left: 3px solid transparent;\n background: transparent;\n border-bottom: 1px solid transparent;\n transition: background .12s ease, border-color .12s ease;\n cursor: pointer;\n color: hsl(var(--ra-text));\n font-family: inherit;\n}\n.ra-shell .ra-row + .ra-row {\n border-top: 1px solid hsl(var(--ra-border) / 0.6);\n}\n.ra-shell .ra-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n border-left-color: var(--ra-row-active-bd);\n}\n.ra-shell .ra-row-compact {\n padding-block: 0.3rem;\n}\n.ra-shell .ra-row-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-icon {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-row-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.8125rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-sub {\n font-size: 0.6875rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.05rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-rule-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.2rem;\n margin-top: 0.2rem;\n}\n.ra-shell .ra-rule-chip {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n padding: 0.05rem 0.4rem;\n border-radius: 999px;\n font-size: 0.625rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.20);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-rule-chip-more {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell[data-density=compact] .ra-row-rule-chips {\n margin-top: 0.15rem;\n gap: 0.15rem;\n}\n.ra-shell[data-density=compact] .ra-rule-chip {\n font-size: 0.6rem;\n padding: 0.02rem 0.35rem;\n}\n.ra-shell .ra-rule-filters {\n display: flex;\n flex-direction: column;\n gap: 0.3rem;\n}\n.ra-shell .ra-rule-filters-row {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n}\n.ra-shell .ra-rule-filter-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.65rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n transition:\n background .12s ease,\n color .12s ease,\n border-color .12s ease;\n max-width: 100%;\n}\n.ra-shell .ra-rule-filter-chip:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n border-color: hsl(var(--ra-accent) / 0.25);\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip[data-tone=complexity][data-active=true] {\n background: hsl(var(--ra-info) / 0.15);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 9rem;\n}\n.ra-shell .ra-rule-filter-chip-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.1rem;\n height: 1rem;\n padding: 0 0.3rem;\n border-radius: 999px;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n font-size: 0.6rem;\n font-weight: 600;\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] .ra-rule-filter-chip-count {\n background: hsl(var(--ra-accent) / 0.18);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-rule-filter-clear {\n align-self: flex-start;\n background: transparent;\n border: 0;\n padding: 0;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n cursor: pointer;\n text-decoration: underline;\n text-decoration-style: dotted;\n}\n.ra-shell .ra-rule-filter-clear:hover {\n color: hsl(var(--ra-text));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.3rem;\n gap: 0.45rem;\n}\n.ra-shell[data-density=compact] .ra-row-title {\n font-size: 0.78125rem;\n}\n.ra-shell .ra-row-actions {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n margin-left: auto;\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-row:hover .ra-row-actions,\n.ra-shell .ra-row:focus-within .ra-row-actions {\n opacity: 1;\n}\n.ra-shell .ra-row-action {\n width: 1.6rem;\n height: 1.6rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 999px;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .15s ease, color .15s ease;\n}\n.ra-shell .ra-row-action:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-action[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.12);\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.6875rem;\n font-weight: 500;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n white-space: nowrap;\n max-width: 14rem;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-chip[data-tone=success] {\n background: hsl(var(--ra-success) / 0.12);\n color: hsl(var(--ra-success));\n border-color: hsl(var(--ra-success) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=warning] {\n background: hsl(var(--ra-warning) / 0.14);\n color: hsl(var(--ra-warning));\n border-color: hsl(var(--ra-warning) / 0.35);\n}\n.ra-shell .ra-chip[data-tone=info] {\n background: hsl(var(--ra-info) / 0.10);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=danger] {\n background: hsl(var(--ra-danger) / 0.10);\n color: hsl(var(--ra-danger));\n border-color: hsl(var(--ra-danger) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=muted] {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-style: dashed;\n}\n.ra-shell .ra-group {\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-group:last-child {\n border-bottom: 0;\n}\n.ra-shell .ra-group-summary {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.6);\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-group-summary:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-group-summary .ra-group-chevron {\n transition: transform .15s ease;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-chevron {\n transform: rotate(-90deg);\n}\n.ra-shell .ra-group-name {\n flex: 1;\n text-align: left;\n}\n.ra-shell .ra-group-count {\n font-size: 0.65rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.4rem;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-body {\n display: none;\n}\n.ra-shell .ra-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 2.5rem 1.5rem;\n gap: 0.75rem;\n}\n.ra-shell .ra-empty-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.08);\n color: hsl(var(--ra-accent));\n margin-bottom: 0.25rem;\n}\n.ra-shell .ra-empty-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n color: hsl(var(--ra-text));\n margin: 0;\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-empty-body {\n font-size: 0.8125rem;\n color: hsl(var(--ra-muted-text));\n max-width: 22rem;\n line-height: 1.45;\n}\n.ra-shell .ra-empty-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n flex-wrap: wrap;\n justify-content: center;\n}\n.ra-shell .ra-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.45rem 0.85rem;\n border-radius: calc(var(--ra-radius) * 0.7);\n font-size: 0.8125rem;\n font-weight: 500;\n border: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n cursor: pointer;\n transition:\n background .15s ease,\n border-color .15s ease,\n box-shadow .15s ease,\n transform .1s ease;\n}\n.ra-shell .ra-btn:hover {\n background: hsl(var(--ra-muted));\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-btn:active {\n transform: translateY(1px);\n}\n.ra-shell .ra-btn[data-variant=primary] {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-surface));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-btn[data-variant=primary]:hover {\n background: hsl(var(--ra-accent) / 0.92);\n}\n.ra-shell .ra-btn[data-variant=ghost] {\n background: transparent;\n border-color: transparent;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-btn[data-variant=ghost]:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-btn[data-variant=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-btn[data-variant=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n border-color: hsl(var(--ra-danger) / 0.40);\n}\n.ra-shell .ra-intro {\n position: relative;\n display: flex;\n gap: 0.85rem;\n padding: 0.9rem 1rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-info) / 0.30);\n background: hsl(var(--ra-info) / 0.08);\n margin-bottom: 1rem;\n}\n.ra-shell .ra-intro[data-tone=success] {\n border-color: hsl(var(--ra-success) / 0.30);\n background: hsl(var(--ra-success) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=warning] {\n border-color: hsl(var(--ra-warning) / 0.35);\n background: hsl(var(--ra-warning) / 0.10);\n}\n.ra-shell .ra-intro-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-info) / 0.18);\n color: hsl(var(--ra-info));\n}\n.ra-shell .ra-intro[data-tone=success] .ra-intro-icon {\n background: hsl(var(--ra-success) / 0.18);\n color: hsl(var(--ra-success));\n}\n.ra-shell .ra-intro[data-tone=warning] .ra-intro-icon {\n background: hsl(var(--ra-warning) / 0.20);\n color: hsl(var(--ra-warning));\n}\n.ra-shell .ra-intro-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-intro-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-title-weight);\n font-size: 0.875rem;\n color: hsl(var(--ra-text));\n margin: 0 0 0.2rem 0;\n}\n.ra-shell .ra-intro-text {\n font-size: 0.8125rem;\n color: hsl(var(--ra-text) / 0.85);\n line-height: 1.45;\n}\n.ra-shell .ra-intro-dismiss {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n width: 1.6rem;\n height: 1.6rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 0;\n color: hsl(var(--ra-muted-text));\n cursor: pointer;\n}\n.ra-shell .ra-intro-dismiss:hover {\n background: hsl(var(--ra-text) / 0.06);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-bulk-menu {\n min-width: 12rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow-hover);\n padding: 0.3rem;\n z-index: 60;\n}\n.ra-shell .ra-bulk-item {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n padding: 0.45rem 0.6rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-bulk-item:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-bulk-item[data-tone=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-bulk-item[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n}\n.ra-shell .ra-bulk-divider {\n height: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-preview-rail {\n background: hsl(var(--ra-surface));\n border-left: 1px solid hsl(var(--ra-border));\n box-shadow: -4px 0 16px hsl(var(--ra-accent) / 0.04);\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n.ra-shell .ra-preview-rail-header {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background:\n linear-gradient(\n 180deg,\n hsl(var(--ra-surface)) 0%,\n hsl(var(--ra-surface) / 0.92) 100%);\n border-bottom: 1px solid hsl(var(--ra-border));\n backdrop-filter: blur(6px);\n}\n.ra-shell .ra-preview-rail-title {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-preview-rail-body {\n flex: 1;\n overflow-y: auto;\n padding: 1rem;\n}\n.ra-confirm-root {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem;\n}\n.ra-confirm-root .ra-confirm-backdrop {\n position: absolute;\n inset: 0;\n background: hsl(0 0% 0% / 0.45);\n backdrop-filter: blur(2px);\n animation: ra-confirm-fade .12s ease-out;\n}\n.ra-confirm-root .ra-confirm-card {\n position: relative;\n width: min(440px, 100%);\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: 0 1px 2px hsl(0 0% 0% / 0.08), 0 24px 48px -12px hsl(0 0% 0% / 0.32);\n padding: 1.25rem;\n animation: ra-confirm-pop .14s ease-out;\n}\n.ra-confirm-root .ra-confirm-header {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n margin-bottom: 0.5rem;\n}\n.ra-confirm-root .ra-confirm-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 999px;\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.12);\n color: hsl(var(--ra-warning, 38 92% 50%));\n}\n.ra-confirm-root .ra-confirm-title {\n font-family: var(--ra-font-display);\n font-weight: 600;\n font-size: 1rem;\n margin: 0;\n}\n.ra-confirm-root .ra-confirm-body {\n font-size: 0.875rem;\n color: hsl(var(--ra-muted-text));\n margin: 0 0 1.1rem;\n line-height: 1.45;\n}\n.ra-confirm-root .ra-confirm-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.ra-confirm-root .ra-confirm-btn {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.45rem 0.85rem;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease;\n}\n.ra-confirm-root .ra-confirm-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-confirm-root .ra-confirm-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-confirm-root .ra-confirm-btn-ghost:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-confirm-root .ra-confirm-btn-danger {\n background: transparent;\n color: hsl(var(--ra-danger, 0 72% 51%));\n border-color: hsl(var(--ra-danger, 0 72% 51%) / 0.45);\n}\n.ra-confirm-root .ra-confirm-btn-danger:hover {\n background: hsl(var(--ra-danger, 0 72% 51%) / 0.08);\n border-color: hsl(var(--ra-danger, 0 72% 51%));\n}\n.ra-confirm-root .ra-confirm-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-confirm-root .ra-confirm-btn-primary:hover {\n filter: brightness(0.95);\n}\n@keyframes ra-confirm-fade {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes ra-confirm-pop {\n from {\n opacity: 0;\n transform: translateY(4px) scale(.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n.ra-shell .ra-unsaved-banner {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 0.75rem;\n border: 1px solid hsl(var(--ra-warning, 38 92% 50%) / 0.35);\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.08);\n border-radius: var(--ra-radius);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n animation: ra-unsaved-slide .14s ease-out;\n}\n.ra-shell .ra-unsaved-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-warning, 38 92% 50%));\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-text {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ra-shell .ra-unsaved-context {\n color: hsl(var(--ra-muted-text));\n font-weight: 400;\n}\n.ra-shell .ra-unsaved-error {\n color: hsl(var(--ra-danger, 0 72% 51%));\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n font-weight: 500;\n}\n.ra-shell .ra-unsaved-actions {\n display: inline-flex;\n gap: 0.4rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.3rem 0.6rem;\n font-size: 0.75rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease,\n opacity .12s ease;\n}\n.ra-shell .ra-unsaved-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.ra-shell .ra-unsaved-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-shell .ra-unsaved-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell .ra-unsaved-btn-ghost:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-unsaved-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-unsaved-btn-primary:hover:not(:disabled) {\n filter: brightness(0.95);\n}\n@keyframes ra-unsaved-slide {\n from {\n opacity: 0;\n transform: translateY(-3px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ra-shell .ra-clipboard-toast {\n position: fixed;\n bottom: 1.25rem;\n left: 50%;\n transform: translateX(-50%);\n z-index: 90;\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n max-width: min(28rem, calc(100vw - 2rem));\n padding: 0.55rem 0.85rem;\n border-radius: 999px;\n background: hsl(var(--ra-text));\n color: hsl(var(--ra-surface));\n font-size: 0.75rem;\n line-height: 1;\n box-shadow: 0 8px 24px -10px hsl(0 0% 0% / 0.45);\n animation: ra-clipboard-pop 0.18s ease-out both;\n pointer-events: none;\n}\n@keyframes ra-clipboard-pop {\n from {\n opacity: 0;\n transform: translate(-50%, 6px);\n }\n to {\n opacity: 1;\n transform: translate(-50%, 0);\n }\n}\n.ra-shell .ra-row-menu-wrap {\n display: inline-flex;\n align-items: center;\n margin-left: 0.25rem;\n}\n.ra-shell .ra-row-menu-trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: 0.35rem;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n opacity: 0;\n transition:\n opacity .15s ease,\n background .15s ease,\n color .15s ease;\n border: 1px solid transparent;\n}\n.ra-shell .ra-row:hover .ra-row-menu-trigger,\n.ra-shell .ra-card-hover:hover .ra-row-menu-trigger,\n.ra-shell .ra-row-menu-trigger:focus-visible,\n.ra-shell .ra-row-menu-trigger[aria-expanded=true] {\n opacity: 1;\n}\n.ra-shell .ra-row-menu-trigger:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-menu {\n position: absolute;\n right: 0;\n top: calc(100% + 4px);\n z-index: 50;\n min-width: 11rem;\n padding: 0.25rem;\n border-radius: 0.5rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n box-shadow: 0 12px 28px -10px hsl(0 0% 0% / 0.25);\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n}\n.ra-shell .ra-row-menu-item {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 0.55rem;\n border-radius: 0.35rem;\n font-size: 0.75rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n text-align: left;\n width: 100%;\n cursor: pointer;\n}\n.ra-shell .ra-row-menu-item:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-row-menu-item:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ra-shell .ra-item-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-item-list-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 1rem 1.25rem 1.5rem;\n}\n.ra-shell .ra-item-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n padding: 0.75rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-toolbar-title {\n display: flex;\n align-items: baseline;\n gap: 0.5rem;\n min-width: 0;\n}\n.ra-shell .ra-item-toolbar-count {\n font-size: 0.7rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.45rem;\n}\n.ra-shell .ra-item-toolbar-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-item-table-wrap {\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n background: hsl(var(--ra-surface));\n overflow: hidden;\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-item-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-table thead th {\n text-align: left;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n padding: 0.65rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.55);\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-item-table tbody td {\n padding: 0.65rem 0.85rem;\n border-bottom: 1px solid hsl(var(--ra-border) / 0.7);\n vertical-align: middle;\n}\n.ra-shell .ra-item-table tbody tr:last-child td {\n border-bottom: 0;\n}\n.ra-shell .ra-item-row {\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-item-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-item-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n}\n.ra-shell .ra-item-row-title {\n font-weight: var(--ra-title-weight);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-row-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-item-row-meta {\n font-size: 0.78rem;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-item-row-actions {\n text-align: right;\n white-space: nowrap;\n}\n.ra-shell .ra-item-row-actions .ra-row-action + .ra-row-action {\n margin-left: 0.15rem;\n}\n.ra-shell .ra-item-cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.85rem;\n}\n.ra-shell .ra-item-gallery {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 1rem;\n}\n.ra-shell .ra-item-card {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n text-align: left;\n padding: 0;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n overflow: hidden;\n cursor: pointer;\n transition:\n box-shadow .18s ease,\n transform .12s ease,\n border-color .15s ease;\n box-shadow: var(--ra-card-shadow);\n font-family: inherit;\n color: inherit;\n}\n.ra-shell .ra-item-card:hover {\n box-shadow: var(--ra-card-shadow-hover);\n border-color: hsl(var(--ra-accent) / 0.30);\n}\n.ra-shell .ra-item-card[data-selected=true] {\n border-color: hsl(var(--ra-accent) / 0.55);\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-item-card-thumb {\n width: 100%;\n aspect-ratio: 1 / 1;\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.12),\n hsl(var(--ra-accent) / 0.04));\n display: flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-accent));\n overflow: hidden;\n}\n.ra-shell .ra-item-card-thumb--gallery {\n aspect-ratio: 16 / 9;\n}\n.ra-shell .ra-item-card-thumb img {\n width: 100%;\n height: 100%;\n -o-object-fit: cover;\n object-fit: cover;\n}\n.ra-shell .ra-item-card-initials {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1.5rem;\n letter-spacing: 0.02em;\n}\n.ra-shell .ra-item-card-body {\n padding: 0.65rem 0.8rem 0.85rem;\n min-width: 0;\n}\n.ra-shell .ra-item-card-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.85rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-delete {\n position: absolute;\n top: 0.4rem;\n right: 0.4rem;\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(4px);\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-item-card:hover .ra-item-card-delete,\n.ra-shell .ra-item-card:focus-within .ra-item-card-delete {\n opacity: 1;\n}\n.ra-shell .ra-item-nav {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-nav-position {\n font-size: 0.72rem;\n color: hsl(var(--ra-muted-text));\n font-variant-numeric: tabular-nums;\n}\n.ra-shell .ra-item-nav-arrows {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n}\n.ra-shell .ra-item-nav-arrows .ra-row-action[disabled] {\n opacity: 0.35;\n cursor: not-allowed;\n}\n.ra-shell .ra-sibling-rail {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-sibling-back {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.6rem 0.85rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted) / 0.5);\n border: 0;\n border-bottom: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-sibling-back:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-sibling-heading {\n padding: 0.6rem 0.85rem 0.4rem;\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-sibling-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n.ra-shell .ra-sibling-list {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.ra-shell .ra-status-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n border-radius: 9999px;\n}\n.ra-shell .ra-status-icon > svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n.ra-shell .ra-status-icon--own {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-status-icon--shared {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-status-icon--missing {\n color: hsl(var(--ra-status-missing) / 0.7);\n}\n.ra-shell .ra-row-status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-row-scope {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: calc(var(--ra-radius) * 0.5);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n margin-left: auto;\n opacity: 0.55;\n transition:\n opacity .12s ease,\n color .12s ease,\n background .12s ease;\n}\n.ra-shell .ra-row:hover .ra-row-scope {\n opacity: 0.85;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-scope {\n opacity: 1;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row[data-tone=own] .ra-row-sub {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-row[data-tone=shared] .ra-row-sub {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-row[data-selected=true] {\n background:\n linear-gradient(\n 90deg,\n hsl(var(--ra-accent) / 0.10) 0%,\n hsl(var(--ra-accent) / 0.04) 100%);\n border-left-width: 3px;\n border-left-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-dirty-pip {\n display: inline-block;\n width: 0.45rem;\n height: 0.45rem;\n border-radius: 9999px;\n background: hsl(var(--ra-warning));\n box-shadow: 0 0 0 2px hsl(var(--ra-warning) / 0.18);\n flex-shrink: 0;\n}\n.ra-shell .ra-group-summary {\n background: transparent;\n}\n.ra-shell {\n position: relative;\n}\n.ra-shell .ra-help-float {\n position: absolute;\n top: 0.65rem;\n right: 0.85rem;\n z-index: 5;\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n padding: 0.3rem 0.6rem;\n font-size: 0.7rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(6px);\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n border-color .12s ease;\n}\n.ra-shell .ra-help-float:hover {\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.4);\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-help-float svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-preview-reopen {\n position: absolute;\n top: 50%;\n right: 0;\n transform: translateY(-50%);\n z-index: 4;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.4rem;\n padding: 0.65rem 0.45rem;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n border-right: 0;\n border-radius: calc(var(--ra-radius) * 0.85) 0 0 calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow);\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n padding-right .15s ease;\n writing-mode: vertical-rl;\n font-size: 0.7rem;\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n.ra-shell .ra-preview-reopen:hover {\n color: hsl(var(--ra-accent));\n background: hsl(var(--ra-accent) / 0.04);\n padding-right: 0.6rem;\n}\n.ra-shell .ra-preview-reopen svg {\n width: 0.85rem;\n height: 0.85rem;\n writing-mode: horizontal-tb;\n}\n");
|
|
3835
|
-
var TOP_LEVEL_SCOPES = ["
|
|
3880
|
+
styleInject(".ra-shell {\n color: hsl(var(--ra-text));\n background: hsl(var(--ra-page-bg));\n font-family: var(--ra-font-ui);\n}\n.ra-shell *,\n.ra-shell *::before,\n.ra-shell *::after {\n box-sizing: border-box;\n}\n.ra-shell .ra-card {\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-card-hover {\n transition:\n box-shadow .18s ease,\n transform .18s ease,\n border-color .18s ease;\n}\n.ra-shell .ra-card-hover:hover {\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-display {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-title {\n font-weight: var(--ra-title-weight);\n}\n.ra-shell :where(button, [role=button], input, select, textarea, a):focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n border-radius: calc(var(--ra-radius) * 0.6);\n}\n.ra-shell .ra-header {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.65rem 0.9rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-accent) / 0.12);\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.08),\n hsl(var(--ra-accent) / 0.02) 60%,\n hsl(var(--ra-surface)) 100%);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-header__main {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 0.625rem;\n}\n.ra-shell .ra-header-aside {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-header-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: calc(var(--ra-radius) * 0.9);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.18);\n}\n.ra-shell .ra-header-text {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-header-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n letter-spacing: -0.01em;\n margin: 0;\n}\n.ra-shell .ra-header-subtitle {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-header-stats {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n padding: 0.15rem 0.4rem;\n border-radius: calc(var(--ra-radius) * 0.75);\n background: hsl(var(--ra-surface) / 0.7);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-header-stats--titled {\n flex-direction: column;\n align-items: stretch;\n padding: 0.4rem 0.55rem;\n gap: 0.3rem;\n}\n.ra-shell .ra-header-stats .ra-stats-items {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n}\n.ra-shell .ra-header-stats .ra-stats-heading {\n display: flex;\n align-items: center;\n gap: 0.35rem;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon {\n display: inline-flex;\n align-items: center;\n color: hsl(var(--ra-text));\n opacity: 0.75;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon > svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 0.15rem 0.45rem;\n min-width: 2.5rem;\n}\n.ra-shell .ra-stat-value {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n line-height: 1;\n}\n.ra-shell .ra-stat-label {\n font-size: 0.6rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-stat-divider {\n width: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-header-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.ra-shell .ra-tabs {\n display: flex;\n gap: 0.25rem;\n padding: 0.25rem;\n background: hsl(var(--sl-control-bg));\n border-radius: var(--sl-control-radius);\n border: 1px solid hsl(var(--sl-control-border));\n}\n.ra-shell .ra-tab {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.4rem 0.7rem;\n border-radius: calc(var(--sl-control-radius) - 2px);\n font-size: 0.78rem;\n font-weight: var(--sl-control-weight);\n color: hsl(var(--sl-control-fg));\n background: transparent;\n border: 0;\n cursor: pointer;\n transition:\n background .15s ease,\n color .15s ease,\n transform .15s ease;\n white-space: nowrap;\n}\n.ra-shell .ra-tab:hover {\n background: hsl(var(--sl-control-hover-bg) / 0.10);\n color: hsl(var(--sl-control-hover-fg));\n}\n.ra-shell .ra-tab:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px hsl(var(--sl-control-focus-ring) / 0.45);\n}\n.ra-shell .ra-tab[aria-selected=true] {\n background: hsl(var(--sl-control-active-bg));\n color: hsl(var(--sl-control-active-fg));\n border-color: hsl(var(--sl-control-active-bd));\n font-weight: var(--sl-control-active-weight);\n box-shadow: 0 1px 2px hsl(var(--sl-control-active-bg) / 0.25);\n}\n.ra-shell .ra-tab[aria-selected=true]:hover {\n background: hsl(var(--sl-control-active-bg) / 0.92);\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[aria-selected=true] .ra-tab-icon {\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[disabled] {\n opacity: .5;\n cursor: not-allowed;\n}\n.ra-shell .ra-tab-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n padding: 0 0.35rem;\n height: 1.1rem;\n border-radius: 999px;\n background: hsl(var(--sl-control-active-fg) / 0.20);\n color: hsl(var(--sl-control-active-fg));\n font-size: 0.625rem;\n font-weight: 600;\n line-height: 1;\n}\n.ra-shell .ra-tab[aria-selected=false] .ra-tab-count {\n background: hsl(var(--sl-control-fg) / 0.15);\n color: hsl(var(--sl-control-fg));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.4rem;\n}\n.ra-shell[data-density=compact] .ra-header {\n padding: 0.75rem 1rem;\n}\n.ra-shell[data-density=compact] .ra-header-icon {\n width: 2.25rem;\n height: 2.25rem;\n}\n.ra-shell .ra-row {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n text-align: left;\n padding: 0.45rem 0.75rem;\n border-left: 3px solid transparent;\n background: transparent;\n border-bottom: 1px solid transparent;\n transition: background .12s ease, border-color .12s ease;\n cursor: pointer;\n color: hsl(var(--ra-text));\n font-family: inherit;\n}\n.ra-shell .ra-row + .ra-row {\n border-top: 1px solid hsl(var(--ra-border) / 0.6);\n}\n.ra-shell .ra-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n border-left-color: var(--ra-row-active-bd);\n}\n.ra-shell .ra-row-compact {\n padding-block: 0.3rem;\n}\n.ra-shell .ra-row-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-icon {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-row-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.8125rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-sub {\n font-size: 0.6875rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.05rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-rule-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.2rem;\n margin-top: 0.2rem;\n}\n.ra-shell .ra-rule-chip {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n padding: 0.05rem 0.4rem;\n border-radius: 999px;\n font-size: 0.625rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.20);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-rule-chip-more {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell[data-density=compact] .ra-row-rule-chips {\n margin-top: 0.15rem;\n gap: 0.15rem;\n}\n.ra-shell[data-density=compact] .ra-rule-chip {\n font-size: 0.6rem;\n padding: 0.02rem 0.35rem;\n}\n.ra-shell .ra-rule-filters {\n display: flex;\n flex-direction: column;\n gap: 0.3rem;\n}\n.ra-shell .ra-rule-filters-row {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n}\n.ra-shell .ra-rule-filter-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.65rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n transition:\n background .12s ease,\n color .12s ease,\n border-color .12s ease;\n max-width: 100%;\n}\n.ra-shell .ra-rule-filter-chip:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n border-color: hsl(var(--ra-accent) / 0.25);\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip[data-tone=complexity][data-active=true] {\n background: hsl(var(--ra-info) / 0.15);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 9rem;\n}\n.ra-shell .ra-rule-filter-chip-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.1rem;\n height: 1rem;\n padding: 0 0.3rem;\n border-radius: 999px;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n font-size: 0.6rem;\n font-weight: 600;\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] .ra-rule-filter-chip-count {\n background: hsl(var(--ra-accent) / 0.18);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-rule-filter-clear {\n align-self: flex-start;\n background: transparent;\n border: 0;\n padding: 0;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n cursor: pointer;\n text-decoration: underline;\n text-decoration-style: dotted;\n}\n.ra-shell .ra-rule-filter-clear:hover {\n color: hsl(var(--ra-text));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.3rem;\n gap: 0.45rem;\n}\n.ra-shell[data-density=compact] .ra-row-title {\n font-size: 0.78125rem;\n}\n.ra-shell .ra-row-actions {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n margin-left: auto;\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-row:hover .ra-row-actions,\n.ra-shell .ra-row:focus-within .ra-row-actions {\n opacity: 1;\n}\n.ra-shell .ra-row-action {\n width: 1.6rem;\n height: 1.6rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 999px;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .15s ease, color .15s ease;\n}\n.ra-shell .ra-row-action:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-action[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.12);\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.6875rem;\n font-weight: 500;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n white-space: nowrap;\n max-width: 14rem;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-chip[data-tone=success] {\n background: hsl(var(--ra-success) / 0.12);\n color: hsl(var(--ra-success));\n border-color: hsl(var(--ra-success) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=warning] {\n background: hsl(var(--ra-warning) / 0.14);\n color: hsl(var(--ra-warning));\n border-color: hsl(var(--ra-warning) / 0.35);\n}\n.ra-shell .ra-chip[data-tone=info] {\n background: hsl(var(--ra-info) / 0.10);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=danger] {\n background: hsl(var(--ra-danger) / 0.10);\n color: hsl(var(--ra-danger));\n border-color: hsl(var(--ra-danger) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=muted] {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-style: dashed;\n}\n.ra-shell .ra-group {\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-group:last-child {\n border-bottom: 0;\n}\n.ra-shell .ra-group-summary {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.6);\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-group-summary:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-group-summary .ra-group-chevron {\n transition: transform .15s ease;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-chevron {\n transform: rotate(-90deg);\n}\n.ra-shell .ra-group-name {\n flex: 1;\n text-align: left;\n}\n.ra-shell .ra-group-count {\n font-size: 0.65rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.4rem;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-body {\n display: none;\n}\n.ra-shell .ra-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 2.5rem 1.5rem;\n gap: 0.75rem;\n}\n.ra-shell .ra-empty-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.08);\n color: hsl(var(--ra-accent));\n margin-bottom: 0.25rem;\n}\n.ra-shell .ra-empty-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n color: hsl(var(--ra-text));\n margin: 0;\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-empty-body {\n font-size: 0.8125rem;\n color: hsl(var(--ra-muted-text));\n max-width: 22rem;\n line-height: 1.45;\n}\n.ra-shell .ra-empty-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n flex-wrap: wrap;\n justify-content: center;\n}\n.ra-shell .ra-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.45rem 0.85rem;\n border-radius: calc(var(--ra-radius) * 0.7);\n font-size: 0.8125rem;\n font-weight: 500;\n border: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n cursor: pointer;\n transition:\n background .15s ease,\n border-color .15s ease,\n box-shadow .15s ease,\n transform .1s ease;\n}\n.ra-shell .ra-btn:hover {\n background: hsl(var(--ra-muted));\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-btn:active {\n transform: translateY(1px);\n}\n.ra-shell .ra-btn[data-variant=primary] {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-surface));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-btn[data-variant=primary]:hover {\n background: hsl(var(--ra-accent) / 0.92);\n}\n.ra-shell .ra-btn[data-variant=ghost] {\n background: transparent;\n border-color: transparent;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-btn[data-variant=ghost]:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-btn[data-variant=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-btn[data-variant=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n border-color: hsl(var(--ra-danger) / 0.40);\n}\n.ra-shell .ra-intro {\n position: relative;\n display: flex;\n gap: 0.85rem;\n padding: 0.9rem 1rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-info) / 0.30);\n background: hsl(var(--ra-info) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=success] {\n border-color: hsl(var(--ra-success) / 0.30);\n background: hsl(var(--ra-success) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=warning] {\n border-color: hsl(var(--ra-warning) / 0.35);\n background: hsl(var(--ra-warning) / 0.10);\n}\n.ra-shell .ra-intro-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-info) / 0.18);\n color: hsl(var(--ra-info));\n}\n.ra-shell .ra-intro[data-tone=success] .ra-intro-icon {\n background: hsl(var(--ra-success) / 0.18);\n color: hsl(var(--ra-success));\n}\n.ra-shell .ra-intro[data-tone=warning] .ra-intro-icon {\n background: hsl(var(--ra-warning) / 0.20);\n color: hsl(var(--ra-warning));\n}\n.ra-shell .ra-intro-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-intro-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-title-weight);\n font-size: 0.875rem;\n color: hsl(var(--ra-text));\n margin: 0 0 0.2rem 0;\n}\n.ra-shell .ra-intro-text {\n font-size: 0.8125rem;\n color: hsl(var(--ra-text) / 0.85);\n line-height: 1.45;\n}\n.ra-shell .ra-intro-dismiss {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n width: 1.6rem;\n height: 1.6rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 0;\n color: hsl(var(--ra-muted-text));\n cursor: pointer;\n}\n.ra-shell .ra-intro-dismiss:hover {\n background: hsl(var(--ra-text) / 0.06);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-bulk-menu {\n min-width: 12rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow-hover);\n padding: 0.3rem;\n z-index: 60;\n}\n.ra-shell .ra-bulk-item {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n padding: 0.45rem 0.6rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-bulk-item:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-bulk-item[data-tone=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-bulk-item[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n}\n.ra-shell .ra-bulk-divider {\n height: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-preview-rail {\n background: hsl(var(--ra-surface));\n border-left: 1px solid hsl(var(--ra-border));\n box-shadow: -4px 0 16px hsl(var(--ra-accent) / 0.04);\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n.ra-shell .ra-preview-rail-header {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background:\n linear-gradient(\n 180deg,\n hsl(var(--ra-surface)) 0%,\n hsl(var(--ra-surface) / 0.92) 100%);\n border-bottom: 1px solid hsl(var(--ra-border));\n backdrop-filter: blur(6px);\n}\n.ra-shell .ra-preview-rail-title {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-preview-rail-body {\n flex: 1;\n overflow-y: auto;\n padding: 1rem;\n}\n.ra-confirm-root {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem;\n}\n.ra-confirm-root .ra-confirm-backdrop {\n position: absolute;\n inset: 0;\n background: hsl(0 0% 0% / 0.45);\n backdrop-filter: blur(2px);\n animation: ra-confirm-fade .12s ease-out;\n}\n.ra-confirm-root .ra-confirm-card {\n position: relative;\n width: min(440px, 100%);\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: 0 1px 2px hsl(0 0% 0% / 0.08), 0 24px 48px -12px hsl(0 0% 0% / 0.32);\n padding: 1.25rem;\n animation: ra-confirm-pop .14s ease-out;\n}\n.ra-confirm-root .ra-confirm-header {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n margin-bottom: 0.5rem;\n}\n.ra-confirm-root .ra-confirm-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 999px;\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.12);\n color: hsl(var(--ra-warning, 38 92% 50%));\n}\n.ra-confirm-root .ra-confirm-title {\n font-family: var(--ra-font-display);\n font-weight: 600;\n font-size: 1rem;\n margin: 0;\n}\n.ra-confirm-root .ra-confirm-body {\n font-size: 0.875rem;\n color: hsl(var(--ra-muted-text));\n margin: 0 0 1.1rem;\n line-height: 1.45;\n}\n.ra-confirm-root .ra-confirm-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.ra-confirm-root .ra-confirm-btn {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.45rem 0.85rem;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease;\n}\n.ra-confirm-root .ra-confirm-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-confirm-root .ra-confirm-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-confirm-root .ra-confirm-btn-ghost:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-confirm-root .ra-confirm-btn-danger {\n background: transparent;\n color: hsl(var(--ra-danger, 0 72% 51%));\n border-color: hsl(var(--ra-danger, 0 72% 51%) / 0.45);\n}\n.ra-confirm-root .ra-confirm-btn-danger:hover {\n background: hsl(var(--ra-danger, 0 72% 51%) / 0.08);\n border-color: hsl(var(--ra-danger, 0 72% 51%));\n}\n.ra-confirm-root .ra-confirm-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-confirm-root .ra-confirm-btn-primary:hover {\n filter: brightness(0.95);\n}\n@keyframes ra-confirm-fade {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes ra-confirm-pop {\n from {\n opacity: 0;\n transform: translateY(4px) scale(.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n.ra-shell .ra-unsaved-banner {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 0.75rem;\n border: 1px solid hsl(var(--ra-warning, 38 92% 50%) / 0.35);\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.08);\n border-radius: var(--ra-radius);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n animation: ra-unsaved-slide .14s ease-out;\n}\n.ra-shell .ra-unsaved-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-warning, 38 92% 50%));\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-text {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ra-shell .ra-unsaved-context {\n color: hsl(var(--ra-muted-text));\n font-weight: 400;\n}\n.ra-shell .ra-unsaved-error {\n color: hsl(var(--ra-danger, 0 72% 51%));\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n font-weight: 500;\n}\n.ra-shell .ra-unsaved-actions {\n display: inline-flex;\n gap: 0.4rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.3rem 0.6rem;\n font-size: 0.75rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease,\n opacity .12s ease;\n}\n.ra-shell .ra-unsaved-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.ra-shell .ra-unsaved-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-shell .ra-unsaved-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell .ra-unsaved-btn-ghost:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-unsaved-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-unsaved-btn-primary:hover:not(:disabled) {\n filter: brightness(0.95);\n}\n@keyframes ra-unsaved-slide {\n from {\n opacity: 0;\n transform: translateY(-3px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ra-shell .ra-clipboard-toast {\n position: fixed;\n bottom: 1.25rem;\n left: 50%;\n transform: translateX(-50%);\n z-index: 90;\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n max-width: min(28rem, calc(100vw - 2rem));\n padding: 0.55rem 0.85rem;\n border-radius: 999px;\n background: hsl(var(--ra-text));\n color: hsl(var(--ra-surface));\n font-size: 0.75rem;\n line-height: 1;\n box-shadow: 0 8px 24px -10px hsl(0 0% 0% / 0.45);\n animation: ra-clipboard-pop 0.18s ease-out both;\n pointer-events: none;\n}\n@keyframes ra-clipboard-pop {\n from {\n opacity: 0;\n transform: translate(-50%, 6px);\n }\n to {\n opacity: 1;\n transform: translate(-50%, 0);\n }\n}\n.ra-shell .ra-row-menu-wrap {\n display: inline-flex;\n align-items: center;\n margin-left: 0.25rem;\n}\n.ra-shell .ra-row-menu-trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: 0.35rem;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n opacity: 0;\n transition:\n opacity .15s ease,\n background .15s ease,\n color .15s ease;\n border: 1px solid transparent;\n}\n.ra-shell .ra-row:hover .ra-row-menu-trigger,\n.ra-shell .ra-card-hover:hover .ra-row-menu-trigger,\n.ra-shell .ra-row-menu-trigger:focus-visible,\n.ra-shell .ra-row-menu-trigger[aria-expanded=true] {\n opacity: 1;\n}\n.ra-shell .ra-row-menu-trigger:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-menu {\n position: absolute;\n right: 0;\n top: calc(100% + 4px);\n z-index: 50;\n min-width: 11rem;\n padding: 0.25rem;\n border-radius: 0.5rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n box-shadow: 0 12px 28px -10px hsl(0 0% 0% / 0.25);\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n}\n.ra-shell .ra-row-menu-item {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 0.55rem;\n border-radius: 0.35rem;\n font-size: 0.75rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n text-align: left;\n width: 100%;\n cursor: pointer;\n}\n.ra-shell .ra-row-menu-item:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-row-menu-item:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ra-shell .ra-item-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-item-list-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 1rem 1.25rem 1.5rem;\n}\n.ra-shell .ra-item-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n padding: 0.75rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-toolbar-title {\n display: flex;\n align-items: baseline;\n gap: 0.5rem;\n min-width: 0;\n}\n.ra-shell .ra-item-toolbar-count {\n font-size: 0.7rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.45rem;\n}\n.ra-shell .ra-item-toolbar-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-item-table-wrap {\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n background: hsl(var(--ra-surface));\n overflow: hidden;\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-item-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-table thead th {\n text-align: left;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n padding: 0.65rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.55);\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-item-table tbody td {\n padding: 0.65rem 0.85rem;\n border-bottom: 1px solid hsl(var(--ra-border) / 0.7);\n vertical-align: middle;\n}\n.ra-shell .ra-item-table tbody tr:last-child td {\n border-bottom: 0;\n}\n.ra-shell .ra-item-row {\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-item-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-item-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n}\n.ra-shell .ra-item-row-title {\n font-weight: var(--ra-title-weight);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-row-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-item-row-meta {\n font-size: 0.78rem;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-item-row-actions {\n text-align: right;\n white-space: nowrap;\n}\n.ra-shell .ra-item-row-actions .ra-row-action + .ra-row-action {\n margin-left: 0.15rem;\n}\n.ra-shell .ra-item-cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.85rem;\n}\n.ra-shell .ra-item-gallery {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 1rem;\n}\n.ra-shell .ra-item-card {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n text-align: left;\n padding: 0;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n overflow: hidden;\n cursor: pointer;\n transition:\n box-shadow .18s ease,\n transform .12s ease,\n border-color .15s ease;\n box-shadow: var(--ra-card-shadow);\n font-family: inherit;\n color: inherit;\n}\n.ra-shell .ra-item-card:hover {\n box-shadow: var(--ra-card-shadow-hover);\n border-color: hsl(var(--ra-accent) / 0.30);\n}\n.ra-shell .ra-item-card[data-selected=true] {\n border-color: hsl(var(--ra-accent) / 0.55);\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-item-card-thumb {\n width: 100%;\n aspect-ratio: 1 / 1;\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.12),\n hsl(var(--ra-accent) / 0.04));\n display: flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-accent));\n overflow: hidden;\n}\n.ra-shell .ra-item-card-thumb--gallery {\n aspect-ratio: 16 / 9;\n}\n.ra-shell .ra-item-card-thumb img {\n width: 100%;\n height: 100%;\n -o-object-fit: cover;\n object-fit: cover;\n}\n.ra-shell .ra-item-card-initials {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1.5rem;\n letter-spacing: 0.02em;\n}\n.ra-shell .ra-item-card-body {\n padding: 0.65rem 0.8rem 0.85rem;\n min-width: 0;\n}\n.ra-shell .ra-item-card-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.85rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-delete {\n position: absolute;\n top: 0.4rem;\n right: 0.4rem;\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(4px);\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-item-card:hover .ra-item-card-delete,\n.ra-shell .ra-item-card:focus-within .ra-item-card-delete {\n opacity: 1;\n}\n.ra-shell .ra-item-nav {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-nav-position {\n font-size: 0.72rem;\n color: hsl(var(--ra-muted-text));\n font-variant-numeric: tabular-nums;\n}\n.ra-shell .ra-item-nav-arrows {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n}\n.ra-shell .ra-item-nav-arrows .ra-row-action[disabled] {\n opacity: 0.35;\n cursor: not-allowed;\n}\n.ra-shell .ra-sibling-rail {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-sibling-back {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.6rem 0.85rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted) / 0.5);\n border: 0;\n border-bottom: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-sibling-back:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-sibling-heading {\n padding: 0.6rem 0.85rem 0.4rem;\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-sibling-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n.ra-shell .ra-sibling-list {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.ra-shell .ra-status-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n border-radius: 9999px;\n}\n.ra-shell .ra-status-icon > svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n.ra-shell .ra-status-icon--own {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-status-icon--shared {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-status-icon--missing {\n color: hsl(var(--ra-status-missing) / 0.7);\n}\n.ra-shell .ra-row-status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-row-scope {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: calc(var(--ra-radius) * 0.5);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n margin-left: auto;\n opacity: 0.55;\n transition:\n opacity .12s ease,\n color .12s ease,\n background .12s ease;\n}\n.ra-shell .ra-row:hover .ra-row-scope {\n opacity: 0.85;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-scope {\n opacity: 1;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row[data-tone=own] .ra-row-sub {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-row[data-tone=shared] .ra-row-sub {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-row[data-selected=true] {\n background:\n linear-gradient(\n 90deg,\n hsl(var(--ra-accent) / 0.10) 0%,\n hsl(var(--ra-accent) / 0.04) 100%);\n border-left-width: 3px;\n border-left-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-dirty-pip {\n display: inline-block;\n width: 0.45rem;\n height: 0.45rem;\n border-radius: 9999px;\n background: hsl(var(--ra-warning));\n box-shadow: 0 0 0 2px hsl(var(--ra-warning) / 0.18);\n flex-shrink: 0;\n}\n.ra-shell .ra-group-summary {\n background: transparent;\n}\n.ra-shell {\n position: relative;\n}\n.ra-shell .ra-help-float {\n position: absolute;\n top: 0.65rem;\n right: 0.85rem;\n z-index: 5;\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n padding: 0.3rem 0.6rem;\n font-size: 0.7rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(6px);\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n border-color .12s ease;\n}\n.ra-shell .ra-help-float:hover {\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.4);\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-help-float svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-preview-reopen {\n position: absolute;\n top: 50%;\n right: 0;\n transform: translateY(-50%);\n z-index: 4;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.4rem;\n padding: 0.65rem 0.45rem;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n border-right: 0;\n border-radius: calc(var(--ra-radius) * 0.85) 0 0 calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow);\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n padding-right .15s ease;\n writing-mode: vertical-rl;\n font-size: 0.7rem;\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n.ra-shell .ra-preview-reopen:hover {\n color: hsl(var(--ra-accent));\n background: hsl(var(--ra-accent) / 0.04);\n padding-right: 0.6rem;\n}\n.ra-shell .ra-preview-reopen svg {\n width: 0.85rem;\n height: 0.85rem;\n writing-mode: horizontal-tb;\n}\n");
|
|
3881
|
+
var TOP_LEVEL_SCOPES = ["collection", "rule", "product"];
|
|
3836
3882
|
var WARNED_FACET_DEPRECATED = false;
|
|
3837
|
-
var
|
|
3838
|
-
const time = Date.now().toString(36);
|
|
3839
|
-
const rand = Math.random().toString(36).slice(2, 8);
|
|
3840
|
-
return `${time}${rand}`;
|
|
3841
|
-
};
|
|
3842
|
-
var newRuleId = () => {
|
|
3843
|
-
const time = Date.now().toString(36);
|
|
3844
|
-
const rand = Math.random().toString(36).slice(2, 10);
|
|
3845
|
-
return `${time}${rand}`;
|
|
3846
|
-
};
|
|
3883
|
+
var DRAFT_ID = "__draft__";
|
|
3847
3884
|
var productItemToSummary = (p) => {
|
|
3848
3885
|
const ref = buildRef({ productId: p.id });
|
|
3849
3886
|
return {
|
|
@@ -3962,15 +3999,27 @@ function RecordsAdminShell(props) {
|
|
|
3962
3999
|
deepLinkState.emit({ view: next }, "view");
|
|
3963
4000
|
}, [onTelemetry, recordType, itemView, setItemView, deepLinkState]);
|
|
3964
4001
|
const [selectedItemId, setSelectedItemId] = useState(null);
|
|
4002
|
+
const [pendingDeepLinkRecordId, setPendingDeepLinkRecordId] = useState(null);
|
|
3965
4003
|
const ctx = useMemo(
|
|
3966
4004
|
() => ({ SL, collectionId, appId, recordType }),
|
|
3967
4005
|
[SL, collectionId, appId, recordType]
|
|
3968
4006
|
);
|
|
3969
4007
|
const probe = useScopeProbe({ SL, collectionId });
|
|
3970
|
-
const topLevelScopes = useMemo(
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
4008
|
+
const topLevelScopes = useMemo(() => {
|
|
4009
|
+
const requested = requestedScopes ?? [];
|
|
4010
|
+
if (requested.length > 0) {
|
|
4011
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4012
|
+
const ordered = [];
|
|
4013
|
+
for (const s of requested) {
|
|
4014
|
+
if (!TOP_LEVEL_SCOPES.includes(s)) continue;
|
|
4015
|
+
if (seen.has(s)) continue;
|
|
4016
|
+
seen.add(s);
|
|
4017
|
+
ordered.push(s);
|
|
4018
|
+
}
|
|
4019
|
+
return ordered;
|
|
4020
|
+
}
|
|
4021
|
+
return [...TOP_LEVEL_SCOPES];
|
|
4022
|
+
}, [requestedScopes]);
|
|
3974
4023
|
useEffect(() => {
|
|
3975
4024
|
if (requestedScopes.includes("facet") && !WARNED_FACET_DEPRECATED) {
|
|
3976
4025
|
WARNED_FACET_DEPRECATED = true;
|
|
@@ -3990,8 +4039,6 @@ function RecordsAdminShell(props) {
|
|
|
3990
4039
|
const initialScope = useMemo(() => {
|
|
3991
4040
|
if (contextScope?.productId && topLevelScopes.includes("product")) return "product";
|
|
3992
4041
|
if (defaultScope && topLevelScopes.includes(defaultScope)) return defaultScope;
|
|
3993
|
-
if (topLevelScopes.includes("rule")) return "rule";
|
|
3994
|
-
if (topLevelScopes.includes("collection")) return "collection";
|
|
3995
4042
|
return topLevelScopes[0] ?? "product";
|
|
3996
4043
|
}, [contextScope?.productId, defaultScope, topLevelScopes]);
|
|
3997
4044
|
const [activeScope, setActiveScope] = useState(initialScope);
|
|
@@ -4002,7 +4049,8 @@ function RecordsAdminShell(props) {
|
|
|
4002
4049
|
const [filter, setFilter] = useState("all");
|
|
4003
4050
|
const [ruleFilters, setRuleFilters] = useState(EMPTY_RULE_FILTERS);
|
|
4004
4051
|
const [facetBrowseFilter, setFacetBrowseFilter] = useState(null);
|
|
4005
|
-
const [
|
|
4052
|
+
const [selectedRecordId, setSelectedRecordId] = useState(null);
|
|
4053
|
+
const [draftKind, setDraftKind] = useState(null);
|
|
4006
4054
|
const [selectedProductId, setSelectedProductId] = useState(
|
|
4007
4055
|
contextScope?.productId
|
|
4008
4056
|
);
|
|
@@ -4082,25 +4130,35 @@ function RecordsAdminShell(props) {
|
|
|
4082
4130
|
}, [activeScope, selectedProductId, productBrowse.items]);
|
|
4083
4131
|
useEffect(() => {
|
|
4084
4132
|
if (activeScope !== "rule" && activeScope !== "collection") return;
|
|
4085
|
-
if (
|
|
4133
|
+
if (selectedRecordId !== null) return;
|
|
4086
4134
|
if (activeScope === "collection" && cardinality === "collection") {
|
|
4087
|
-
setSelectedFacetRef("");
|
|
4088
4135
|
return;
|
|
4089
4136
|
}
|
|
4090
4137
|
const first = recordList.items[0];
|
|
4091
|
-
if (first)
|
|
4092
|
-
}, [activeScope,
|
|
4138
|
+
if (first?.id) setSelectedRecordId(first.id);
|
|
4139
|
+
}, [activeScope, selectedRecordId, recordList.items, cardinality]);
|
|
4093
4140
|
useEffect(() => {
|
|
4094
4141
|
setSearch("");
|
|
4095
4142
|
setFilter("all");
|
|
4096
4143
|
setRuleFilters(EMPTY_RULE_FILTERS);
|
|
4097
4144
|
setFacetBrowseFilter(null);
|
|
4098
|
-
|
|
4145
|
+
setSelectedRecordId(null);
|
|
4146
|
+
setDraftKind(null);
|
|
4099
4147
|
}, [activeScope]);
|
|
4100
4148
|
const editingScope = useMemo(() => {
|
|
4101
4149
|
if (activeScope === "rule" || activeScope === "collection") {
|
|
4102
|
-
if (
|
|
4103
|
-
|
|
4150
|
+
if (selectedRecordId === null) {
|
|
4151
|
+
if (activeScope === "collection" && cardinality === "collection") {
|
|
4152
|
+
return parseRef("");
|
|
4153
|
+
}
|
|
4154
|
+
return null;
|
|
4155
|
+
}
|
|
4156
|
+
if (selectedRecordId === DRAFT_ID) {
|
|
4157
|
+
return parseRef("");
|
|
4158
|
+
}
|
|
4159
|
+
const hit = recordList.items.find((it) => it.id === selectedRecordId);
|
|
4160
|
+
if (!hit) return null;
|
|
4161
|
+
return hit.scope;
|
|
4104
4162
|
}
|
|
4105
4163
|
if (!selectedProductId) return null;
|
|
4106
4164
|
if (drillTab === "variant") {
|
|
@@ -4112,19 +4170,9 @@ function RecordsAdminShell(props) {
|
|
|
4112
4170
|
return parseRef(buildRef({ productId: selectedProductId, batchId: selectedBatchId }));
|
|
4113
4171
|
}
|
|
4114
4172
|
return parseRef(buildRef({ productId: selectedProductId }));
|
|
4115
|
-
}, [activeScope,
|
|
4173
|
+
}, [activeScope, cardinality, selectedRecordId, recordList.items, selectedProductId, drillTab, selectedVariantId, selectedBatchId]);
|
|
4116
4174
|
const isCollection = cardinality === "collection";
|
|
4117
|
-
const
|
|
4118
|
-
if (!isCollection) return null;
|
|
4119
|
-
if (!selectedItemId) return null;
|
|
4120
|
-
const baseRef = editingScope?.raw ?? "";
|
|
4121
|
-
return buildItemRef(baseRef, selectedItemId);
|
|
4122
|
-
}, [isCollection, selectedItemId, editingScope]);
|
|
4123
|
-
const editingTargetScope = useMemo(() => {
|
|
4124
|
-
if (!isCollection) return editingScope;
|
|
4125
|
-
if (!editingItemRef) return null;
|
|
4126
|
-
return parseRef(editingItemRef);
|
|
4127
|
-
}, [isCollection, editingScope, editingItemRef]);
|
|
4175
|
+
const editingTargetScope = editingScope;
|
|
4128
4176
|
const skipNextItemResetRef = useRef(false);
|
|
4129
4177
|
useEffect(() => {
|
|
4130
4178
|
if (skipNextItemResetRef.current) {
|
|
@@ -4141,20 +4189,19 @@ function RecordsAdminShell(props) {
|
|
|
4141
4189
|
useEffect(() => {
|
|
4142
4190
|
if (!deepLinkState.enabled) return;
|
|
4143
4191
|
if (selectedItemId) return;
|
|
4144
|
-
deepLinkState.emit({ scope: editingScope?.raw ?? null,
|
|
4192
|
+
deepLinkState.emit({ scope: editingScope?.raw ?? null, recordId: null }, "scope");
|
|
4145
4193
|
lastAppliedDLRef.current = `${""}|${editingScope?.raw ?? ""}|${itemView}`;
|
|
4146
4194
|
}, [deepLinkState.enabled, editingScope?.raw, selectedItemId, itemView]);
|
|
4147
4195
|
useEffect(() => {
|
|
4148
4196
|
if (!deepLinkState.enabled) return;
|
|
4149
|
-
const {
|
|
4150
|
-
const sig = `${
|
|
4197
|
+
const { recordId, scope, view } = deepLinkState.urlState;
|
|
4198
|
+
const sig = `${recordId ?? ""}|${scope ?? ""}|${view ?? ""}`;
|
|
4151
4199
|
if (sig === lastAppliedDLRef.current) return;
|
|
4152
4200
|
lastAppliedDLRef.current = sig;
|
|
4153
4201
|
if (view && itemViews.includes(view) && view !== itemView) {
|
|
4154
4202
|
setItemView(view);
|
|
4155
4203
|
}
|
|
4156
|
-
const railRef =
|
|
4157
|
-
const itemId = item ? item.includes("item:") ? item.slice(item.lastIndexOf("item:") + "item:".length) : item : null;
|
|
4204
|
+
const railRef = scope ?? "";
|
|
4158
4205
|
const parsed = railRef ? parseRef(railRef) : null;
|
|
4159
4206
|
if (parsed?.productId) {
|
|
4160
4207
|
if (activeScope !== "product") setActiveScope("product");
|
|
@@ -4168,16 +4215,12 @@ function RecordsAdminShell(props) {
|
|
|
4168
4215
|
if (parsed.facetValue) {
|
|
4169
4216
|
setFacetBrowseFilter({ facetKey: parsed.facetId, facetValue: parsed.facetValue });
|
|
4170
4217
|
}
|
|
4171
|
-
if (
|
|
4218
|
+
if (selectedRecordId !== null) setSelectedRecordId(null);
|
|
4172
4219
|
} else {
|
|
4173
|
-
if (
|
|
4174
|
-
}
|
|
4175
|
-
if (itemId !== selectedItemId) {
|
|
4176
|
-
if (railRef && railRef !== editingScope?.raw) {
|
|
4177
|
-
skipNextItemResetRef.current = true;
|
|
4178
|
-
}
|
|
4179
|
-
setSelectedItemId(itemId);
|
|
4220
|
+
if (selectedRecordId !== null) setSelectedRecordId(null);
|
|
4180
4221
|
}
|
|
4222
|
+
setPendingDeepLinkRecordId(recordId ?? null);
|
|
4223
|
+
if (!recordId && selectedItemId !== null) setSelectedItemId(null);
|
|
4181
4224
|
}, [deepLinkState.enabled, deepLinkState.urlState]);
|
|
4182
4225
|
const supportedForResolution = useMemo(() => requestedScopes, [requestedScopes]);
|
|
4183
4226
|
const resolved = useResolvedRecord({
|
|
@@ -4190,7 +4233,12 @@ function RecordsAdminShell(props) {
|
|
|
4190
4233
|
batchId: editingTargetScope?.batchId,
|
|
4191
4234
|
facetId: editingTargetScope?.facetId,
|
|
4192
4235
|
facetValue: editingTargetScope?.facetValue,
|
|
4193
|
-
|
|
4236
|
+
// Id-primary path: when the user has selected a saved record by UUID
|
|
4237
|
+
// (records-driven tabs, deep-link by `?recordId=`), bypass the
|
|
4238
|
+
// inheritance chain and load that exact row. Drafts (`DRAFT_ID`) and
|
|
4239
|
+
// pinned-anchor tabs (Products) leave `recordId` undefined so the
|
|
4240
|
+
// resolver runs `match()` against the anchors above.
|
|
4241
|
+
recordId: selectedRecordId && selectedRecordId !== DRAFT_ID ? selectedRecordId : void 0,
|
|
4194
4242
|
supportedScopes: supportedForResolution,
|
|
4195
4243
|
enabled: !!editingTargetScope
|
|
4196
4244
|
});
|
|
@@ -4318,8 +4366,8 @@ function RecordsAdminShell(props) {
|
|
|
4318
4366
|
const sourceValue = onCopyOverride ? onCopyOverride({ value: editorCtx.value, scope: editingScope }) : cloneValue(editorCtx.value);
|
|
4319
4367
|
clipboard.set({
|
|
4320
4368
|
value: sourceValue,
|
|
4321
|
-
sourceScope: editingScope
|
|
4322
|
-
|
|
4369
|
+
sourceScope: editingScope,
|
|
4370
|
+
sourceRecordId: resolved.recordId,
|
|
4323
4371
|
sourceLabel: editorHeaderLabel
|
|
4324
4372
|
});
|
|
4325
4373
|
onTelemetry?.({ type: "clipboard.copy", recordType, sourceRef: editingScope.raw });
|
|
@@ -4340,10 +4388,7 @@ function RecordsAdminShell(props) {
|
|
|
4340
4388
|
]);
|
|
4341
4389
|
const pasteCurrent = useCallback(async () => {
|
|
4342
4390
|
if (!enableClipboard || !editingScope || !clipboard.entry) return;
|
|
4343
|
-
const compat = checkPasteCompatibility(
|
|
4344
|
-
{ kind: clipboard.entry.sourceScope, raw: clipboard.entry.sourceRef },
|
|
4345
|
-
editingScope
|
|
4346
|
-
);
|
|
4391
|
+
const compat = checkPasteCompatibility(clipboard.entry.sourceScope, editingScope);
|
|
4347
4392
|
if (compat.status === "denied") {
|
|
4348
4393
|
setClipboardNotice({ message: compat.reason ?? "Paste not allowed here", variant: "paste" });
|
|
4349
4394
|
return;
|
|
@@ -4370,7 +4415,7 @@ function RecordsAdminShell(props) {
|
|
|
4370
4415
|
});
|
|
4371
4416
|
if (!ok) return;
|
|
4372
4417
|
}
|
|
4373
|
-
const sourceParsed =
|
|
4418
|
+
const sourceParsed = clipboard.entry.sourceScope;
|
|
4374
4419
|
const transformed = onPasteOverride ? onPasteOverride(
|
|
4375
4420
|
{ value: clipboard.entry.value, sourceScope: sourceParsed },
|
|
4376
4421
|
{ scope: editingScope, currentValue: editorCtx.value ?? null }
|
|
@@ -4380,12 +4425,12 @@ function RecordsAdminShell(props) {
|
|
|
4380
4425
|
onTelemetry?.({
|
|
4381
4426
|
type: "clipboard.paste",
|
|
4382
4427
|
recordType,
|
|
4383
|
-
sourceRef: clipboard.entry.
|
|
4428
|
+
sourceRef: clipboard.entry.sourceScope.raw,
|
|
4384
4429
|
destinationRef: editingScope.raw,
|
|
4385
4430
|
replaced: willReplace
|
|
4386
4431
|
});
|
|
4387
4432
|
setClipboardNotice({
|
|
4388
|
-
message: i18n.pasteToast.replace("{name}", clipboard.entry.sourceLabel ?? clipboard.entry.
|
|
4433
|
+
message: i18n.pasteToast.replace("{name}", clipboard.entry.sourceLabel ?? clipboard.entry.sourceScope.raw),
|
|
4389
4434
|
variant: "paste"
|
|
4390
4435
|
});
|
|
4391
4436
|
}, [
|
|
@@ -4409,11 +4454,10 @@ function RecordsAdminShell(props) {
|
|
|
4409
4454
|
]);
|
|
4410
4455
|
const editorPasteCompat = useMemo(() => {
|
|
4411
4456
|
if (!enableClipboard || !clipboard.entry || !editingScope) return null;
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
);
|
|
4457
|
+
const sameRecord = clipboard.entry.sourceRecordId && resolved.recordId && clipboard.entry.sourceRecordId === resolved.recordId;
|
|
4458
|
+
const sameAnchor = !clipboard.entry.sourceRecordId && clipboard.entry.sourceScope.raw === editingScope.raw;
|
|
4459
|
+
if (sameRecord || sameAnchor) return { status: "denied" };
|
|
4460
|
+
return checkPasteCompatibility(clipboard.entry.sourceScope, editingScope);
|
|
4417
4461
|
}, [enableClipboard, clipboard.entry, editingScope]);
|
|
4418
4462
|
const editorClipboard = enableClipboard && editingScope ? {
|
|
4419
4463
|
onCopy: copyCurrent,
|
|
@@ -4425,31 +4469,30 @@ function RecordsAdminShell(props) {
|
|
|
4425
4469
|
pasteSourceLabel: clipboard.entry?.sourceLabel,
|
|
4426
4470
|
pasteWillReplace: resolved.source === "self" && !!clipboard.entry
|
|
4427
4471
|
} : void 0;
|
|
4428
|
-
const [
|
|
4472
|
+
const [pendingPasteTarget, setPendingPasteTarget] = useState(null);
|
|
4429
4473
|
useEffect(() => {
|
|
4430
|
-
if (!
|
|
4431
|
-
if (!editingScope
|
|
4474
|
+
if (!pendingPasteTarget) return;
|
|
4475
|
+
if (!editingScope) return;
|
|
4476
|
+
const matched = pendingPasteTarget.kind === "record" ? selectedRecordId === pendingPasteTarget.recordId : editingScope.raw === pendingPasteTarget.ref;
|
|
4477
|
+
if (!matched) return;
|
|
4432
4478
|
const t = window.setTimeout(() => {
|
|
4433
|
-
|
|
4479
|
+
setPendingPasteTarget(null);
|
|
4434
4480
|
void pasteCurrent();
|
|
4435
4481
|
}, 0);
|
|
4436
4482
|
return () => window.clearTimeout(t);
|
|
4437
|
-
}, [
|
|
4483
|
+
}, [pendingPasteTarget, editingScope, selectedRecordId, pasteCurrent]);
|
|
4438
4484
|
const rowClipboard = enableClipboard ? (record) => {
|
|
4439
4485
|
const summaryHasData = record.data != null;
|
|
4440
4486
|
const sourceParsed = record.scope;
|
|
4441
|
-
const compat = clipboard.entry ? checkPasteCompatibility(
|
|
4442
|
-
|
|
4443
|
-
sourceParsed
|
|
4444
|
-
) : null;
|
|
4445
|
-
const sameRef = clipboard.entry?.sourceRef === record.ref;
|
|
4487
|
+
const compat = clipboard.entry ? checkPasteCompatibility(clipboard.entry.sourceScope, sourceParsed) : null;
|
|
4488
|
+
const sameTarget = clipboard.entry ? clipboard.entry.sourceRecordId && record.id ? clipboard.entry.sourceRecordId === record.id : clipboard.entry.sourceScope.raw === record.ref : false;
|
|
4446
4489
|
return {
|
|
4447
4490
|
onCopy: summaryHasData ? () => {
|
|
4448
4491
|
const value = onCopyOverride ? onCopyOverride({ value: record.data, scope: sourceParsed }) : cloneValue(record.data);
|
|
4449
4492
|
clipboard.set({
|
|
4450
4493
|
value,
|
|
4451
|
-
sourceScope: sourceParsed
|
|
4452
|
-
|
|
4494
|
+
sourceScope: sourceParsed,
|
|
4495
|
+
sourceRecordId: record.id ?? void 0,
|
|
4453
4496
|
sourceLabel: record.label
|
|
4454
4497
|
});
|
|
4455
4498
|
onTelemetry?.({ type: "clipboard.copy", recordType, sourceRef: record.ref });
|
|
@@ -4460,9 +4503,11 @@ function RecordsAdminShell(props) {
|
|
|
4460
4503
|
} : void 0,
|
|
4461
4504
|
onPaste: () => {
|
|
4462
4505
|
onLeftSelectRef.current?.(record);
|
|
4463
|
-
|
|
4506
|
+
setPendingPasteTarget(
|
|
4507
|
+
record.id ? { kind: "record", recordId: record.id } : { kind: "anchor", ref: record.ref }
|
|
4508
|
+
);
|
|
4464
4509
|
},
|
|
4465
|
-
canPaste: !!clipboard.entry && !
|
|
4510
|
+
canPaste: !!clipboard.entry && !sameTarget && compat?.status !== "denied",
|
|
4466
4511
|
pasteWillReplace: record.status === "configured",
|
|
4467
4512
|
clipboardSourceLabel: clipboard.entry?.sourceLabel
|
|
4468
4513
|
};
|
|
@@ -4471,6 +4516,7 @@ function RecordsAdminShell(props) {
|
|
|
4471
4516
|
const baseScopeRef = editingScope?.raw ?? "";
|
|
4472
4517
|
const itemNounLabel = itemNoun || "item";
|
|
4473
4518
|
const buildItemUrlValue = useCallback((id) => {
|
|
4519
|
+
if (!baseScopeRef && id.startsWith("item:")) return id;
|
|
4474
4520
|
return baseScopeRef ? `${baseScopeRef}/item:${id}` : id;
|
|
4475
4521
|
}, [baseScopeRef]);
|
|
4476
4522
|
const onItemOpen = useCallback((itemId) => {
|
|
@@ -4478,31 +4524,31 @@ function RecordsAdminShell(props) {
|
|
|
4478
4524
|
void runWithGuard(() => {
|
|
4479
4525
|
setSelectedItemId(itemId);
|
|
4480
4526
|
onTelemetry?.({ type: "item.open", recordType, scopeRef: baseScopeRef, itemId });
|
|
4481
|
-
deepLinkState.emit({
|
|
4527
|
+
deepLinkState.emit({ recordId: itemId, scope: baseScopeRef || null }, "record.open");
|
|
4482
4528
|
});
|
|
4483
4529
|
}, [isCollection, runWithGuard, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
|
|
4484
4530
|
const onItemCreate = useCallback(() => {
|
|
4485
4531
|
if (!isCollection) return;
|
|
4486
4532
|
void runWithGuard(() => {
|
|
4487
|
-
const id = generateItemId ? generateItemId() :
|
|
4533
|
+
const id = generateItemId ? generateItemId() : DRAFT_ID;
|
|
4488
4534
|
setSelectedItemId(id);
|
|
4489
4535
|
onTelemetry?.({ type: "item.create", recordType, scopeRef: baseScopeRef });
|
|
4490
|
-
deepLinkState.emit({
|
|
4536
|
+
deepLinkState.emit({ recordId: null, scope: baseScopeRef || null }, "record.open");
|
|
4491
4537
|
});
|
|
4492
4538
|
}, [isCollection, runWithGuard, generateItemId, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
|
|
4493
4539
|
const onItemDelete = useCallback(async (itemId) => {
|
|
4494
4540
|
if (!isCollection) return;
|
|
4495
|
-
|
|
4541
|
+
if (itemId === DRAFT_ID) return;
|
|
4496
4542
|
if (onBeforeDelete) {
|
|
4497
|
-
const ok = await onBeforeDelete(parseRef(
|
|
4543
|
+
const ok = await onBeforeDelete(editingScope ?? parseRef(""));
|
|
4498
4544
|
if (!ok) return;
|
|
4499
4545
|
}
|
|
4500
4546
|
try {
|
|
4501
|
-
const {
|
|
4502
|
-
await
|
|
4547
|
+
const { removeRecord: removeRecord2 } = await import('../../records-JWS6LKJ2.js');
|
|
4548
|
+
await removeRecord2(ctx, itemId);
|
|
4503
4549
|
onTelemetry?.({ type: "item.delete", recordType, scopeRef: baseScopeRef, itemId });
|
|
4504
4550
|
if (selectedItemId === itemId) setSelectedItemId(null);
|
|
4505
|
-
if (selectedItemId === itemId) deepLinkState.emit({
|
|
4551
|
+
if (selectedItemId === itemId) deepLinkState.emit({ recordId: null }, "record.close");
|
|
4506
4552
|
collectionItems.refetch();
|
|
4507
4553
|
} catch (err) {
|
|
4508
4554
|
console.error("[RecordsAdminShell] item delete failed", err);
|
|
@@ -4537,14 +4583,14 @@ function RecordsAdminShell(props) {
|
|
|
4537
4583
|
const onItemBack = useCallback(() => {
|
|
4538
4584
|
void runWithGuard(() => {
|
|
4539
4585
|
setSelectedItemId(null);
|
|
4540
|
-
deepLinkState.emit({
|
|
4586
|
+
deepLinkState.emit({ recordId: null }, "record.close");
|
|
4541
4587
|
});
|
|
4542
4588
|
}, [runWithGuard, deepLinkState]);
|
|
4543
4589
|
const stepToItem = useCallback((id) => {
|
|
4544
4590
|
void runWithGuard(() => {
|
|
4545
4591
|
setSelectedItemId(id);
|
|
4546
4592
|
onTelemetry?.({ type: "item.open", recordType, scopeRef: baseScopeRef, itemId: id });
|
|
4547
|
-
deepLinkState.emit({
|
|
4593
|
+
deepLinkState.emit({ recordId: id, scope: baseScopeRef || null }, "record.step");
|
|
4548
4594
|
});
|
|
4549
4595
|
}, [runWithGuard, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
|
|
4550
4596
|
const onItemPrev = useCallback(() => {
|
|
@@ -4717,21 +4763,21 @@ function RecordsAdminShell(props) {
|
|
|
4717
4763
|
const isRecordsTab = isRuleTab || isGlobalTab;
|
|
4718
4764
|
const onCreateRule = useCallback(() => {
|
|
4719
4765
|
void runWithGuard(() => {
|
|
4720
|
-
const id = newRuleId();
|
|
4721
|
-
const ref = `rule:${id}`;
|
|
4722
4766
|
if (activeScope !== "rule") setActiveScope("rule");
|
|
4723
|
-
|
|
4767
|
+
setSelectedRecordId(DRAFT_ID);
|
|
4768
|
+
setDraftKind("rule");
|
|
4724
4769
|
});
|
|
4725
4770
|
}, [runWithGuard, activeScope]);
|
|
4726
4771
|
const hasGlobalRecord = useMemo(
|
|
4727
|
-
() => recordList.items.some((it) => !it.scope.productId && !it.scope.facetId && !it.scope.variantId && !it.scope.batchId && !it.scope.proofId
|
|
4772
|
+
() => recordList.items.some((it) => !it.scope.productId && !it.scope.facetId && !it.scope.variantId && !it.scope.batchId && !it.scope.proofId),
|
|
4728
4773
|
[recordList.items]
|
|
4729
4774
|
);
|
|
4730
4775
|
const showCreateGlobal = isGlobalTab && !isCollection && !hasGlobalRecord;
|
|
4731
4776
|
const onCreateGlobal = useCallback(() => {
|
|
4732
4777
|
void runWithGuard(() => {
|
|
4733
4778
|
if (activeScope !== "collection") setActiveScope("collection");
|
|
4734
|
-
|
|
4779
|
+
setSelectedRecordId(DRAFT_ID);
|
|
4780
|
+
setDraftKind("global");
|
|
4735
4781
|
});
|
|
4736
4782
|
}, [runWithGuard, activeScope]);
|
|
4737
4783
|
const filteredRuleItems = useMemo(
|
|
@@ -4773,26 +4819,25 @@ function RecordsAdminShell(props) {
|
|
|
4773
4819
|
}
|
|
4774
4820
|
return Array.from(byKey.values());
|
|
4775
4821
|
}, [facetBrowse.items]);
|
|
4776
|
-
const stripItemRecords = useCallback(
|
|
4777
|
-
(items) => items.filter((it) => !it.scope.itemId && !it.ref.startsWith("item:") && !it.ref.includes("/item:")),
|
|
4778
|
-
[]
|
|
4779
|
-
);
|
|
4780
4822
|
const collectionGlobalAllRow = useMemo(
|
|
4781
4823
|
() => ({
|
|
4782
4824
|
id: null,
|
|
4783
4825
|
ref: "",
|
|
4784
4826
|
scope: parseRef(""),
|
|
4785
4827
|
data: null,
|
|
4786
|
-
status: "
|
|
4828
|
+
status: "empty",
|
|
4787
4829
|
label: i18n.itemsAllLabel,
|
|
4788
4830
|
subtitle: collectionItems.items.length ? `${collectionItems.items.length} ${itemNoun}${collectionItems.items.length === 1 ? "" : "s"}` : void 0
|
|
4789
4831
|
}),
|
|
4790
4832
|
[i18n.itemsAllLabel, collectionItems.items.length, itemNoun]
|
|
4791
4833
|
);
|
|
4792
|
-
const leftItems = isProductTab ? productListItems : isRuleTab ? applyFacetBrowseFilter(
|
|
4834
|
+
const leftItems = isProductTab ? productListItems : isRuleTab ? applyFacetBrowseFilter(filteredRuleItems) : isGlobalTab && isCollection ? [collectionGlobalAllRow] : isRecordsTab ? applyFacetBrowseFilter(recordList.items) : [];
|
|
4793
4835
|
const leftLoading = isProductTab ? !productPinned && productBrowse.isLoading : isRecordsTab ? recordList.isLoading || probe.isLoading : false;
|
|
4794
4836
|
const leftError = isProductTab ? productBrowse.error : isRecordsTab ? recordList.error : null;
|
|
4795
|
-
const
|
|
4837
|
+
const leftSelectedId = isProductTab ? void 0 : selectedRecordId && selectedRecordId !== DRAFT_ID ? selectedRecordId : void 0;
|
|
4838
|
+
const leftSelectedAnchorKey = isProductTab ? selectedProductId ? buildRef({ productId: selectedProductId }) : void 0 : void 0;
|
|
4839
|
+
const dirtyId = !editorCtx.isDirty ? void 0 : selectedRecordId && selectedRecordId !== DRAFT_ID ? selectedRecordId : void 0;
|
|
4840
|
+
const dirtyAnchorKey = !editorCtx.isDirty ? void 0 : isProductTab ? editingScope?.raw : void 0;
|
|
4796
4841
|
const onLeftSelect = (item) => {
|
|
4797
4842
|
void runWithGuard(() => {
|
|
4798
4843
|
if (isProductTab) {
|
|
@@ -4801,7 +4846,8 @@ function RecordsAdminShell(props) {
|
|
|
4801
4846
|
setSelectedBatchId(void 0);
|
|
4802
4847
|
setDrillTab("product");
|
|
4803
4848
|
} else {
|
|
4804
|
-
|
|
4849
|
+
setSelectedRecordId(item.id ?? null);
|
|
4850
|
+
setDraftKind(null);
|
|
4805
4851
|
}
|
|
4806
4852
|
});
|
|
4807
4853
|
};
|
|
@@ -5056,9 +5102,11 @@ function RecordsAdminShell(props) {
|
|
|
5056
5102
|
RecordList,
|
|
5057
5103
|
{
|
|
5058
5104
|
items: leftItems,
|
|
5059
|
-
|
|
5105
|
+
selectedId: leftSelectedId,
|
|
5106
|
+
selectedAnchorKey: leftSelectedAnchorKey,
|
|
5060
5107
|
onSelect: onLeftSelect,
|
|
5061
|
-
|
|
5108
|
+
dirtyId,
|
|
5109
|
+
dirtyAnchorKey,
|
|
5062
5110
|
presentation: effectivePresentation,
|
|
5063
5111
|
renderListRow,
|
|
5064
5112
|
groupBy: effectiveGroupBy,
|
|
@@ -5151,7 +5199,7 @@ var RecordBrowser = ({
|
|
|
5151
5199
|
scopes,
|
|
5152
5200
|
activeScope,
|
|
5153
5201
|
onActiveScopeChange,
|
|
5154
|
-
|
|
5202
|
+
selectedId,
|
|
5155
5203
|
onSelectRef,
|
|
5156
5204
|
items,
|
|
5157
5205
|
counts,
|
|
@@ -5194,7 +5242,7 @@ var RecordBrowser = ({
|
|
|
5194
5242
|
!isLoading && error && /* @__PURE__ */ jsx(ErrorState, { error }),
|
|
5195
5243
|
!isLoading && !error && items.length === 0 && /* @__PURE__ */ jsx(EmptyState, { title: i18n.noResults, body: search ? void 0 : i18n.emptyBody }),
|
|
5196
5244
|
!isLoading && !error && items.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5197
|
-
/* @__PURE__ */ jsx(RecordList, { items,
|
|
5245
|
+
/* @__PURE__ */ jsx(RecordList, { items, selectedId, onSelect: onSelectRef }),
|
|
5198
5246
|
hasNextPage && /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
|
|
5199
5247
|
"button",
|
|
5200
5248
|
{
|
|
@@ -5459,16 +5507,13 @@ function useCollectedRecords(args) {
|
|
|
5459
5507
|
target.facetValue = facetValue;
|
|
5460
5508
|
const ctx = { SL, collectionId, appId, recordType };
|
|
5461
5509
|
const result = await matchRecords(ctx, parsedRefToTarget(target), { strategy: "all" }).catch(() => null);
|
|
5462
|
-
const
|
|
5463
|
-
const baseList =
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
depth: i
|
|
5470
|
-
};
|
|
5471
|
-
});
|
|
5510
|
+
const entries = result?.data ?? [];
|
|
5511
|
+
const baseList = entries.map((entry, i) => ({
|
|
5512
|
+
ref: entry.ref ?? "",
|
|
5513
|
+
scope: parseRef(entry.ref ?? ""),
|
|
5514
|
+
data: entry.data,
|
|
5515
|
+
depth: i
|
|
5516
|
+
}));
|
|
5472
5517
|
const sortKind = sort?.kind ?? "specificity";
|
|
5473
5518
|
const direction = sort?.direction ?? (sortKind === "specificity" ? "desc" : "asc");
|
|
5474
5519
|
const sign = direction === "desc" ? -1 : 1;
|
|
@@ -5551,11 +5596,11 @@ function useMergedRecord(args) {
|
|
|
5551
5596
|
target.facetValue = facetValue;
|
|
5552
5597
|
const ctx = { SL, collectionId, appId, recordType };
|
|
5553
5598
|
const result = await matchRecords(ctx, parsedRefToTarget(target), { strategy: "all" }).catch(() => null);
|
|
5554
|
-
const
|
|
5555
|
-
if (
|
|
5556
|
-
const present =
|
|
5557
|
-
ref: entry.
|
|
5558
|
-
data: entry.
|
|
5599
|
+
const entries = result?.data ?? [];
|
|
5600
|
+
if (entries.length === 0) return { data: null, provenance: {}, layers: [] };
|
|
5601
|
+
const present = entries.map((entry) => ({
|
|
5602
|
+
ref: entry.ref ?? "",
|
|
5603
|
+
data: entry.data
|
|
5559
5604
|
}));
|
|
5560
5605
|
const ordered = [...present].reverse();
|
|
5561
5606
|
let merged = null;
|
|
@@ -5578,6 +5623,6 @@ function useMergedRecord(args) {
|
|
|
5578
5623
|
};
|
|
5579
5624
|
}
|
|
5580
5625
|
|
|
5581
|
-
export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, DrawerPreview, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, ItemListView, ItemViewSwitcher, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SiblingRail, SidePreview, StatusDot, StatusFilterPills, StatusIcon, TabbedPreview, UtilityRow, VariantList,
|
|
5626
|
+
export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, DrawerPreview, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, ItemListView, ItemViewSwitcher, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SiblingRail, SidePreview, StatusDot, StatusFilterPills, StatusIcon, TabbedPreview, UtilityRow, VariantList, buildRef, checkPasteCompatibility, cloneValue, createDefaultDeepLinkAdapter, downloadBlob, exportCsv, importCsv, mergeIcons, parseRef, pickHeaderIcon, resolutionChain, resolveRecord, statusToneLabel, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeProbe, useUnsavedGuard };
|
|
5582
5627
|
//# sourceMappingURL=index.js.map
|
|
5583
5628
|
//# sourceMappingURL=index.js.map
|