@proveanything/smartlinks-utils-ui 0.3.8 → 0.3.11

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.
@@ -1,13 +1,22 @@
1
- import { styleInject } from '../../chunk-NIAIQRFC.js';
1
+ import { styleInject } from '../../chunk-3BLWNYM4.js';
2
2
  import { cn } from '../../chunk-L7FQ52F5.js';
3
+ import { listRecords, parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, upsertRecord, deleteRecord } from '../../chunk-TY2UIZ24.js';
4
+ export { bulkDelete, bulkUpsert, deleteRecord, getRecordByRef, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-TY2UIZ24.js';
3
5
  import { createContext, useMemo, useState, useEffect, useCallback, useRef, useContext, createElement } from 'react';
4
- import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, Globe, Tag, Boxes, Layers, Package, Rows3, Image, List, ChevronRight, Eraser, Box, X, AlertTriangle, Info, HelpCircle, Search, CornerDownLeft, Circle, AlertCircle, Undo2, Save } from 'lucide-react';
6
+ import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, 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 } from 'lucide-react';
5
7
  import { useQueryClient, useInfiniteQuery, useQuery } from '@tanstack/react-query';
6
8
  import { createPortal } from 'react-dom';
7
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
10
 
9
11
  var DEFAULT_ICONS = {
10
- scope: { product: Package, variant: Layers, batch: Boxes, facet: Tag, universal: Globe },
12
+ scope: {
13
+ collection: Globe,
14
+ product: Package,
15
+ variant: Layers,
16
+ batch: Boxes,
17
+ facet: Tag,
18
+ universal: Globe
19
+ },
11
20
  status: { own: CheckCircle2, inherited: ArrowDownLeft, missing: CircleDashed },
12
21
  action: {
13
22
  add: Plus,
@@ -86,18 +95,49 @@ var DEFAULT_I18N = {
86
95
  unsavedPromptSave: "Save & continue",
87
96
  unsavedBannerBody: "Unsaved changes on {name}",
88
97
  presentationList: "List",
89
- presentationGrid: "Grid",
90
- presentationGallery: "Gallery",
91
98
  presentationCompact: "Compact",
99
+ itemViewTable: "Table",
100
+ itemViewCards: "Cards",
101
+ itemViewGallery: "Gallery",
92
102
  newItem: "New item",
93
103
  noItemsTitle: "No items yet",
94
104
  noItemsBody: "Create your first item to get started.",
105
+ backToList: "Back to list",
106
+ prevItem: "Previous",
107
+ nextItem: "Next",
108
+ itemListTitle: "Items",
109
+ itemColumnLabel: "Name",
110
+ itemColumnUpdated: "Updated",
111
+ itemActions: "Actions",
112
+ backToScopes: "\u2190 All scopes",
113
+ siblingsHeading: "Items in this scope",
95
114
  railEmptyTitle: "No records yet",
96
- railEmptyBody: "Records you create will appear here."
115
+ railEmptyBody: "Records you create will appear here.",
116
+ copy: "Copy",
117
+ paste: "Paste",
118
+ pasteFrom: "Paste from {name}",
119
+ pasteReplace: "Paste (replace)",
120
+ clipboardEmpty: "Nothing to paste",
121
+ copyToast: "Copied {name}. Pick a destination to paste.",
122
+ pasteToast: "Pasted from {name}. Review and Save.",
123
+ pasteConfirmTitle: "Replace existing values?",
124
+ pasteConfirmBody: "{destination} already has saved values. Replace them with the copied values?",
125
+ pasteConfirmReplace: "Replace",
126
+ pasteConfirmCancel: "Cancel",
127
+ pasteWarnTitle: "Cross-scope paste",
128
+ pasteWarnContinue: "Continue"
97
129
  };
98
130
 
99
131
  // src/components/RecordsAdmin/types/presentation.ts
100
- var ALL_PRESENTATIONS = ["list", "grid", "gallery", "compact"];
132
+ var ALL_PRESENTATIONS = ["list", "compact"];
133
+ var ALL_ITEM_VIEWS = ["table", "cards", "gallery"];
134
+
135
+ // src/components/RecordsAdmin/types/deepLink.ts
136
+ var DEFAULT_DEEP_LINK_PARAM_NAMES = {
137
+ item: "item",
138
+ scope: "scope",
139
+ view: "view"
140
+ };
101
141
 
102
142
  // src/components/RecordsAdmin/data/refs.ts
103
143
  var KIND_KEYS = {
@@ -126,6 +166,9 @@ var parseRef = (raw) => {
126
166
  } else {
127
167
  parsed.facetId = id;
128
168
  }
169
+ } else if (k === "item") {
170
+ parsed.itemId = id;
171
+ continue;
129
172
  } else if (k in KIND_KEYS) {
130
173
  parsed[KIND_KEYS[k]] = id;
131
174
  }
@@ -143,6 +186,7 @@ var buildRef = (a) => {
143
186
  if (a.variantId) parts.push(`variant:${a.variantId}`);
144
187
  if (a.batchId) parts.push(`batch:${a.batchId}`);
145
188
  if (a.proofId) parts.push(`proof:${a.proofId}`);
189
+ if (a.itemId) parts.push(`item:${a.itemId}`);
146
190
  return parts.join("/");
147
191
  };
148
192
  var resolutionChain = (target, supportedScopes) => {
@@ -159,173 +203,23 @@ var resolutionChain = (target, supportedScopes) => {
159
203
  if (supportedScopes.includes("facet") && target.facetId) {
160
204
  chain.push(buildRef({ facetId: target.facetId, facetValue: target.facetValue }));
161
205
  }
162
- return Array.from(new Set(chain));
163
- };
164
-
165
- // src/components/RecordsAdmin/data/scopeBridge.ts
166
- var parsedRefToScope = (ref) => {
167
- const scope = {};
168
- if (ref.productId) scope.productId = ref.productId;
169
- if (ref.variantId) scope.variantId = ref.variantId;
170
- if (ref.batchId) scope.batchId = ref.batchId;
171
- if (ref.proofId) scope.proofId = ref.proofId;
172
- if (ref.facetId) {
173
- scope.facets = [{
174
- key: ref.facetId,
175
- valueKeys: ref.facetValue ? [ref.facetValue] : []
176
- }];
177
- }
178
- return scope;
179
- };
180
- var parsedRefToTarget = (ref) => {
181
- const target = {};
182
- if (ref.productId) target.productId = ref.productId;
183
- if (ref.variantId) target.variantId = ref.variantId;
184
- if (ref.batchId) target.batchId = ref.batchId;
185
- if (ref.proofId) target.proofId = ref.proofId;
186
- if (ref.facetId && ref.facetValue) {
187
- target.facets = { [ref.facetId]: [ref.facetValue] };
188
- }
189
- return target;
190
- };
191
- var scopesEqual = (a, b) => {
192
- if ((a.productId ?? null) !== (b.productId ?? null)) return false;
193
- if ((a.variantId ?? null) !== (b.variantId ?? null)) return false;
194
- if ((a.batchId ?? null) !== (b.batchId ?? null)) return false;
195
- if ((a.proofId ?? null) !== (b.proofId ?? null)) return false;
196
- const af = a.facets ?? [];
197
- const bf = b.facets ?? [];
198
- if (af.length !== bf.length) return false;
199
- const norm = (xs) => xs.map((f) => `${f.key}:${[...f.valueKeys].sort().join(",")}`).sort().join("|");
200
- return norm(af) === norm(bf);
201
- };
202
-
203
- // src/components/RecordsAdmin/data/records.ts
204
- var listRecords = async (ctx, params = {}) => {
205
- const { limit = 100, offset, ref, refPrefix, q, sort } = params;
206
- const res = await ctx.SL.app.records.list(
207
- ctx.collectionId,
208
- ctx.appId,
209
- {
210
- ...ctx.recordType ? { recordType: ctx.recordType } : {},
211
- limit,
212
- offset,
213
- ref,
214
- refPrefix,
215
- q,
216
- sort
217
- },
218
- true
219
- );
220
- return {
221
- data: res?.data ?? [],
222
- total: res?.pagination?.total ?? (res?.data?.length ?? 0),
223
- hasMore: res?.pagination?.hasMore ?? false
224
- };
225
- };
226
- var getRecordByRef = async (ctx, ref) => {
227
- const res = await ctx.SL.app.records.list(
228
- ctx.collectionId,
229
- ctx.appId,
230
- { ...ctx.recordType ? { recordType: ctx.recordType } : {}, ref, limit: 1 },
231
- true
232
- );
233
- return res?.data?.[0] ?? null;
234
- };
235
- var upsertRecord = async (ctx, write) => {
236
- const ref = write.ref ?? deriveRefFromScope(write.scope);
237
- const res = await ctx.SL.app.records.upsert(ctx.collectionId, ctx.appId, {
238
- ref,
239
- ...ctx.recordType ? { recordType: ctx.recordType } : {},
240
- scope: write.scope,
241
- data: write.data,
242
- status: write.status,
243
- startsAt: write.startsAt,
244
- expiresAt: write.expiresAt,
245
- customId: write.customId,
246
- sourceSystem: write.sourceSystem
247
- });
248
- return { record: res, isCreate: !!res?.created };
249
- };
250
- var deleteRecord = async (ctx, ref) => {
251
- const existing = await getRecordByRef(ctx, ref).catch(() => null);
252
- if (!existing) return false;
253
- await ctx.SL.app.records.remove(ctx.collectionId, ctx.appId, existing.id, true);
254
- return true;
255
- };
256
- var restoreRecord = async (ctx, recordId) => ctx.SL.app.records.restore(ctx.collectionId, ctx.appId, recordId);
257
- var matchRecords = async (ctx, target, opts = {}) => ctx.SL.app.records.match(
258
- ctx.collectionId,
259
- ctx.appId,
260
- {
261
- target,
262
- ...ctx.recordType ? { recordType: ctx.recordType } : {},
263
- strategy: opts.strategy ?? "all",
264
- at: opts.at,
265
- includeScheduled: opts.includeScheduled,
266
- includeExpired: opts.includeExpired,
267
- limit: opts.limit
268
- },
269
- true
270
- );
271
- var bulkUpsert = async (ctx, entries) => {
272
- const CHUNK = 500;
273
- let saved = 0;
274
- let failed = 0;
275
- for (let i = 0; i < entries.length; i += CHUNK) {
276
- const slice = entries.slice(i, i + CHUNK);
277
- const items = slice.map((e) => ({
278
- ref: e.ref ?? deriveRefFromScope(e.scope),
279
- ...ctx.recordType ? { recordType: ctx.recordType } : {},
280
- scope: e.scope,
281
- data: e.data,
282
- status: e.status
283
- }));
284
- const res = await ctx.SL.app.records.bulkUpsert(ctx.collectionId, ctx.appId, items).catch(() => ({ saved: 0, failed: items.length }));
285
- saved += res.saved ?? 0;
286
- failed += res.failed ?? 0;
206
+ if (supportedScopes.includes("collection")) {
207
+ chain.push("");
287
208
  }
288
- return { saved, failed };
209
+ return Array.from(new Set(chain));
289
210
  };
290
- var bulkDelete = async (ctx, input) => {
291
- if ("scope" in input) {
292
- const res = await ctx.SL.app.records.bulkDelete(
293
- ctx.collectionId,
294
- ctx.appId,
295
- { scope: input.scope, ...ctx.recordType ? { recordType: ctx.recordType } : {} }
296
- );
297
- return { removed: res.deleted ?? 0 };
298
- }
299
- const CHUNK = 1e3;
300
- let removed = 0;
301
- for (let i = 0; i < input.refs.length; i += CHUNK) {
302
- const slice = input.refs.slice(i, i + CHUNK);
303
- const res = await ctx.SL.app.records.bulkDelete(
304
- ctx.collectionId,
305
- ctx.appId,
306
- { refs: slice, ...ctx.recordType ? { recordType: ctx.recordType } : {} }
307
- );
308
- removed += res.deleted ?? 0;
211
+ var splitItemRef = (raw) => {
212
+ if (!raw) return { scopeRef: "" };
213
+ const segs = raw.split("/").filter(Boolean);
214
+ const last = segs[segs.length - 1];
215
+ if (last && last.startsWith("item:")) {
216
+ return { scopeRef: segs.slice(0, -1).join("/"), itemId: last.slice("item:".length) };
309
217
  }
310
- return { removed };
218
+ return { scopeRef: raw };
311
219
  };
312
- var deriveRefFromScope = (scope) => {
313
- const parts = [];
314
- if (scope.facets && scope.facets.length > 0) {
315
- const sorted = [...scope.facets].sort((a, b) => a.key.localeCompare(b.key));
316
- for (const f of sorted) {
317
- const vals = [...f.valueKeys].sort().join(",");
318
- parts.push(vals ? `facet:${f.key}=${vals}` : `facet:${f.key}`);
319
- }
320
- }
321
- if (scope.productId) parts.push(`product:${scope.productId}`);
322
- if (scope.variantId) parts.push(`variant:${scope.variantId}`);
323
- if (scope.batchId) parts.push(`batch:${scope.batchId}`);
324
- if (scope.proofId) parts.push(`proof:${scope.proofId}`);
325
- return parts.join("/");
220
+ var buildItemRef = (scopeRef, itemId) => {
221
+ return scopeRef ? `${scopeRef}/item:${itemId}` : `item:${itemId}`;
326
222
  };
327
-
328
- // src/components/RecordsAdmin/hooks/useRecordList.ts
329
223
  var defaultClassify = (r) => {
330
224
  if (!r.data) return "empty";
331
225
  const keys = Object.keys(r.data);
@@ -366,7 +260,7 @@ var useRecordList = (args) => {
366
260
  scopeKind,
367
261
  search = "",
368
262
  filter = "all",
369
- classify,
263
+ classify: classify2,
370
264
  enabled = true,
371
265
  scaffolder,
372
266
  contextScope,
@@ -401,9 +295,9 @@ var useRecordList = (args) => {
401
295
  const [scaffolded, setScaffolded] = useState(null);
402
296
  const rawItems = useMemo(() => {
403
297
  const all = query.data?.pages.flatMap((p) => p.data) ?? [];
404
- const cls = classify ?? defaultClassify;
298
+ const cls = classify2 ?? defaultClassify;
405
299
  return all.map(toSummary).filter((s) => matchesScope(scopeKind, s.scope)).filter((s) => matchesContext(s.scope, contextScope)).map((s) => ({ ...s, status: cls(s) }));
406
- }, [query.data, scopeKind, classify, contextScope]);
300
+ }, [query.data, scopeKind, classify2, contextScope]);
407
301
  useEffect(() => {
408
302
  if (!scaffolder) {
409
303
  setScaffolded(null);
@@ -1187,7 +1081,7 @@ var ConfirmDialog = ({
1187
1081
  children: discardLabel
1188
1082
  }
1189
1083
  ),
1190
- /* @__PURE__ */ jsx(
1084
+ saveLabel ? /* @__PURE__ */ jsx(
1191
1085
  "button",
1192
1086
  {
1193
1087
  type: "button",
@@ -1196,7 +1090,7 @@ var ConfirmDialog = ({
1196
1090
  onClick: () => onChoice("save"),
1197
1091
  children: saveLabel
1198
1092
  }
1199
- )
1093
+ ) : null
1200
1094
  ] })
1201
1095
  ]
1202
1096
  }
@@ -1253,7 +1147,124 @@ var useConfirmDialog = () => {
1253
1147
  )
1254
1148
  };
1255
1149
  };
1150
+ var DEFAULTS2 = {
1151
+ title: "Replace existing values?",
1152
+ body: "This destination already has saved values. Replace them?",
1153
+ confirmLabel: "Replace",
1154
+ cancelLabel: "Cancel"
1155
+ };
1156
+ var usePasteConfirm = () => {
1157
+ const [open, setOpen] = useState(false);
1158
+ const [state, setState] = useState(DEFAULTS2);
1159
+ const resolverRef = useRef(null);
1160
+ const confirm = useCallback((i18n) => {
1161
+ setState({ ...DEFAULTS2, ...i18n ?? {} });
1162
+ setOpen(true);
1163
+ return new Promise((resolve) => {
1164
+ resolverRef.current = resolve;
1165
+ });
1166
+ }, []);
1167
+ const handleChoice = useCallback((choice) => {
1168
+ setOpen(false);
1169
+ const r = resolverRef.current;
1170
+ resolverRef.current = null;
1171
+ r?.(choice === "discard");
1172
+ }, []);
1173
+ return {
1174
+ confirm,
1175
+ dialog: /* @__PURE__ */ jsx(
1176
+ ConfirmDialog,
1177
+ {
1178
+ open,
1179
+ title: state.title,
1180
+ body: state.body,
1181
+ saveLabel: "",
1182
+ discardLabel: state.confirmLabel,
1183
+ cancelLabel: state.cancelLabel,
1184
+ onChoice: handleChoice
1185
+ }
1186
+ )
1187
+ };
1188
+ };
1189
+ var stores = /* @__PURE__ */ new Map();
1190
+ var storageKey = (key) => `ra:clipboard:${key}`;
1191
+ var getStore = (key) => {
1192
+ let s = stores.get(key);
1193
+ if (!s) {
1194
+ s = { entry: null, listeners: /* @__PURE__ */ new Set() };
1195
+ if (typeof window !== "undefined") {
1196
+ try {
1197
+ const raw = window.sessionStorage.getItem(storageKey(key));
1198
+ if (raw) s.entry = JSON.parse(raw);
1199
+ } catch {
1200
+ }
1201
+ }
1202
+ stores.set(key, s);
1203
+ }
1204
+ return s;
1205
+ };
1206
+ var persist = (key, entry) => {
1207
+ if (typeof window === "undefined") return;
1208
+ try {
1209
+ if (entry) window.sessionStorage.setItem(storageKey(key), JSON.stringify(entry));
1210
+ else window.sessionStorage.removeItem(storageKey(key));
1211
+ } catch {
1212
+ }
1213
+ };
1214
+ var notify = (store) => {
1215
+ store.listeners.forEach((l) => l());
1216
+ };
1217
+ var composeKey = (appId, recordType) => `${appId}::${recordType}`;
1218
+ function useRecordClipboard(args) {
1219
+ const key = composeKey(args.appId, args.recordType);
1220
+ const store = getStore(key);
1221
+ const [entry, setEntry] = useState(
1222
+ store.entry
1223
+ );
1224
+ useEffect(() => {
1225
+ const listener = () => setEntry(store.entry);
1226
+ store.listeners.add(listener);
1227
+ listener();
1228
+ return () => {
1229
+ store.listeners.delete(listener);
1230
+ };
1231
+ }, [store]);
1232
+ const set = useCallback((next) => {
1233
+ const full = { ...next, copiedAt: (/* @__PURE__ */ new Date()).toISOString() };
1234
+ store.entry = full;
1235
+ persist(key, full);
1236
+ notify(store);
1237
+ }, [store, key]);
1238
+ const clear = useCallback(() => {
1239
+ store.entry = null;
1240
+ persist(key, null);
1241
+ notify(store);
1242
+ }, [store, key]);
1243
+ return { entry, hasEntry: entry != null, set, clear };
1244
+ }
1245
+ function checkPasteCompatibility(source, destination) {
1246
+ const from = source.kind;
1247
+ const to = destination.kind;
1248
+ if (from === to) return { status: "allowed" };
1249
+ if ((from === "variant" || from === "batch") && to === "product") {
1250
+ return { status: "warn", reason: "This will overwrite product-level values." };
1251
+ }
1252
+ return { status: "allowed" };
1253
+ }
1254
+ function cloneValue(value) {
1255
+ if (value == null) return value;
1256
+ try {
1257
+ return structuredClone(value);
1258
+ } catch {
1259
+ try {
1260
+ return JSON.parse(JSON.stringify(value));
1261
+ } catch {
1262
+ return value;
1263
+ }
1264
+ }
1265
+ }
1256
1266
  var LABELS = {
1267
+ collection: "Global",
1257
1268
  product: "Products",
1258
1269
  facet: "Shared",
1259
1270
  variant: "Variants",
@@ -1332,8 +1343,90 @@ var StatusDot = ({ source, status, className }) => {
1332
1343
  else if (source === "inherited" || status === "partial") cls = "ra-status-shared";
1333
1344
  return /* @__PURE__ */ jsx("span", { className: cn("ra-status-dot", cls, className), "aria-hidden": "true" });
1334
1345
  };
1346
+ var RowContextMenu = ({
1347
+ onCopy,
1348
+ onPaste,
1349
+ canPaste,
1350
+ pasteWillReplace,
1351
+ pasteSourceLabel,
1352
+ i18n
1353
+ }) => {
1354
+ const [open, setOpen] = useState(false);
1355
+ const wrapperRef = useRef(null);
1356
+ useEffect(() => {
1357
+ if (!open) return;
1358
+ const onDoc = (e) => {
1359
+ if (!wrapperRef.current?.contains(e.target)) setOpen(false);
1360
+ };
1361
+ const onKey = (e) => {
1362
+ if (e.key === "Escape") setOpen(false);
1363
+ };
1364
+ document.addEventListener("mousedown", onDoc);
1365
+ document.addEventListener("keydown", onKey);
1366
+ return () => {
1367
+ document.removeEventListener("mousedown", onDoc);
1368
+ document.removeEventListener("keydown", onKey);
1369
+ };
1370
+ }, [open]);
1371
+ if (!onCopy && !onPaste) return null;
1372
+ const pasteLabel = !canPaste ? i18n.clipboardEmpty : pasteSourceLabel ? i18n.pasteFrom.replace("{name}", pasteSourceLabel) : pasteWillReplace ? i18n.pasteReplace : i18n.paste;
1373
+ return /* @__PURE__ */ jsxs("div", { ref: wrapperRef, className: "ra-row-menu-wrap relative", children: [
1374
+ /* @__PURE__ */ jsx(
1375
+ "button",
1376
+ {
1377
+ type: "button",
1378
+ className: "ra-row-menu-trigger",
1379
+ "aria-label": "Row actions",
1380
+ "aria-haspopup": "menu",
1381
+ "aria-expanded": open,
1382
+ onClick: (e) => {
1383
+ e.stopPropagation();
1384
+ setOpen((v) => !v);
1385
+ },
1386
+ children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "w-3.5 h-3.5", "aria-hidden": "true" })
1387
+ }
1388
+ ),
1389
+ open && /* @__PURE__ */ jsxs("div", { role: "menu", className: "ra-row-menu", onClick: (e) => e.stopPropagation(), children: [
1390
+ onCopy && /* @__PURE__ */ jsxs(
1391
+ "button",
1392
+ {
1393
+ type: "button",
1394
+ role: "menuitem",
1395
+ className: "ra-row-menu-item",
1396
+ onClick: (e) => {
1397
+ e.stopPropagation();
1398
+ setOpen(false);
1399
+ onCopy();
1400
+ },
1401
+ children: [
1402
+ /* @__PURE__ */ jsx(Copy, { className: "w-3 h-3", "aria-hidden": "true" }),
1403
+ /* @__PURE__ */ jsx("span", { children: i18n.copy })
1404
+ ]
1405
+ }
1406
+ ),
1407
+ onPaste && /* @__PURE__ */ jsxs(
1408
+ "button",
1409
+ {
1410
+ type: "button",
1411
+ role: "menuitem",
1412
+ className: "ra-row-menu-item",
1413
+ disabled: !canPaste,
1414
+ onClick: (e) => {
1415
+ e.stopPropagation();
1416
+ setOpen(false);
1417
+ if (canPaste) onPaste();
1418
+ },
1419
+ children: [
1420
+ /* @__PURE__ */ jsx(ClipboardPaste, { className: "w-3 h-3", "aria-hidden": "true" }),
1421
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: pasteLabel })
1422
+ ]
1423
+ }
1424
+ )
1425
+ ] })
1426
+ ] });
1427
+ };
1335
1428
  var DefaultRecordRow = ({ record, ctx, compact = false }) => {
1336
- const { selected, onSelect, isDirty } = ctx;
1429
+ const { selected, onSelect, isDirty, onCopy, onPaste, canPaste, pasteWillReplace, clipboardSourceLabel } = ctx;
1337
1430
  const ScopeIcon = record.scope.kind && record.scope.kind !== "collection" ? DEFAULT_ICONS.scope[record.scope.kind] : DEFAULT_ICONS.scope.product;
1338
1431
  return /* @__PURE__ */ jsxs(
1339
1432
  "button",
@@ -1358,69 +1451,24 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
1358
1451
  "aria-label": "Unsaved changes",
1359
1452
  className: "ra-status-dot ra-status-shared shrink-0"
1360
1453
  }
1361
- )
1362
- ]
1363
- }
1364
- );
1365
- };
1366
- var initials = (s) => s.split(/\s+/).filter(Boolean).slice(0, 2).map((p) => p[0]?.toUpperCase() ?? "").join("") || "?";
1367
- var DefaultRecordCard = ({ record, ctx, variant = "grid" }) => {
1368
- const { selected, onSelect, isDirty } = ctx;
1369
- const aspect = variant === "gallery" ? "aspect-video" : "aspect-square";
1370
- return /* @__PURE__ */ jsxs(
1371
- "button",
1372
- {
1373
- type: "button",
1374
- onClick: onSelect,
1375
- className: cn(
1376
- "group flex flex-col text-left rounded-md overflow-hidden border ra-card-hover",
1377
- selected && "ring-2"
1378
- ),
1379
- style: {
1380
- background: "hsl(var(--ra-surface))",
1381
- borderColor: selected ? "var(--ra-row-active-bd)" : "hsl(var(--ra-border))",
1382
- boxShadow: selected ? `0 0 0 2px hsl(var(--ra-accent) / 0.45), var(--ra-card-shadow)` : "var(--ra-card-shadow)"
1383
- },
1384
- children: [
1385
- /* @__PURE__ */ jsxs(
1386
- "div",
1454
+ ),
1455
+ (onCopy || onPaste) && /* @__PURE__ */ jsx(
1456
+ RowContextMenu,
1387
1457
  {
1388
- className: cn(aspect, "relative w-full flex items-center justify-center overflow-hidden"),
1389
- style: { background: "hsl(var(--ra-muted))" },
1390
- children: [
1391
- record.thumbnail ? /* @__PURE__ */ jsx(
1392
- "img",
1393
- {
1394
- src: record.thumbnail,
1395
- alt: "",
1396
- loading: "lazy",
1397
- className: "w-full h-full object-cover"
1398
- }
1399
- ) : /* @__PURE__ */ jsx(
1400
- "span",
1401
- {
1402
- className: "text-2xl ra-display",
1403
- style: { color: "hsl(var(--ra-muted-text))" },
1404
- children: initials(record.label)
1405
- }
1406
- ),
1407
- /* @__PURE__ */ jsx("div", { className: "absolute top-1.5 left-1.5", children: /* @__PURE__ */ jsx(StatusDot, { status: record.status }) }),
1408
- isDirty && /* @__PURE__ */ jsx(
1409
- "span",
1410
- {
1411
- title: "Unsaved changes",
1412
- "aria-label": "Unsaved changes",
1413
- className: "ra-status-dot ra-status-shared absolute top-1.5 right-1.5"
1414
- }
1415
- )
1416
- ]
1458
+ onCopy,
1459
+ onPaste,
1460
+ canPaste,
1461
+ pasteWillReplace,
1462
+ pasteSourceLabel: clipboardSourceLabel,
1463
+ i18n: {
1464
+ copy: DEFAULT_I18N.copy,
1465
+ paste: DEFAULT_I18N.paste,
1466
+ pasteFrom: DEFAULT_I18N.pasteFrom,
1467
+ pasteReplace: DEFAULT_I18N.pasteReplace,
1468
+ clipboardEmpty: DEFAULT_I18N.clipboardEmpty
1469
+ }
1417
1470
  }
1418
- ),
1419
- /* @__PURE__ */ jsxs("div", { className: "p-2.5 min-w-0", children: [
1420
- /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: record.label }),
1421
- variant === "gallery" && record.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: record.subtitle }),
1422
- record.badges && record.badges.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex gap-1 mt-1.5 flex-wrap", children: record.badges.slice(0, 3).map((b, i) => /* @__PURE__ */ jsx("span", { className: "ra-chip", "data-tone": "muted", children: b.label }, `${b.label}-${i}`)) })
1423
- ] })
1471
+ )
1424
1472
  ]
1425
1473
  }
1426
1474
  );
@@ -1432,14 +1480,18 @@ var RecordList = ({
1432
1480
  dirtyRef,
1433
1481
  presentation = "list",
1434
1482
  renderListRow,
1435
- renderCard,
1436
- groupBy
1483
+ groupBy,
1484
+ rowClipboard
1437
1485
  }) => {
1438
- const buildCtx = (item) => ({
1439
- selected: item.ref === selectedRef,
1440
- onSelect: () => onSelect(item),
1441
- isDirty: !!dirtyRef && item.ref === dirtyRef
1442
- });
1486
+ const buildCtx = (item) => {
1487
+ const cb = rowClipboard ? rowClipboard(item) : null;
1488
+ return {
1489
+ selected: item.ref === selectedRef,
1490
+ onSelect: () => onSelect(item),
1491
+ isDirty: !!dirtyRef && item.ref === dirtyRef,
1492
+ ...cb ?? {}
1493
+ };
1494
+ };
1443
1495
  const groups = useMemo(() => {
1444
1496
  if (!groupBy) return null;
1445
1497
  const buckets = /* @__PURE__ */ new Map();
@@ -1455,20 +1507,6 @@ var RecordList = ({
1455
1507
  return orderedKeys.map((k) => buckets.get(k));
1456
1508
  }, [items, groupBy]);
1457
1509
  const renderItems = (rows) => {
1458
- if (presentation === "grid" || presentation === "gallery") {
1459
- const minColPx = presentation === "gallery" ? 200 : 120;
1460
- return /* @__PURE__ */ jsx(
1461
- "div",
1462
- {
1463
- className: "grid gap-2 p-2",
1464
- style: { gridTemplateColumns: `repeat(auto-fill, minmax(${minColPx}px, 1fr))` },
1465
- children: rows.map((item) => {
1466
- const ctx = buildCtx(item);
1467
- return /* @__PURE__ */ jsx("div", { children: renderCard ? renderCard(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordCard, { record: item, ctx, variant: presentation }) }, item.ref);
1468
- })
1469
- }
1470
- );
1471
- }
1472
1510
  const compact = presentation === "compact";
1473
1511
  return /* @__PURE__ */ jsx("ul", { children: rows.map((item) => {
1474
1512
  const ctx = buildCtx(item);
@@ -1551,18 +1589,12 @@ var ErrorState = ({ error }) => /* @__PURE__ */ jsxs("div", { className: "ra-emp
1551
1589
  ] });
1552
1590
  var ICONS = {
1553
1591
  list: List,
1554
- grid: LayoutGrid,
1555
- gallery: Image,
1556
1592
  compact: Rows3
1557
1593
  };
1558
1594
  var labelFor = (p, i18n) => {
1559
1595
  switch (p) {
1560
1596
  case "list":
1561
1597
  return i18n.presentationList;
1562
- case "grid":
1563
- return i18n.presentationGrid;
1564
- case "gallery":
1565
- return i18n.presentationGallery;
1566
1598
  case "compact":
1567
1599
  return i18n.presentationCompact;
1568
1600
  }
@@ -1601,6 +1633,7 @@ var PresentationSwitcher = ({ options, value, onChange, i18n }) => {
1601
1633
  );
1602
1634
  };
1603
1635
  var KEY_PREFIX = "smartlinks-ui:records-admin:presentation";
1636
+ var ITEM_VIEW_KEY_PREFIX = "smartlinks-ui:records-admin:item-view";
1604
1637
  var safeRead = (key) => {
1605
1638
  try {
1606
1639
  return typeof window === "undefined" ? null : window.localStorage.getItem(key);
@@ -1632,46 +1665,235 @@ function usePresentationPref(args) {
1632
1665
  }, [key]);
1633
1666
  return [value, set];
1634
1667
  }
1635
- var segmentsFor = (s) => {
1636
- const out = [];
1637
- if (s.facetId) out.push({ label: s.facetValue ? `${s.facetId}: ${s.facetValue}` : `Facet: ${s.facetId}`, key: "facet" });
1638
- if (s.productId) out.push({ label: `Product: ${s.productId}`, key: "product" });
1639
- if (s.variantId) out.push({ label: `Variant: ${s.variantId}`, key: "variant" });
1640
- if (s.batchId) out.push({ label: `Batch: ${s.batchId}`, key: "batch" });
1641
- return out;
1642
- };
1643
- var ScopeBreadcrumb = ({ scope }) => {
1644
- const segs = segmentsFor(scope);
1645
- if (segs.length === 0) return null;
1646
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Scope", className: "flex items-center gap-1 text-xs flex-wrap", style: { color: "hsl(var(--ra-muted-text))" }, children: segs.map((s, i) => /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
1647
- i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 opacity-50" }),
1648
- /* @__PURE__ */ jsx("span", { style: { color: "hsl(var(--ra-text))" }, children: s.label })
1649
- ] }, s.key)) });
1650
- };
1651
- var BulkActionsMenu = ({
1652
- i18n,
1653
- onApplyToMany,
1654
- onCopyFrom,
1655
- onClearMany,
1656
- onImportCsv,
1657
- onExportCsv
1658
- }) => {
1659
- const [open, setOpen] = useState(false);
1660
- const ref = useRef(null);
1668
+ function useItemViewPref(args) {
1669
+ const { appId, recordType, options, defaultValue } = args;
1670
+ const key = `${ITEM_VIEW_KEY_PREFIX}:${appId}:${recordType ?? "_default"}`;
1671
+ const initial = () => {
1672
+ const stored = safeRead(key);
1673
+ if (stored && options.includes(stored)) return stored;
1674
+ return options.includes(defaultValue) ? defaultValue : options[0];
1675
+ };
1676
+ const [value, setValue] = useState(initial);
1661
1677
  useEffect(() => {
1662
- if (!open) return;
1663
- const onDocClick = (e) => {
1664
- if (ref.current && !ref.current.contains(e.target)) setOpen(false);
1665
- };
1666
- document.addEventListener("mousedown", onDocClick);
1667
- return () => document.removeEventListener("mousedown", onDocClick);
1668
- }, [open]);
1669
- const items = [
1670
- onApplyToMany && { key: "apply", label: i18n.applyToMany, onClick: onApplyToMany, icon: Layers },
1671
- onCopyFrom && { key: "copy", label: i18n.copyFrom, onClick: onCopyFrom, icon: Copy },
1672
- onImportCsv && { key: "imp", label: i18n.importCsv, onClick: onImportCsv, icon: Upload, divider: true },
1673
- onExportCsv && { key: "exp", label: i18n.exportCsv, onClick: onExportCsv, icon: Download },
1674
- onClearMany && { key: "clear", label: i18n.clear, onClick: onClearMany, icon: Eraser, tone: "danger", divider: true }
1678
+ if (!options.includes(value)) setValue(options[0]);
1679
+ }, [options, value]);
1680
+ const set = useCallback((next) => {
1681
+ setValue(next);
1682
+ safeWrite(key, next);
1683
+ }, [key]);
1684
+ return [value, set];
1685
+ }
1686
+ var QK_BASE2 = ["records-admin", "collection-items"];
1687
+ var defaultToSummary = (rec, base) => {
1688
+ const data = rec.data;
1689
+ if (!data) return base;
1690
+ const label = data.title ?? data.name ?? data.label ?? data.question ?? base.label;
1691
+ const subtitle = data.subtitle ?? data.summary ?? data.description ?? base.subtitle;
1692
+ const thumbnail = data.thumbnail ?? data.image ?? data.cover ?? base.thumbnail;
1693
+ return { ...base, label, subtitle, thumbnail };
1694
+ };
1695
+ function useCollectionItems(args) {
1696
+ const {
1697
+ ctx,
1698
+ scope,
1699
+ pageSize = 100,
1700
+ toSummary: toSummary2 = defaultToSummary,
1701
+ enabled = true
1702
+ } = args;
1703
+ const queryClient = useQueryClient();
1704
+ const scopeRef = scope?.raw ?? "";
1705
+ const refPrefix = scopeRef ? `${scopeRef}/item:` : "item:";
1706
+ const queryKey = useMemo(
1707
+ () => [...QK_BASE2, ctx.collectionId, ctx.appId, ctx.recordType, scopeRef],
1708
+ [ctx.collectionId, ctx.appId, ctx.recordType, scopeRef]
1709
+ );
1710
+ const query = useInfiniteQuery({
1711
+ queryKey,
1712
+ enabled: enabled && !!scope,
1713
+ initialPageParam: 0,
1714
+ queryFn: async ({ pageParam }) => {
1715
+ const offset = pageParam;
1716
+ const { data, total, hasMore } = await listRecords(ctx, {
1717
+ limit: pageSize,
1718
+ offset,
1719
+ refPrefix
1720
+ });
1721
+ return { data, total, hasMore, nextOffset: offset + data.length };
1722
+ },
1723
+ getNextPageParam: (last) => last.hasMore ? last.nextOffset : void 0,
1724
+ staleTime: 15e3
1725
+ });
1726
+ const items = useMemo(() => {
1727
+ const all = query.data?.pages.flatMap((p) => p.data) ?? [];
1728
+ return all.map((rec) => {
1729
+ const ref = rec.ref ?? "";
1730
+ const parsed = parseRef(ref);
1731
+ const { itemId } = splitItemRef(ref);
1732
+ if (!itemId) return null;
1733
+ const base = {
1734
+ id: rec.id,
1735
+ ref,
1736
+ scope: parsed,
1737
+ data: rec.data ?? null,
1738
+ status: rec.data ? "configured" : "empty",
1739
+ label: itemId,
1740
+ updatedAt: rec.updatedAt,
1741
+ itemId
1742
+ };
1743
+ return toSummary2(rec, base);
1744
+ }).filter((x) => x !== null);
1745
+ }, [query.data, toSummary2]);
1746
+ const refetch = useCallback(() => {
1747
+ queryClient.invalidateQueries({ queryKey });
1748
+ }, [queryClient, queryKey]);
1749
+ return {
1750
+ items,
1751
+ total: query.data?.pages[query.data.pages.length - 1]?.total ?? items.length,
1752
+ isLoading: query.isLoading,
1753
+ error: query.error ?? null,
1754
+ hasNextPage: query.hasNextPage,
1755
+ isFetchingNextPage: query.isFetchingNextPage,
1756
+ fetchNextPage: query.fetchNextPage,
1757
+ refetch
1758
+ };
1759
+ }
1760
+
1761
+ // src/components/RecordsAdmin/data/deepLinkAdapter.ts
1762
+ var findQueryHost = (loc) => {
1763
+ if (loc.search && loc.search.length > 1) return "search";
1764
+ if (loc.hash && loc.hash.includes("?")) return "hash";
1765
+ return "search";
1766
+ };
1767
+ var getQueryString = (loc) => {
1768
+ const host = findQueryHost(loc);
1769
+ if (host === "search") return loc.search.startsWith("?") ? loc.search.slice(1) : loc.search;
1770
+ const idx = loc.hash.indexOf("?");
1771
+ return idx >= 0 ? loc.hash.slice(idx + 1) : "";
1772
+ };
1773
+ var buildUrl = (loc, nextQuery) => {
1774
+ const host = findQueryHost(loc);
1775
+ const qs = nextQuery ? `?${nextQuery}` : "";
1776
+ if (host === "search") {
1777
+ return `${loc.pathname}${qs}${loc.hash}`;
1778
+ }
1779
+ const hashPath = loc.hash.includes("?") ? loc.hash.slice(0, loc.hash.indexOf("?")) : loc.hash;
1780
+ return `${loc.pathname}${loc.search}${hashPath}${qs}`;
1781
+ };
1782
+ var createDefaultDeepLinkAdapter = (paramNames) => ({
1783
+ read() {
1784
+ if (typeof window === "undefined") return {};
1785
+ const params = new URLSearchParams(getQueryString(window.location));
1786
+ return {
1787
+ item: params.get(paramNames.item),
1788
+ scope: params.get(paramNames.scope),
1789
+ view: params.get(paramNames.view)
1790
+ };
1791
+ },
1792
+ write(partial, mode) {
1793
+ if (typeof window === "undefined") return;
1794
+ const params = new URLSearchParams(getQueryString(window.location));
1795
+ const apply = (key, value) => {
1796
+ if (value == null || value === "") params.delete(key);
1797
+ else params.set(key, value);
1798
+ };
1799
+ if ("item" in partial) apply(paramNames.item, partial.item);
1800
+ if ("scope" in partial) apply(paramNames.scope, partial.scope);
1801
+ if ("view" in partial) apply(paramNames.view, partial.view);
1802
+ const nextUrl = buildUrl(window.location, params.toString());
1803
+ if (mode === "push") window.history.pushState({}, "", nextUrl);
1804
+ else window.history.replaceState({}, "", nextUrl);
1805
+ },
1806
+ subscribe(listener) {
1807
+ if (typeof window === "undefined") return () => {
1808
+ };
1809
+ window.addEventListener("popstate", listener);
1810
+ window.addEventListener("hashchange", listener);
1811
+ return () => {
1812
+ window.removeEventListener("popstate", listener);
1813
+ window.removeEventListener("hashchange", listener);
1814
+ };
1815
+ }
1816
+ });
1817
+
1818
+ // src/components/RecordsAdmin/hooks/useDeepLinkState.ts
1819
+ var SMART_PUSH = ["item.open", "item.close", "scope"];
1820
+ var classify = (mode, kind) => {
1821
+ if (mode === "push") return "push";
1822
+ if (mode === "replace") return "replace";
1823
+ return SMART_PUSH.includes(kind) ? "push" : "replace";
1824
+ };
1825
+ function useDeepLinkState(options) {
1826
+ const enabled = !!options?.enabled;
1827
+ const history = options?.history ?? "smart";
1828
+ const paramNames = useMemo(() => ({
1829
+ ...DEFAULT_DEEP_LINK_PARAM_NAMES,
1830
+ ...options?.paramNames ?? {}
1831
+ }), [options?.paramNames]);
1832
+ const defaultAdapterRef = useRef(null);
1833
+ const adapter = useMemo(() => {
1834
+ if (!enabled) return null;
1835
+ if (options?.adapter) return options.adapter;
1836
+ if (!defaultAdapterRef.current) {
1837
+ defaultAdapterRef.current = createDefaultDeepLinkAdapter(paramNames);
1838
+ }
1839
+ return defaultAdapterRef.current;
1840
+ }, [enabled, options?.adapter, paramNames]);
1841
+ const [urlState, setUrlState] = useState(
1842
+ () => adapter ? adapter.read() : {}
1843
+ );
1844
+ useEffect(() => {
1845
+ if (!adapter) return;
1846
+ setUrlState(adapter.read());
1847
+ return adapter.subscribe(() => setUrlState(adapter.read()));
1848
+ }, [adapter]);
1849
+ const emit = useCallback((partial, kind) => {
1850
+ if (!adapter) return;
1851
+ const mode = classify(history, kind);
1852
+ adapter.write(partial, mode);
1853
+ setUrlState((prev) => ({ ...prev, ...partial }));
1854
+ }, [adapter, history]);
1855
+ return { urlState, emit, paramNames, enabled };
1856
+ }
1857
+ var segmentsFor = (s) => {
1858
+ const out = [];
1859
+ if (s.facetId) out.push({ label: s.facetValue ? `${s.facetId}: ${s.facetValue}` : `Facet: ${s.facetId}`, key: "facet" });
1860
+ if (s.productId) out.push({ label: `Product: ${s.productId}`, key: "product" });
1861
+ if (s.variantId) out.push({ label: `Variant: ${s.variantId}`, key: "variant" });
1862
+ if (s.batchId) out.push({ label: `Batch: ${s.batchId}`, key: "batch" });
1863
+ return out;
1864
+ };
1865
+ var ScopeBreadcrumb = ({ scope }) => {
1866
+ const segs = segmentsFor(scope);
1867
+ if (segs.length === 0) return null;
1868
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Scope", className: "flex items-center gap-1 text-xs flex-wrap", style: { color: "hsl(var(--ra-muted-text))" }, children: segs.map((s, i) => /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
1869
+ i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 opacity-50" }),
1870
+ /* @__PURE__ */ jsx("span", { style: { color: "hsl(var(--ra-text))" }, children: s.label })
1871
+ ] }, s.key)) });
1872
+ };
1873
+ var BulkActionsMenu = ({
1874
+ i18n,
1875
+ onApplyToMany,
1876
+ onCopyFrom,
1877
+ onClearMany,
1878
+ onImportCsv,
1879
+ onExportCsv
1880
+ }) => {
1881
+ const [open, setOpen] = useState(false);
1882
+ const ref = useRef(null);
1883
+ useEffect(() => {
1884
+ if (!open) return;
1885
+ const onDocClick = (e) => {
1886
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
1887
+ };
1888
+ document.addEventListener("mousedown", onDocClick);
1889
+ return () => document.removeEventListener("mousedown", onDocClick);
1890
+ }, [open]);
1891
+ const items = [
1892
+ onApplyToMany && { key: "apply", label: i18n.applyToMany, onClick: onApplyToMany, icon: Layers },
1893
+ onCopyFrom && { key: "copy", label: i18n.copyFrom, onClick: onCopyFrom, icon: Copy },
1894
+ onImportCsv && { key: "imp", label: i18n.importCsv, onClick: onImportCsv, icon: Upload, divider: true },
1895
+ onExportCsv && { key: "exp", label: i18n.exportCsv, onClick: onExportCsv, icon: Download },
1896
+ onClearMany && { key: "clear", label: i18n.clear, onClick: onClearMany, icon: Eraser, tone: "danger", divider: true }
1675
1897
  ].filter(Boolean);
1676
1898
  if (items.length === 0) return null;
1677
1899
  return /* @__PURE__ */ jsxs("div", { className: "relative", ref, children: [
@@ -1721,8 +1943,10 @@ var DeleteButton = ({
1721
1943
  label = "Delete record",
1722
1944
  confirmLabel = "Confirm delete",
1723
1945
  revertMs = 3e3,
1724
- disabled
1946
+ disabled,
1947
+ icon
1725
1948
  }) => {
1949
+ const Icon = icon ?? Trash2;
1726
1950
  const [armed, setArmed] = useState(false);
1727
1951
  const [busy, setBusy] = useState(false);
1728
1952
  const timerRef = useRef(null);
@@ -1783,7 +2007,7 @@ var DeleteButton = ({
1783
2007
  color: "hsl(var(--ra-danger, var(--ra-text)))"
1784
2008
  },
1785
2009
  children: [
1786
- /* @__PURE__ */ jsx(Trash2, { className: "w-3.5 h-3.5" }),
2010
+ /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5" }),
1787
2011
  label
1788
2012
  ]
1789
2013
  }
@@ -1799,8 +2023,17 @@ function RecordEditor({
1799
2023
  onBeforeDelete,
1800
2024
  headerLabel,
1801
2025
  headerSubtitle,
1802
- headerMeta
2026
+ headerMeta,
2027
+ clipboard,
2028
+ actionLabels,
2029
+ actionIcons
1803
2030
  }) {
2031
+ const saveLabel = actionLabels?.save ?? i18n.save;
2032
+ const discardLabel = actionLabels?.discard ?? i18n.discard;
2033
+ const deleteLabel = actionLabels?.delete ?? i18n.delete;
2034
+ const SaveIcon = actionIcons?.save;
2035
+ const DiscardIcon = actionIcons?.discard;
2036
+ const DeleteIcon = actionIcons?.delete;
1804
2037
  const sourceLabel = ctx.source === "self" ? "Customised" : ctx.source === "inherited" ? "Inherited" : null;
1805
2038
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
1806
2039
  /* @__PURE__ */ jsxs(
@@ -1878,15 +2111,18 @@ function RecordEditor({
1878
2111
  style: { borderColor: "hsl(var(--ra-border))", background: "hsl(var(--ra-surface))" },
1879
2112
  children: [
1880
2113
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1881
- /* @__PURE__ */ jsx(
2114
+ /* @__PURE__ */ jsxs(
1882
2115
  "button",
1883
2116
  {
1884
2117
  type: "button",
1885
2118
  onClick: ctx.reset,
1886
2119
  disabled: !ctx.isDirty || !!ctx.isSaving,
1887
- className: "text-xs px-3 py-1.5 rounded-md border transition-opacity disabled:opacity-40 hover:bg-[hsl(var(--ra-muted))]",
2120
+ className: "text-xs px-3 py-1.5 rounded-md border transition-opacity disabled:opacity-40 hover:bg-[hsl(var(--ra-muted))] inline-flex items-center gap-1.5",
1888
2121
  style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
1889
- children: i18n.discard
2122
+ children: [
2123
+ DiscardIcon && /* @__PURE__ */ jsx(DiscardIcon, { className: "h-4 w-4" }),
2124
+ discardLabel
2125
+ ]
1890
2126
  }
1891
2127
  ),
1892
2128
  ctx.canRemove && /* @__PURE__ */ jsx(
@@ -1894,10 +2130,45 @@ function RecordEditor({
1894
2130
  {
1895
2131
  onConfirm: () => ctx.remove(),
1896
2132
  onBeforeDelete,
1897
- label: i18n.delete,
1898
- confirmLabel: i18n.confirmDelete
2133
+ label: deleteLabel,
2134
+ confirmLabel: i18n.confirmDelete,
2135
+ icon: DeleteIcon
1899
2136
  }
1900
2137
  ),
2138
+ clipboard && /* @__PURE__ */ jsxs(Fragment, { children: [
2139
+ /* @__PURE__ */ jsxs(
2140
+ "button",
2141
+ {
2142
+ type: "button",
2143
+ onClick: clipboard.onCopy,
2144
+ disabled: !clipboard.canCopy || !!ctx.isSaving,
2145
+ title: i18n.copy,
2146
+ "aria-label": i18n.copy,
2147
+ className: "text-xs px-2.5 py-1.5 rounded-md border transition-opacity disabled:opacity-40 hover:bg-[hsl(var(--ra-muted))] inline-flex items-center gap-1.5",
2148
+ style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
2149
+ children: [
2150
+ /* @__PURE__ */ jsx(Copy, { className: "w-3 h-3" }),
2151
+ i18n.copy
2152
+ ]
2153
+ }
2154
+ ),
2155
+ /* @__PURE__ */ jsxs(
2156
+ "button",
2157
+ {
2158
+ type: "button",
2159
+ onClick: clipboard.onPaste,
2160
+ disabled: !clipboard.canPaste || !!ctx.isSaving,
2161
+ title: !clipboard.canPaste ? i18n.clipboardEmpty : clipboard.pasteSourceLabel ? i18n.pasteFrom.replace("{name}", clipboard.pasteSourceLabel) : i18n.paste,
2162
+ "aria-label": i18n.paste,
2163
+ className: "text-xs px-2.5 py-1.5 rounded-md border transition-opacity disabled:opacity-40 hover:bg-[hsl(var(--ra-muted))] inline-flex items-center gap-1.5",
2164
+ style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
2165
+ children: [
2166
+ /* @__PURE__ */ jsx(ClipboardPaste, { className: "w-3 h-3" }),
2167
+ clipboard.pasteWillReplace ? i18n.pasteReplace : i18n.paste
2168
+ ]
2169
+ }
2170
+ )
2171
+ ] }),
1901
2172
  footerExtra,
1902
2173
  ctx.saveError != null && !ctx.isSaving && /* @__PURE__ */ jsx(
1903
2174
  "span",
@@ -1909,7 +2180,7 @@ function RecordEditor({
1909
2180
  }
1910
2181
  )
1911
2182
  ] }),
1912
- /* @__PURE__ */ jsx(
2183
+ /* @__PURE__ */ jsxs(
1913
2184
  "button",
1914
2185
  {
1915
2186
  type: "button",
@@ -1918,9 +2189,12 @@ function RecordEditor({
1918
2189
  });
1919
2190
  },
1920
2191
  disabled: !ctx.isDirty || !!ctx.isSaving,
1921
- className: "text-xs px-3 py-1.5 rounded-md font-medium transition-opacity disabled:opacity-40",
2192
+ className: "text-xs px-3 py-1.5 rounded-md font-medium transition-opacity disabled:opacity-40 inline-flex items-center gap-1.5",
1922
2193
  style: { background: "hsl(var(--ra-accent))", color: "hsl(var(--ra-surface))" },
1923
- children: ctx.isSaving ? i18n.saving ?? "Saving\u2026" : i18n.save
2194
+ children: [
2195
+ SaveIcon && !ctx.isSaving && /* @__PURE__ */ jsx(SaveIcon, { className: "h-4 w-4" }),
2196
+ ctx.isSaving ? i18n.saving ?? "Saving\u2026" : saveLabel
2197
+ ]
1924
2198
  }
1925
2199
  )
1926
2200
  ]
@@ -1945,16 +2219,18 @@ var ProductDrillDown = ({
1945
2219
  batches,
1946
2220
  variantsLoading,
1947
2221
  batchesLoading,
1948
- children
2222
+ children,
2223
+ hideSingleTab
1949
2224
  }) => {
1950
2225
  const tabs = ["product"];
1951
2226
  if (showVariants) tabs.push("variant");
1952
2227
  if (showBatches) tabs.push("batch");
2228
+ const showTabStrip = tabs.length > 1 || !hideSingleTab;
1953
2229
  const childList = active === "variant" ? variants : active === "batch" ? batches : [];
1954
2230
  const childLoading = active === "variant" ? variantsLoading : active === "batch" ? batchesLoading : false;
1955
2231
  const childEmptyLabel = active === "variant" ? "No variants" : "No batches";
1956
2232
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
1957
- /* @__PURE__ */ jsx(
2233
+ showTabStrip && /* @__PURE__ */ jsx(
1958
2234
  "div",
1959
2235
  {
1960
2236
  className: "flex items-center gap-1 px-4 pt-3 border-b",
@@ -2367,6 +2643,394 @@ var PreviewScopePicker = ({
2367
2643
  )
2368
2644
  ] });
2369
2645
  };
2646
+ var ICONS2 = {
2647
+ table: Table,
2648
+ cards: LayoutGrid,
2649
+ gallery: Image
2650
+ };
2651
+ var labelFor2 = (v, i18n) => {
2652
+ if (v === "table") return i18n.itemViewTable;
2653
+ if (v === "cards") return i18n.itemViewCards;
2654
+ return i18n.itemViewGallery;
2655
+ };
2656
+ var ItemViewSwitcher = ({ options, value, onChange, i18n }) => {
2657
+ if (options.length < 2) return null;
2658
+ return /* @__PURE__ */ jsx("div", { role: "tablist", className: "ra-tabs", "aria-label": "Item view", style: { padding: "0.15rem" }, children: options.map((opt) => {
2659
+ const Icon = ICONS2[opt];
2660
+ const active = value === opt;
2661
+ return /* @__PURE__ */ jsxs(
2662
+ "button",
2663
+ {
2664
+ type: "button",
2665
+ role: "tab",
2666
+ "aria-selected": active,
2667
+ onClick: () => onChange(opt),
2668
+ className: "ra-tab",
2669
+ title: labelFor2(opt, i18n),
2670
+ style: { padding: "0.3rem 0.55rem" },
2671
+ children: [
2672
+ /* @__PURE__ */ jsx(Icon, { className: cn("ra-tab-icon w-3.5 h-3.5") }),
2673
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: labelFor2(opt, i18n) })
2674
+ ]
2675
+ },
2676
+ opt
2677
+ );
2678
+ }) });
2679
+ };
2680
+ var formatDate = (iso) => {
2681
+ if (!iso) return "\u2014";
2682
+ try {
2683
+ const d = new Date(iso);
2684
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
2685
+ } catch {
2686
+ return iso;
2687
+ }
2688
+ };
2689
+ function DefaultItemTable({
2690
+ items,
2691
+ columns,
2692
+ selectedId,
2693
+ onOpen,
2694
+ onDelete,
2695
+ i18n
2696
+ }) {
2697
+ const cols = columns ?? [];
2698
+ const useFallback = cols.length === 0;
2699
+ return /* @__PURE__ */ jsx("div", { className: "ra-item-table-wrap", children: /* @__PURE__ */ jsxs("table", { className: "ra-item-table", children: [
2700
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
2701
+ useFallback ? /* @__PURE__ */ jsxs(Fragment, { children: [
2702
+ /* @__PURE__ */ jsx("th", { children: i18n.itemColumnLabel }),
2703
+ /* @__PURE__ */ jsx("th", { style: { width: "12rem" }, children: i18n.itemColumnUpdated })
2704
+ ] }) : cols.map((c) => /* @__PURE__ */ jsx("th", { style: { width: c.width, textAlign: c.align ?? "left" }, children: c.header }, c.key)),
2705
+ /* @__PURE__ */ jsx(
2706
+ "th",
2707
+ {
2708
+ style: { width: "6.5rem", textAlign: "right" },
2709
+ "aria-label": i18n.itemActions
2710
+ }
2711
+ )
2712
+ ] }) }),
2713
+ /* @__PURE__ */ jsx("tbody", { children: items.map((item) => {
2714
+ const id = item.itemId ?? "";
2715
+ const isSelected = !!selectedId && selectedId === id;
2716
+ return /* @__PURE__ */ jsxs(
2717
+ "tr",
2718
+ {
2719
+ "data-selected": isSelected,
2720
+ onClick: () => onOpen(id),
2721
+ className: "ra-item-row",
2722
+ children: [
2723
+ useFallback ? /* @__PURE__ */ jsxs(Fragment, { children: [
2724
+ /* @__PURE__ */ jsxs("td", { children: [
2725
+ /* @__PURE__ */ jsx("div", { className: "ra-item-row-title", children: item.label }),
2726
+ item.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-item-row-sub", children: item.subtitle })
2727
+ ] }),
2728
+ /* @__PURE__ */ jsx("td", { className: "ra-item-row-meta", children: formatDate(item.updatedAt) })
2729
+ ] }) : cols.map((c) => /* @__PURE__ */ jsx("td", { style: { textAlign: c.align ?? "left" }, children: c.render(item) }, c.key)),
2730
+ /* @__PURE__ */ jsxs("td", { className: "ra-item-row-actions", children: [
2731
+ /* @__PURE__ */ jsx(
2732
+ "button",
2733
+ {
2734
+ type: "button",
2735
+ className: "ra-row-action",
2736
+ onClick: (e) => {
2737
+ e.stopPropagation();
2738
+ onOpen(id);
2739
+ },
2740
+ "aria-label": "Edit",
2741
+ children: /* @__PURE__ */ jsx(Pencil, { className: "w-3.5 h-3.5" })
2742
+ }
2743
+ ),
2744
+ /* @__PURE__ */ jsx(
2745
+ "button",
2746
+ {
2747
+ type: "button",
2748
+ className: "ra-row-action",
2749
+ "data-tone": "danger",
2750
+ onClick: (e) => {
2751
+ e.stopPropagation();
2752
+ onDelete(id);
2753
+ },
2754
+ "aria-label": i18n.delete,
2755
+ children: /* @__PURE__ */ jsx(Trash2, { className: "w-3.5 h-3.5" })
2756
+ }
2757
+ )
2758
+ ] })
2759
+ ]
2760
+ },
2761
+ item.ref
2762
+ );
2763
+ }) })
2764
+ ] }) });
2765
+ }
2766
+ var initials = (label) => label.split(/\s+/).slice(0, 2).map((s) => s[0]?.toUpperCase() ?? "").join("") || "?";
2767
+ function DefaultItemCards({
2768
+ items,
2769
+ variant,
2770
+ selectedId,
2771
+ ctx,
2772
+ renderCard,
2773
+ i18n
2774
+ }) {
2775
+ const isGallery = variant === "gallery";
2776
+ return /* @__PURE__ */ jsx("div", { className: isGallery ? "ra-item-gallery" : "ra-item-cards", children: items.map((item) => {
2777
+ const id = item.itemId ?? "";
2778
+ const slotCtx = {
2779
+ ...ctx,
2780
+ selected: selectedId === id
2781
+ };
2782
+ if (renderCard) {
2783
+ return /* @__PURE__ */ jsx(
2784
+ "div",
2785
+ {
2786
+ onClick: () => ctx.onOpen(id),
2787
+ className: "ra-item-card-wrap",
2788
+ "data-selected": slotCtx.selected,
2789
+ children: renderCard(item, slotCtx)
2790
+ },
2791
+ item.ref
2792
+ );
2793
+ }
2794
+ return /* @__PURE__ */ jsxs(
2795
+ "button",
2796
+ {
2797
+ type: "button",
2798
+ onClick: () => ctx.onOpen(id),
2799
+ className: `ra-item-card ${isGallery ? "ra-item-card--gallery" : ""}`,
2800
+ "data-selected": slotCtx.selected,
2801
+ children: [
2802
+ /* @__PURE__ */ jsx("div", { className: `ra-item-card-thumb ${isGallery ? "ra-item-card-thumb--gallery" : ""}`, children: item.thumbnail ? /* @__PURE__ */ jsx("img", { src: item.thumbnail, alt: "", loading: "lazy" }) : /* @__PURE__ */ jsx("span", { className: "ra-item-card-initials", children: initials(item.label) }) }),
2803
+ /* @__PURE__ */ jsxs("div", { className: "ra-item-card-body", children: [
2804
+ /* @__PURE__ */ jsx("div", { className: "ra-item-card-title", children: item.label }),
2805
+ item.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-item-card-sub", children: item.subtitle })
2806
+ ] }),
2807
+ /* @__PURE__ */ jsx(
2808
+ "button",
2809
+ {
2810
+ type: "button",
2811
+ className: "ra-row-action ra-item-card-delete",
2812
+ "data-tone": "danger",
2813
+ onClick: (e) => {
2814
+ e.stopPropagation();
2815
+ ctx.onDelete(id);
2816
+ },
2817
+ "aria-label": i18n.delete,
2818
+ children: /* @__PURE__ */ jsx(Trash2, { className: "w-3.5 h-3.5" })
2819
+ }
2820
+ )
2821
+ ]
2822
+ },
2823
+ item.ref
2824
+ );
2825
+ }) });
2826
+ }
2827
+ function ItemListView({
2828
+ items,
2829
+ isLoading,
2830
+ error,
2831
+ ctx,
2832
+ itemNoun,
2833
+ view,
2834
+ views,
2835
+ onViewChange,
2836
+ renderItemList,
2837
+ renderItemCard,
2838
+ renderItemEmpty,
2839
+ itemColumns,
2840
+ i18n
2841
+ }) {
2842
+ const newLabel = i18n.newItem.includes("{noun}") ? i18n.newItem.replace("{noun}", itemNoun) : i18n.newItem;
2843
+ const toolbar = /* @__PURE__ */ jsxs("div", { className: "ra-item-toolbar", children: [
2844
+ /* @__PURE__ */ jsxs("div", { className: "ra-item-toolbar-title", children: [
2845
+ /* @__PURE__ */ jsx("h2", { className: "ra-display", style: { fontSize: "0.95rem", margin: 0 }, children: i18n.itemListTitle }),
2846
+ /* @__PURE__ */ jsx("span", { className: "ra-item-toolbar-count", children: items.length })
2847
+ ] }),
2848
+ /* @__PURE__ */ jsxs("div", { className: "ra-item-toolbar-actions", children: [
2849
+ !renderItemList && /* @__PURE__ */ jsx(
2850
+ ItemViewSwitcher,
2851
+ {
2852
+ options: views,
2853
+ value: view,
2854
+ onChange: onViewChange,
2855
+ i18n
2856
+ }
2857
+ ),
2858
+ /* @__PURE__ */ jsxs(
2859
+ "button",
2860
+ {
2861
+ type: "button",
2862
+ onClick: ctx.onCreate,
2863
+ className: "ra-btn",
2864
+ "data-variant": "primary",
2865
+ children: [
2866
+ /* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5" }),
2867
+ newLabel
2868
+ ]
2869
+ }
2870
+ )
2871
+ ] })
2872
+ ] });
2873
+ let body;
2874
+ if (isLoading) {
2875
+ body = /* @__PURE__ */ jsx(LoadingState, {});
2876
+ } else if (error) {
2877
+ body = /* @__PURE__ */ jsx(ErrorState, { error });
2878
+ } else if (items.length === 0) {
2879
+ body = renderItemEmpty ? renderItemEmpty(ctx) : /* @__PURE__ */ jsx(
2880
+ EmptyState,
2881
+ {
2882
+ title: i18n.noItemsTitle,
2883
+ body: i18n.noItemsBody,
2884
+ action: /* @__PURE__ */ jsxs(
2885
+ "button",
2886
+ {
2887
+ type: "button",
2888
+ onClick: ctx.onCreate,
2889
+ className: "ra-btn",
2890
+ "data-variant": "primary",
2891
+ children: [
2892
+ /* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5" }),
2893
+ newLabel
2894
+ ]
2895
+ }
2896
+ )
2897
+ }
2898
+ );
2899
+ } else if (renderItemList) {
2900
+ body = renderItemList(items, ctx);
2901
+ } else if (view === "table") {
2902
+ body = /* @__PURE__ */ jsx(
2903
+ DefaultItemTable,
2904
+ {
2905
+ items,
2906
+ columns: itemColumns,
2907
+ selectedId: ctx.selectedId,
2908
+ onOpen: ctx.onOpen,
2909
+ onDelete: ctx.onDelete,
2910
+ i18n
2911
+ }
2912
+ );
2913
+ } else {
2914
+ body = /* @__PURE__ */ jsx(
2915
+ DefaultItemCards,
2916
+ {
2917
+ items,
2918
+ variant: view,
2919
+ selectedId: ctx.selectedId,
2920
+ ctx,
2921
+ renderCard: renderItemCard,
2922
+ i18n
2923
+ }
2924
+ );
2925
+ }
2926
+ return /* @__PURE__ */ jsxs("div", { className: "ra-item-list", children: [
2927
+ toolbar,
2928
+ /* @__PURE__ */ jsx("div", { className: "ra-item-list-body", children: body })
2929
+ ] });
2930
+ }
2931
+ var EditorItemNav = ({
2932
+ label,
2933
+ position,
2934
+ total,
2935
+ onBack,
2936
+ onPrev,
2937
+ onNext,
2938
+ canPrev,
2939
+ canNext,
2940
+ i18n
2941
+ }) => /* @__PURE__ */ jsxs("div", { className: "ra-item-nav", children: [
2942
+ /* @__PURE__ */ jsxs(
2943
+ "button",
2944
+ {
2945
+ type: "button",
2946
+ onClick: onBack,
2947
+ className: "ra-btn",
2948
+ "data-variant": "ghost",
2949
+ children: [
2950
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "w-3.5 h-3.5" }),
2951
+ i18n.backToList
2952
+ ]
2953
+ }
2954
+ ),
2955
+ typeof position === "number" && typeof total === "number" && total > 0 && /* @__PURE__ */ jsxs("span", { className: "ra-item-nav-position", "aria-label": label, children: [
2956
+ position,
2957
+ " / ",
2958
+ total
2959
+ ] }),
2960
+ /* @__PURE__ */ jsxs("div", { className: "ra-item-nav-arrows", children: [
2961
+ /* @__PURE__ */ jsx(
2962
+ "button",
2963
+ {
2964
+ type: "button",
2965
+ onClick: onPrev,
2966
+ disabled: !canPrev,
2967
+ className: "ra-row-action",
2968
+ "aria-label": i18n.prevItem,
2969
+ title: i18n.prevItem,
2970
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-4 h-4" })
2971
+ }
2972
+ ),
2973
+ /* @__PURE__ */ jsx(
2974
+ "button",
2975
+ {
2976
+ type: "button",
2977
+ onClick: onNext,
2978
+ disabled: !canNext,
2979
+ className: "ra-row-action",
2980
+ "aria-label": i18n.nextItem,
2981
+ title: i18n.nextItem,
2982
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4" })
2983
+ }
2984
+ )
2985
+ ] })
2986
+ ] });
2987
+ function SiblingRail({
2988
+ items,
2989
+ selectedItemId,
2990
+ isLoading,
2991
+ error,
2992
+ onBack,
2993
+ onSelect,
2994
+ i18n
2995
+ }) {
2996
+ return /* @__PURE__ */ jsxs("div", { className: "ra-sibling-rail", children: [
2997
+ /* @__PURE__ */ jsxs(
2998
+ "button",
2999
+ {
3000
+ type: "button",
3001
+ onClick: onBack,
3002
+ className: "ra-sibling-back",
3003
+ children: [
3004
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "w-3.5 h-3.5" }),
3005
+ i18n.backToScopes
3006
+ ]
3007
+ }
3008
+ ),
3009
+ /* @__PURE__ */ jsx("div", { className: "ra-sibling-heading", children: i18n.siblingsHeading }),
3010
+ /* @__PURE__ */ jsxs("div", { className: "ra-sibling-body", children: [
3011
+ isLoading && /* @__PURE__ */ jsx(LoadingState, {}),
3012
+ !isLoading && error && /* @__PURE__ */ jsx(ErrorState, { error }),
3013
+ !isLoading && !error && items.length === 0 && /* @__PURE__ */ jsx(EmptyState, { title: i18n.noItemsTitle, body: i18n.noItemsBody }),
3014
+ !isLoading && !error && items.length > 0 && /* @__PURE__ */ jsx("ul", { className: "ra-sibling-list", children: items.map((item) => {
3015
+ const id = item.itemId ?? "";
3016
+ const selected = selectedItemId === id;
3017
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
3018
+ "button",
3019
+ {
3020
+ type: "button",
3021
+ onClick: () => onSelect(id),
3022
+ className: "ra-row",
3023
+ "data-selected": selected,
3024
+ children: /* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
3025
+ /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: item.label }),
3026
+ item.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: item.subtitle })
3027
+ ] })
3028
+ }
3029
+ ) }, item.ref);
3030
+ }) })
3031
+ ] })
3032
+ ] });
3033
+ }
2370
3034
  var TONE_ICON = {
2371
3035
  info: Lightbulb,
2372
3036
  success: CheckCircle2,
@@ -2395,8 +3059,9 @@ var IntroCard = ({ title, body, onDismiss, tone = "info", action }) => {
2395
3059
  )
2396
3060
  ] });
2397
3061
  };
2398
- var UtilityRow = ({ label, introHidden, onShowIntro }) => {
3062
+ var UtilityRow = ({ label, customLabel, introHidden, onShowIntro }) => {
2399
3063
  if (!introHidden || !onShowIntro) return null;
3064
+ const text = customLabel ?? `How ${label.toLowerCase()} works`;
2400
3065
  return /* @__PURE__ */ jsx(
2401
3066
  "div",
2402
3067
  {
@@ -2412,9 +3077,7 @@ var UtilityRow = ({ label, introHidden, onShowIntro }) => {
2412
3077
  style: { padding: "0.25rem 0.55rem", fontSize: "0.7rem" },
2413
3078
  children: [
2414
3079
  /* @__PURE__ */ jsx(HelpCircle, { className: "w-3 h-3" }),
2415
- "How ",
2416
- label.toLowerCase(),
2417
- " works"
3080
+ text
2418
3081
  ]
2419
3082
  }
2420
3083
  )
@@ -2433,7 +3096,8 @@ function ShellHeader({
2433
3096
  stats,
2434
3097
  statsItems,
2435
3098
  statsTitle,
2436
- statsIcon
3099
+ statsIcon,
3100
+ trailingSlot
2437
3101
  }) {
2438
3102
  let iconNode = null;
2439
3103
  if (showHeaderIcon) {
@@ -2488,7 +3152,10 @@ function ShellHeader({
2488
3152
  ]
2489
3153
  }
2490
3154
  ) : null,
2491
- headerActions ? /* @__PURE__ */ jsx("div", { className: "ra-header-actions", children: headerActions }) : null
3155
+ headerActions || trailingSlot ? /* @__PURE__ */ jsxs("div", { className: "ra-header-actions", children: [
3156
+ headerActions,
3157
+ trailingSlot
3158
+ ] }) : null
2492
3159
  ] })
2493
3160
  ] });
2494
3161
  }
@@ -2503,8 +3170,12 @@ var UnsavedBanner = ({
2503
3170
  discardLabel,
2504
3171
  bodyTemplate,
2505
3172
  savingLabel,
2506
- errorLabel
3173
+ errorLabel,
3174
+ SaveIcon,
3175
+ DiscardIcon
2507
3176
  }) => {
3177
+ const SI = SaveIcon ?? Save;
3178
+ const DI = DiscardIcon ?? Undo2;
2508
3179
  const name = label ?? context ?? "this record";
2509
3180
  const message = bodyTemplate.replace("{name}", name);
2510
3181
  return /* @__PURE__ */ jsxs("div", { className: "ra-unsaved-banner", role: "status", "aria-live": "polite", children: [
@@ -2526,7 +3197,7 @@ var UnsavedBanner = ({
2526
3197
  onClick: onDiscard,
2527
3198
  disabled: isSaving,
2528
3199
  children: [
2529
- /* @__PURE__ */ jsx(Undo2, { className: "w-3 h-3" }),
3200
+ /* @__PURE__ */ jsx(DI, { className: "w-3 h-3" }),
2530
3201
  discardLabel
2531
3202
  ]
2532
3203
  }
@@ -2539,7 +3210,7 @@ var UnsavedBanner = ({
2539
3210
  onClick: onSave,
2540
3211
  disabled: isSaving,
2541
3212
  children: [
2542
- /* @__PURE__ */ jsx(Save, { className: "w-3 h-3" }),
3213
+ /* @__PURE__ */ jsx(SI, { className: "w-3 h-3" }),
2543
3214
  isSaving ? savingLabel ?? "Saving\u2026" : saveLabel
2544
3215
  ]
2545
3216
  }
@@ -2547,6 +3218,25 @@ var UnsavedBanner = ({
2547
3218
  ] })
2548
3219
  ] });
2549
3220
  };
3221
+ var ClipboardToast = ({ message, variant = "copy", onDismiss }) => {
3222
+ useEffect(() => {
3223
+ const t = window.setTimeout(onDismiss, 2500);
3224
+ return () => window.clearTimeout(t);
3225
+ }, [message, onDismiss]);
3226
+ const Icon = variant === "paste" ? ClipboardPaste : Copy;
3227
+ return /* @__PURE__ */ jsxs(
3228
+ "div",
3229
+ {
3230
+ role: "status",
3231
+ "aria-live": "polite",
3232
+ className: "ra-clipboard-toast",
3233
+ children: [
3234
+ /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5 shrink-0", "aria-hidden": "true" }),
3235
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: message })
3236
+ ]
3237
+ }
3238
+ );
3239
+ };
2550
3240
 
2551
3241
  // src/components/RecordsAdmin/data/csv.ts
2552
3242
  var escapeCell = (s) => {
@@ -2656,7 +3346,7 @@ var downloadBlob = (blob, filename) => {
2656
3346
  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.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');
2657
3347
 
2658
3348
  // src/components/RecordsAdmin/shell/shell.css
2659
- 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(--ra-muted));\n border-radius: calc(var(--ra-radius) * 0.85);\n border: 1px solid hsl(var(--ra-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(--ra-radius) * 0.65);\n font-size: 0.78rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\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(--ra-surface));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-tab[aria-selected=true] {\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n box-shadow: var(--ra-card-shadow);\n font-weight: var(--ra-title-weight);\n}\n.ra-shell .ra-tab[aria-selected=true] .ra-tab-icon {\n color: hsl(var(--ra-accent));\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(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\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(--ra-muted-text) / 0.15);\n color: hsl(var(--ra-muted-text));\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.65rem;\n width: 100%;\n text-align: left;\n padding: 0.65rem 0.85rem;\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-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\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.875rem;\n line-height: 1.25;\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.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-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");
3349
+ 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(--ra-muted));\n border-radius: calc(var(--ra-radius) * 0.85);\n border: 1px solid hsl(var(--ra-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(--ra-radius) * 0.65);\n font-size: 0.78rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\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(--ra-surface));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-tab[aria-selected=true] {\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n box-shadow: var(--ra-card-shadow);\n font-weight: var(--ra-title-weight);\n}\n.ra-shell .ra-tab[aria-selected=true] .ra-tab-icon {\n color: hsl(var(--ra-accent));\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(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\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(--ra-muted-text) / 0.15);\n color: hsl(var(--ra-muted-text));\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.65rem;\n width: 100%;\n text-align: left;\n padding: 0.65rem 0.85rem;\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-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\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.875rem;\n line-height: 1.25;\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.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-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");
2660
3350
  var TOP_LEVEL_SCOPES = ["facet", "product"];
2661
3351
  var defaultItemId = () => {
2662
3352
  const time = Date.now().toString(36);
@@ -2689,7 +3379,7 @@ function RecordsAdminShell(props) {
2689
3379
  renderPreview,
2690
3380
  intro,
2691
3381
  csvSchema,
2692
- classify,
3382
+ classify: classify2,
2693
3383
  defaultData,
2694
3384
  i18n: i18nOverride,
2695
3385
  onTelemetry,
@@ -2705,7 +3395,6 @@ function RecordsAdminShell(props) {
2705
3395
  disableBeforeUnload = false,
2706
3396
  presentations = ["list"],
2707
3397
  defaultPresentation,
2708
- renderCard,
2709
3398
  renderListRow,
2710
3399
  renderEmpty,
2711
3400
  cardinality = "singleton",
@@ -2724,10 +3413,35 @@ function RecordsAdminShell(props) {
2724
3413
  icons: iconsOverride,
2725
3414
  groupBy,
2726
3415
  renderEmptyState,
2727
- density = "comfortable"
3416
+ density = "comfortable",
3417
+ enableClipboard = true,
3418
+ onCopy: onCopyOverride,
3419
+ onPaste: onPasteOverride,
3420
+ actionLabels,
3421
+ actionIcons,
3422
+ editorTabs = "off",
3423
+ // Right-pane item view (collection cardinality)
3424
+ itemViews = ["table"],
3425
+ defaultItemView,
3426
+ itemColumns,
3427
+ renderItemList,
3428
+ renderItemCard,
3429
+ renderItemEmpty,
3430
+ collectionRailMode = "siblings",
3431
+ // Deep linking
3432
+ deepLink
2728
3433
  } = props;
2729
3434
  const i18n = { ...DEFAULT_I18N, ...i18nOverride ?? {} };
2730
3435
  const icons = useMemo(() => mergeIcons(iconsOverride), [iconsOverride]);
3436
+ const deepLinkState = useDeepLinkState(deepLink);
3437
+ const lastAppliedDLRef = useRef("");
3438
+ const multiOpenWarnedRef = useRef(false);
3439
+ if (editorTabs === "multi" && !multiOpenWarnedRef.current) {
3440
+ multiOpenWarnedRef.current = true;
3441
+ console.warn(
3442
+ '[RecordsAdminShell] editorTabs="multi" is reserved for a future release and currently behaves like "off". Track in records-admin-shell.md.'
3443
+ );
3444
+ }
2731
3445
  const [presentation, setPresentation] = usePresentationPref({
2732
3446
  appId,
2733
3447
  recordType,
@@ -2738,6 +3452,25 @@ function RecordsAdminShell(props) {
2738
3452
  onTelemetry?.({ type: "presentation.change", recordType, from: presentation, to: next });
2739
3453
  setPresentation(next);
2740
3454
  }, [onTelemetry, recordType, presentation, setPresentation]);
3455
+ const [itemView, setItemView] = useItemViewPref({
3456
+ appId,
3457
+ recordType,
3458
+ options: itemViews,
3459
+ defaultValue: defaultItemView ?? itemViews[0] ?? "table"
3460
+ });
3461
+ const onItemViewChange = useCallback((next) => {
3462
+ onTelemetry?.({
3463
+ type: "item.view.change",
3464
+ recordType,
3465
+ scopeRef: "",
3466
+ // populated below if a scope is active
3467
+ from: itemView,
3468
+ to: next
3469
+ });
3470
+ setItemView(next);
3471
+ deepLinkState.emit({ view: next }, "view");
3472
+ }, [onTelemetry, recordType, itemView, setItemView, deepLinkState]);
3473
+ const [selectedItemId, setSelectedItemId] = useState(null);
2741
3474
  const ctx = useMemo(
2742
3475
  () => ({ SL, collectionId, appId, recordType }),
2743
3476
  [SL, collectionId, appId, recordType]
@@ -2796,6 +3529,15 @@ function RecordsAdminShell(props) {
2796
3529
  }
2797
3530
  }, [contextScope?.batchId]);
2798
3531
  const { dismissed, dismiss, undismiss } = useIntroDismissed(SL, collectionId, appId, recordType);
3532
+ const headerWillRender = useMemo(() => {
3533
+ const headerCustomised = !!title || !!subtitle || !!headerIcon || !!headerActions || showStats || !!statsItems || !!statsTitle || !!statsIcon;
3534
+ return showHeader === true || showHeader !== false && headerCustomised;
3535
+ }, [showHeader, title, subtitle, headerIcon, headerActions, showStats, statsItems, statsTitle, statsIcon]);
3536
+ const resolvedReopenAffordance = useMemo(() => {
3537
+ const requested = intro?.reopenAffordance ?? "header";
3538
+ if (requested === "header" && !headerWillRender) return "footer";
3539
+ return requested;
3540
+ }, [intro?.reopenAffordance, headerWillRender]);
2799
3541
  const productBrowse = useProductBrowse({
2800
3542
  SL,
2801
3543
  collectionId,
@@ -2807,7 +3549,7 @@ function RecordsAdminShell(props) {
2807
3549
  scopeKind: activeScope,
2808
3550
  search,
2809
3551
  filter,
2810
- classify,
3552
+ classify: classify2,
2811
3553
  contextScope,
2812
3554
  enabled: activeScope === "facet" && !probe.isLoading
2813
3555
  });
@@ -2862,19 +3604,82 @@ function RecordsAdminShell(props) {
2862
3604
  }
2863
3605
  return parseRef(buildRef({ productId: selectedProductId }));
2864
3606
  }, [activeScope, selectedFacetRef, selectedProductId, drillTab, selectedVariantId, selectedBatchId]);
3607
+ const isCollection = cardinality === "collection";
3608
+ const editingItemRef = useMemo(() => {
3609
+ if (!isCollection) return null;
3610
+ if (!selectedItemId) return null;
3611
+ const baseRef = editingScope?.raw ?? "";
3612
+ return buildItemRef(baseRef, selectedItemId);
3613
+ }, [isCollection, selectedItemId, editingScope]);
3614
+ const editingTargetScope = useMemo(() => {
3615
+ if (!isCollection) return editingScope;
3616
+ if (!editingItemRef) return null;
3617
+ return parseRef(editingItemRef);
3618
+ }, [isCollection, editingScope, editingItemRef]);
3619
+ const skipNextItemResetRef = useRef(false);
3620
+ useEffect(() => {
3621
+ if (skipNextItemResetRef.current) {
3622
+ skipNextItemResetRef.current = false;
3623
+ return;
3624
+ }
3625
+ setSelectedItemId(null);
3626
+ }, [editingScope?.raw]);
3627
+ const collectionItems = useCollectionItems({
3628
+ ctx,
3629
+ scope: isCollection ? editingScope : null,
3630
+ enabled: isCollection
3631
+ });
3632
+ useEffect(() => {
3633
+ if (!deepLinkState.enabled) return;
3634
+ if (selectedItemId) return;
3635
+ deepLinkState.emit({ scope: editingScope?.raw ?? null, item: null }, "scope");
3636
+ lastAppliedDLRef.current = `${""}|${editingScope?.raw ?? ""}|${itemView}`;
3637
+ }, [deepLinkState.enabled, editingScope?.raw, selectedItemId, itemView]);
3638
+ useEffect(() => {
3639
+ if (!deepLinkState.enabled) return;
3640
+ const { item, scope, view } = deepLinkState.urlState;
3641
+ const sig = `${item ?? ""}|${scope ?? ""}|${view ?? ""}`;
3642
+ if (sig === lastAppliedDLRef.current) return;
3643
+ lastAppliedDLRef.current = sig;
3644
+ if (view && itemViews.includes(view) && view !== itemView) {
3645
+ setItemView(view);
3646
+ }
3647
+ const railRef = item ? item.includes("item:") ? item.slice(0, item.lastIndexOf("item:")).replace(/\/$/, "") : "" : scope ?? "";
3648
+ const itemId = item ? item.includes("item:") ? item.slice(item.lastIndexOf("item:") + "item:".length) : item : null;
3649
+ const parsed = railRef ? parseRef(railRef) : null;
3650
+ if (parsed?.productId) {
3651
+ if (activeScope !== "product") setActiveScope("product");
3652
+ if (selectedProductId !== parsed.productId) setSelectedProductId(parsed.productId);
3653
+ const nextDrill = parsed.batchId ? "batch" : parsed.variantId ? "variant" : "product";
3654
+ if (drillTab !== nextDrill) setDrillTab(nextDrill);
3655
+ if (parsed.variantId && selectedVariantId !== parsed.variantId) setSelectedVariantId(parsed.variantId);
3656
+ if (parsed.batchId && selectedBatchId !== parsed.batchId) setSelectedBatchId(parsed.batchId);
3657
+ } else if (parsed?.facetId) {
3658
+ if (activeScope !== "facet") setActiveScope("facet");
3659
+ if (selectedFacetRef !== railRef) setSelectedFacetRef(railRef);
3660
+ } else {
3661
+ if (selectedFacetRef) setSelectedFacetRef(void 0);
3662
+ }
3663
+ if (itemId !== selectedItemId) {
3664
+ if (railRef && railRef !== editingScope?.raw) {
3665
+ skipNextItemResetRef.current = true;
3666
+ }
3667
+ setSelectedItemId(itemId);
3668
+ }
3669
+ }, [deepLinkState.enabled, deepLinkState.urlState]);
2865
3670
  const supportedForResolution = useMemo(() => requestedScopes, [requestedScopes]);
2866
3671
  const resolved = useResolvedRecord({
2867
3672
  SL,
2868
3673
  appId,
2869
3674
  recordType,
2870
3675
  collectionId,
2871
- productId: editingScope?.productId,
2872
- variantId: editingScope?.variantId,
2873
- batchId: editingScope?.batchId,
2874
- facetId: editingScope?.facetId,
2875
- facetValue: editingScope?.facetValue,
3676
+ productId: editingTargetScope?.productId,
3677
+ variantId: editingTargetScope?.variantId,
3678
+ batchId: editingTargetScope?.batchId,
3679
+ facetId: editingTargetScope?.facetId,
3680
+ facetValue: editingTargetScope?.facetValue,
2876
3681
  supportedScopes: supportedForResolution,
2877
- enabled: !!editingScope
3682
+ enabled: !!editingTargetScope
2878
3683
  });
2879
3684
  const refetchAll = useCallback(() => {
2880
3685
  productBrowse.refetch();
@@ -2882,20 +3687,23 @@ function RecordsAdminShell(props) {
2882
3687
  facetBrowse.refetch();
2883
3688
  variantChildren.refetch();
2884
3689
  batchChildren.refetch();
2885
- }, [productBrowse, recordList, facetBrowse, variantChildren, batchChildren]);
3690
+ if (isCollection) collectionItems.refetch();
3691
+ }, [productBrowse, recordList, facetBrowse, variantChildren, batchChildren, isCollection, collectionItems]);
2886
3692
  const editorCtx = useRecordEditor({
2887
3693
  ctx,
2888
- scope: editingScope ?? parseRef(""),
3694
+ scope: editingTargetScope ?? parseRef(""),
2889
3695
  resolved: { data: resolved.data, source: resolved.source, sourceRef: resolved.sourceRef, parentValue: resolved.parentValue },
2890
3696
  defaultData,
2891
3697
  reseed: dirtyStrategy === "keep" ? "preserve-dirty" : "always",
2892
3698
  onSaved: () => {
2893
- onTelemetry?.({ type: "record.save", recordType, ref: editingScope?.raw ?? "", isCreate: resolved.source !== "self" });
3699
+ onTelemetry?.({ type: "record.save", recordType, ref: editingTargetScope?.raw ?? "", isCreate: resolved.source !== "self" });
2894
3700
  refetchAll();
2895
3701
  },
2896
3702
  onDeleted: () => {
2897
- onTelemetry?.({ type: "record.delete", recordType, ref: editingScope?.raw ?? "" });
2898
- if (activeScope === "facet") {
3703
+ onTelemetry?.({ type: "record.delete", recordType, ref: editingTargetScope?.raw ?? "" });
3704
+ if (isCollection && selectedItemId) {
3705
+ setSelectedItemId(null);
3706
+ } else if (activeScope === "facet") {
2899
3707
  setSelectedFacetRef(void 0);
2900
3708
  } else if (drillTab === "variant") {
2901
3709
  setSelectedVariantId(void 0);
@@ -2915,6 +3723,12 @@ function RecordsAdminShell(props) {
2915
3723
  disableParentMessage: dirtyStrategy === "keep"
2916
3724
  });
2917
3725
  const dirtyConfirm = useConfirmDialog();
3726
+ const pasteConfirm = usePasteConfirm();
3727
+ const clipboard = useRecordClipboard({
3728
+ appId,
3729
+ recordType: recordType ?? "__default"
3730
+ });
3731
+ const [clipboardNotice, setClipboardNotice] = useState(null);
2918
3732
  const { runWithGuard } = useDirtyNavigation({
2919
3733
  strategy: dirtyStrategy,
2920
3734
  isDirty: editorCtx.isDirty,
@@ -2991,15 +3805,259 @@ function RecordsAdminShell(props) {
2991
3805
  }
2992
3806
  return void 0;
2993
3807
  }, [activeScope, editingScope, selectedProductId, productBrowse.items]);
3808
+ const copyCurrent = useCallback(() => {
3809
+ if (!enableClipboard || !editingScope) return;
3810
+ const sourceValue = onCopyOverride ? onCopyOverride({ value: editorCtx.value, scope: editingScope }) : cloneValue(editorCtx.value);
3811
+ clipboard.set({
3812
+ value: sourceValue,
3813
+ sourceScope: editingScope.kind,
3814
+ sourceRef: editingScope.raw,
3815
+ sourceLabel: editorHeaderLabel
3816
+ });
3817
+ onTelemetry?.({ type: "clipboard.copy", recordType, sourceRef: editingScope.raw });
3818
+ setClipboardNotice({
3819
+ message: i18n.copyToast.replace("{name}", editorHeaderLabel ?? editingScope.raw),
3820
+ variant: "copy"
3821
+ });
3822
+ }, [
3823
+ enableClipboard,
3824
+ editingScope,
3825
+ onCopyOverride,
3826
+ editorCtx.value,
3827
+ clipboard,
3828
+ editorHeaderLabel,
3829
+ onTelemetry,
3830
+ recordType,
3831
+ i18n.copyToast
3832
+ ]);
3833
+ const pasteCurrent = useCallback(async () => {
3834
+ if (!enableClipboard || !editingScope || !clipboard.entry) return;
3835
+ const compat = checkPasteCompatibility(
3836
+ { kind: clipboard.entry.sourceScope, raw: clipboard.entry.sourceRef },
3837
+ editingScope
3838
+ );
3839
+ if (compat.status === "denied") {
3840
+ setClipboardNotice({ message: compat.reason ?? "Paste not allowed here", variant: "paste" });
3841
+ return;
3842
+ }
3843
+ if (compat.status === "warn") {
3844
+ const ok = await pasteConfirm.confirm({
3845
+ title: i18n.pasteWarnTitle,
3846
+ body: compat.reason ?? "",
3847
+ confirmLabel: i18n.pasteWarnContinue,
3848
+ cancelLabel: i18n.pasteConfirmCancel
3849
+ });
3850
+ if (!ok) return;
3851
+ }
3852
+ const willReplace = resolved.source === "self";
3853
+ if (willReplace) {
3854
+ const ok = await pasteConfirm.confirm({
3855
+ title: i18n.pasteConfirmTitle,
3856
+ body: i18n.pasteConfirmBody.replace(
3857
+ "{destination}",
3858
+ editorHeaderLabel ?? editingScope.raw
3859
+ ),
3860
+ confirmLabel: i18n.pasteConfirmReplace,
3861
+ cancelLabel: i18n.pasteConfirmCancel
3862
+ });
3863
+ if (!ok) return;
3864
+ }
3865
+ const sourceParsed = { kind: clipboard.entry.sourceScope, raw: clipboard.entry.sourceRef };
3866
+ const transformed = onPasteOverride ? onPasteOverride(
3867
+ { value: clipboard.entry.value, sourceScope: sourceParsed },
3868
+ { scope: editingScope, currentValue: editorCtx.value ?? null }
3869
+ ) : cloneValue(clipboard.entry.value);
3870
+ if (transformed === null) return;
3871
+ editorCtx.onChange(transformed);
3872
+ onTelemetry?.({
3873
+ type: "clipboard.paste",
3874
+ recordType,
3875
+ sourceRef: clipboard.entry.sourceRef,
3876
+ destinationRef: editingScope.raw,
3877
+ replaced: willReplace
3878
+ });
3879
+ setClipboardNotice({
3880
+ message: i18n.pasteToast.replace("{name}", clipboard.entry.sourceLabel ?? clipboard.entry.sourceRef),
3881
+ variant: "paste"
3882
+ });
3883
+ }, [
3884
+ enableClipboard,
3885
+ editingScope,
3886
+ clipboard.entry,
3887
+ pasteConfirm,
3888
+ resolved.source,
3889
+ onPasteOverride,
3890
+ editorCtx,
3891
+ onTelemetry,
3892
+ recordType,
3893
+ editorHeaderLabel,
3894
+ i18n.pasteWarnTitle,
3895
+ i18n.pasteWarnContinue,
3896
+ i18n.pasteConfirmCancel,
3897
+ i18n.pasteConfirmTitle,
3898
+ i18n.pasteConfirmBody,
3899
+ i18n.pasteConfirmReplace,
3900
+ i18n.pasteToast
3901
+ ]);
3902
+ const editorPasteCompat = useMemo(() => {
3903
+ if (!enableClipboard || !clipboard.entry || !editingScope) return null;
3904
+ if (clipboard.entry.sourceRef === editingScope.raw) return { status: "denied" };
3905
+ return checkPasteCompatibility(
3906
+ { kind: clipboard.entry.sourceScope, raw: clipboard.entry.sourceRef },
3907
+ editingScope
3908
+ );
3909
+ }, [enableClipboard, clipboard.entry, editingScope]);
3910
+ const editorClipboard = enableClipboard && editingScope ? {
3911
+ onCopy: copyCurrent,
3912
+ onPaste: () => {
3913
+ void pasteCurrent();
3914
+ },
3915
+ canCopy: true,
3916
+ canPaste: !!clipboard.entry && editorPasteCompat?.status !== "denied",
3917
+ pasteSourceLabel: clipboard.entry?.sourceLabel,
3918
+ pasteWillReplace: resolved.source === "self" && !!clipboard.entry
3919
+ } : void 0;
3920
+ const [pendingPasteRef, setPendingPasteRef] = useState(null);
3921
+ useEffect(() => {
3922
+ if (!pendingPasteRef) return;
3923
+ if (!editingScope || editingScope.raw !== pendingPasteRef) return;
3924
+ const t = window.setTimeout(() => {
3925
+ setPendingPasteRef(null);
3926
+ void pasteCurrent();
3927
+ }, 0);
3928
+ return () => window.clearTimeout(t);
3929
+ }, [pendingPasteRef, editingScope, pasteCurrent]);
3930
+ const rowClipboard = enableClipboard ? (record) => {
3931
+ const summaryHasData = record.data != null;
3932
+ const sourceParsed = record.scope;
3933
+ const compat = clipboard.entry ? checkPasteCompatibility(
3934
+ { kind: clipboard.entry.sourceScope, raw: clipboard.entry.sourceRef },
3935
+ sourceParsed
3936
+ ) : null;
3937
+ const sameRef = clipboard.entry?.sourceRef === record.ref;
3938
+ return {
3939
+ onCopy: summaryHasData ? () => {
3940
+ const value = onCopyOverride ? onCopyOverride({ value: record.data, scope: sourceParsed }) : cloneValue(record.data);
3941
+ clipboard.set({
3942
+ value,
3943
+ sourceScope: sourceParsed.kind,
3944
+ sourceRef: record.ref,
3945
+ sourceLabel: record.label
3946
+ });
3947
+ onTelemetry?.({ type: "clipboard.copy", recordType, sourceRef: record.ref });
3948
+ setClipboardNotice({
3949
+ message: i18n.copyToast.replace("{name}", record.label),
3950
+ variant: "copy"
3951
+ });
3952
+ } : void 0,
3953
+ onPaste: () => {
3954
+ onLeftSelectRef.current?.(record);
3955
+ setPendingPasteRef(record.ref);
3956
+ },
3957
+ canPaste: !!clipboard.entry && !sameRef && compat?.status !== "denied",
3958
+ pasteWillReplace: record.status === "configured",
3959
+ clipboardSourceLabel: clipboard.entry?.sourceLabel
3960
+ };
3961
+ } : void 0;
3962
+ const onLeftSelectRef = useRef(null);
3963
+ const baseScopeRef = editingScope?.raw ?? "";
3964
+ const itemNounLabel = itemNoun || "item";
3965
+ const buildItemUrlValue = useCallback((id) => {
3966
+ return baseScopeRef ? `${baseScopeRef}/item:${id}` : id;
3967
+ }, [baseScopeRef]);
3968
+ const onItemOpen = useCallback((itemId) => {
3969
+ if (!isCollection) return;
3970
+ void runWithGuard(() => {
3971
+ setSelectedItemId(itemId);
3972
+ onTelemetry?.({ type: "item.open", recordType, scopeRef: baseScopeRef, itemId });
3973
+ deepLinkState.emit({ item: buildItemUrlValue(itemId) }, "item.open");
3974
+ });
3975
+ }, [isCollection, runWithGuard, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
3976
+ const onItemCreate = useCallback(() => {
3977
+ if (!isCollection) return;
3978
+ void runWithGuard(() => {
3979
+ const id = generateItemId ? generateItemId() : defaultItemId();
3980
+ setSelectedItemId(id);
3981
+ onTelemetry?.({ type: "item.create", recordType, scopeRef: baseScopeRef });
3982
+ deepLinkState.emit({ item: buildItemUrlValue(id) }, "item.open");
3983
+ });
3984
+ }, [isCollection, runWithGuard, generateItemId, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
3985
+ const onItemDelete = useCallback(async (itemId) => {
3986
+ if (!isCollection) return;
3987
+ const ref = buildItemRef(baseScopeRef, itemId);
3988
+ if (onBeforeDelete) {
3989
+ const ok = await onBeforeDelete(parseRef(ref));
3990
+ if (!ok) return;
3991
+ }
3992
+ try {
3993
+ const { deleteRecord: deleteRecord2 } = await import('../../records-66QWR67J.js');
3994
+ await deleteRecord2(ctx, ref);
3995
+ onTelemetry?.({ type: "item.delete", recordType, scopeRef: baseScopeRef, itemId });
3996
+ if (selectedItemId === itemId) setSelectedItemId(null);
3997
+ if (selectedItemId === itemId) deepLinkState.emit({ item: null }, "item.close");
3998
+ collectionItems.refetch();
3999
+ } catch (err) {
4000
+ console.error("[RecordsAdminShell] item delete failed", err);
4001
+ }
4002
+ }, [
4003
+ isCollection,
4004
+ baseScopeRef,
4005
+ ctx,
4006
+ onBeforeDelete,
4007
+ onTelemetry,
4008
+ recordType,
4009
+ selectedItemId,
4010
+ collectionItems,
4011
+ deepLinkState
4012
+ ]);
4013
+ const itemViewCtx = useMemo(() => ({
4014
+ onOpen: onItemOpen,
4015
+ onCreate: onItemCreate,
4016
+ onDelete: (id) => {
4017
+ void onItemDelete(id);
4018
+ },
4019
+ scope: editingScope ?? parseRef(""),
4020
+ selectedId: selectedItemId ?? void 0,
4021
+ isLoading: collectionItems.isLoading
4022
+ }), [onItemOpen, onItemCreate, onItemDelete, editingScope, selectedItemId, collectionItems.isLoading]);
4023
+ const itemPosition = useMemo(() => {
4024
+ if (!isCollection || !selectedItemId) return null;
4025
+ const idx = collectionItems.items.findIndex((it) => it.itemId === selectedItemId);
4026
+ if (idx < 0) return null;
4027
+ return { index: idx, total: collectionItems.items.length };
4028
+ }, [isCollection, selectedItemId, collectionItems.items]);
4029
+ const onItemBack = useCallback(() => {
4030
+ void runWithGuard(() => {
4031
+ setSelectedItemId(null);
4032
+ deepLinkState.emit({ item: null }, "item.close");
4033
+ });
4034
+ }, [runWithGuard, deepLinkState]);
4035
+ const stepToItem = useCallback((id) => {
4036
+ void runWithGuard(() => {
4037
+ setSelectedItemId(id);
4038
+ onTelemetry?.({ type: "item.open", recordType, scopeRef: baseScopeRef, itemId: id });
4039
+ deepLinkState.emit({ item: buildItemUrlValue(id) }, "item.step");
4040
+ });
4041
+ }, [runWithGuard, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
4042
+ const onItemPrev = useCallback(() => {
4043
+ if (!itemPosition || itemPosition.index <= 0) return;
4044
+ const next = collectionItems.items[itemPosition.index - 1];
4045
+ if (next?.itemId) stepToItem(next.itemId);
4046
+ }, [itemPosition, collectionItems.items, stepToItem]);
4047
+ const onItemNext = useCallback(() => {
4048
+ if (!itemPosition || itemPosition.index >= itemPosition.total - 1) return;
4049
+ const next = collectionItems.items[itemPosition.index + 1];
4050
+ if (next?.itemId) stepToItem(next.itemId);
4051
+ }, [itemPosition, collectionItems.items, stepToItem]);
2994
4052
  const renderEditorWithPreview = () => {
2995
- if (!editingScope) return null;
4053
+ if (!editingTargetScope) return null;
2996
4054
  const previewBody = renderPreview && effectivePreviewScope ? renderPreview({ resolved: editorCtx.value, previewScope: effectivePreviewScope }) : null;
2997
4055
  const scopePicker = previewScopePicker && effectivePreviewScope ? /* @__PURE__ */ jsx(
2998
4056
  PreviewScopePicker,
2999
4057
  {
3000
4058
  SL,
3001
4059
  collectionId,
3002
- editingScope,
4060
+ editingScope: editingTargetScope,
3003
4061
  value: effectivePreviewScope,
3004
4062
  onChange: setPreviewScope,
3005
4063
  showVariants: drillVariantsAllowed,
@@ -3007,6 +4065,20 @@ function RecordsAdminShell(props) {
3007
4065
  i18n: { previewAs: i18n.previewAs, previewAsDefault: i18n.previewAsDefault }
3008
4066
  }
3009
4067
  ) : null;
4068
+ const itemNav = isCollection && selectedItemId && itemPosition ? /* @__PURE__ */ jsx(
4069
+ EditorItemNav,
4070
+ {
4071
+ label: editorHeaderLabel,
4072
+ position: itemPosition.index + 1,
4073
+ total: itemPosition.total,
4074
+ onBack: onItemBack,
4075
+ onPrev: onItemPrev,
4076
+ onNext: onItemNext,
4077
+ canPrev: itemPosition.index > 0,
4078
+ canNext: itemPosition.index < itemPosition.total - 1,
4079
+ i18n
4080
+ }
4081
+ ) : null;
3010
4082
  const baseEditor = (extraFooter, inlinePreviewBody) => /* @__PURE__ */ jsx(
3011
4083
  RecordEditor,
3012
4084
  {
@@ -3015,71 +4087,86 @@ function RecordsAdminShell(props) {
3015
4087
  bulkActions: { ...csvBulk, i18n },
3016
4088
  preview: inlinePreviewBody,
3017
4089
  footerExtra: extraFooter,
3018
- onBeforeDelete: onBeforeDelete && editingScope ? () => onBeforeDelete(editingScope) : void 0,
4090
+ onBeforeDelete: onBeforeDelete && editingTargetScope ? () => onBeforeDelete(editingTargetScope) : void 0,
3019
4091
  headerLabel: editorHeaderLabel,
3020
4092
  headerSubtitle: editorHeaderSubtitle,
3021
4093
  headerMeta: editorHeaderMeta,
4094
+ clipboard: editorClipboard,
4095
+ actionLabels,
4096
+ actionIcons,
3022
4097
  children: renderEditor(editorCtx)
3023
4098
  }
3024
4099
  );
3025
- if (!previewBody) return baseEditor();
4100
+ const withNav = (node) => itemNav ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full min-h-0", children: [
4101
+ itemNav,
4102
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: node })
4103
+ ] }) : node;
4104
+ if (!previewBody) return withNav(baseEditor());
3026
4105
  if (previewMode === "inline") {
3027
- return baseEditor(
4106
+ return withNav(baseEditor(
3028
4107
  void 0,
3029
4108
  /* @__PURE__ */ jsx(InlinePreview, { label: i18n.preview, scopePicker, children: previewBody })
3030
- );
4109
+ ));
3031
4110
  }
3032
4111
  if (previewMode === "side") {
3033
4112
  if (!sidePreviewOpen) {
3034
- return /* @__PURE__ */ jsx("div", { className: "relative h-full", children: baseEditor(
4113
+ return withNav(
4114
+ /* @__PURE__ */ jsx("div", { className: "relative h-full", children: baseEditor(
4115
+ /* @__PURE__ */ jsx(
4116
+ PreviewToggleButton,
4117
+ {
4118
+ onClick: () => setSidePreviewOpen(true),
4119
+ label: i18n.openPreview
4120
+ }
4121
+ )
4122
+ ) })
4123
+ );
4124
+ }
4125
+ return withNav(
4126
+ /* @__PURE__ */ jsxs("div", { className: "grid h-full", style: { gridTemplateColumns: "minmax(0, 1fr) minmax(280px, 420px)" }, children: [
4127
+ /* @__PURE__ */ jsx("div", { className: "overflow-hidden", children: baseEditor() }),
3035
4128
  /* @__PURE__ */ jsx(
3036
- PreviewToggleButton,
4129
+ SidePreview,
3037
4130
  {
3038
- onClick: () => setSidePreviewOpen(true),
3039
- label: i18n.openPreview
4131
+ label: i18n.preview,
4132
+ scopePicker,
4133
+ onClose: () => setSidePreviewOpen(false),
4134
+ children: previewBody
3040
4135
  }
3041
4136
  )
3042
- ) });
3043
- }
3044
- return /* @__PURE__ */ jsxs("div", { className: "grid h-full", style: { gridTemplateColumns: "minmax(0, 1fr) minmax(280px, 420px)" }, children: [
3045
- /* @__PURE__ */ jsx("div", { className: "overflow-hidden", children: baseEditor() }),
4137
+ ] })
4138
+ );
4139
+ }
4140
+ if (previewMode === "tab") {
4141
+ return withNav(
3046
4142
  /* @__PURE__ */ jsx(
3047
- SidePreview,
4143
+ TabbedPreview,
3048
4144
  {
3049
- label: i18n.preview,
4145
+ editor: baseEditor(),
4146
+ preview: previewBody,
3050
4147
  scopePicker,
3051
- onClose: () => setSidePreviewOpen(false),
3052
- children: previewBody
4148
+ i18n: { editor: i18n.editor, preview: i18n.preview }
3053
4149
  }
3054
4150
  )
3055
- ] });
3056
- }
3057
- if (previewMode === "tab") {
3058
- return /* @__PURE__ */ jsx(
3059
- TabbedPreview,
3060
- {
3061
- editor: baseEditor(),
3062
- preview: previewBody,
3063
- scopePicker,
3064
- i18n: { editor: i18n.editor, preview: i18n.preview }
3065
- }
3066
4151
  );
3067
4152
  }
3068
- return /* @__PURE__ */ jsxs("div", { className: "relative h-full", children: [
3069
- baseEditor(
3070
- /* @__PURE__ */ jsx(PreviewToggleButton, { onClick: () => setDrawerOpen(true), label: i18n.openPreview })
3071
- ),
3072
- /* @__PURE__ */ jsx(
3073
- DrawerPreview,
3074
- {
3075
- open: drawerOpen,
3076
- onClose: () => setDrawerOpen(false),
3077
- label: i18n.preview,
3078
- scopePicker,
3079
- children: previewBody
3080
- }
3081
- )
3082
- ] });
4153
+ return withNav(
4154
+ /* @__PURE__ */ jsxs("div", { className: "relative h-full", children: [
4155
+ baseEditor(
4156
+ /* @__PURE__ */ jsx(PreviewToggleButton, { onClick: () => setDrawerOpen(true), label: i18n.openPreview })
4157
+ ),
4158
+ /* @__PURE__ */ jsx(
4159
+ DrawerPreview,
4160
+ {
4161
+ open: drawerOpen,
4162
+ onClose: () => setDrawerOpen(false),
4163
+ label: i18n.preview,
4164
+ scopePicker,
4165
+ children: previewBody
4166
+ }
4167
+ )
4168
+ ] })
4169
+ );
3083
4170
  };
3084
4171
  const isProductTab = activeScope === "product";
3085
4172
  const productPinned = !!contextScope?.productId;
@@ -3125,6 +4212,7 @@ function RecordsAdminShell(props) {
3125
4212
  }
3126
4213
  });
3127
4214
  };
4215
+ onLeftSelectRef.current = onLeftSelect;
3128
4216
  return /* @__PURE__ */ jsxs(
3129
4217
  "div",
3130
4218
  {
@@ -3132,6 +4220,15 @@ function RecordsAdminShell(props) {
3132
4220
  "data-density": density,
3133
4221
  children: [
3134
4222
  dirtyConfirm.dialog,
4223
+ pasteConfirm.dialog,
4224
+ clipboardNotice && /* @__PURE__ */ jsx(
4225
+ ClipboardToast,
4226
+ {
4227
+ message: clipboardNotice.message,
4228
+ variant: clipboardNotice.variant,
4229
+ onDismiss: () => setClipboardNotice(null)
4230
+ }
4231
+ ),
3135
4232
  /* @__PURE__ */ jsxs("div", { className: "px-4 pt-4 space-y-3", children: [
3136
4233
  intro && !dismissed && /* @__PURE__ */ jsx(
3137
4234
  IntroCard,
@@ -3145,9 +4242,9 @@ function RecordsAdminShell(props) {
3145
4242
  }
3146
4243
  ),
3147
4244
  (() => {
3148
- const headerCustomised = !!title || !!subtitle || !!headerIcon || !!headerActions || showStats || !!statsItems || !!statsTitle || !!statsIcon;
3149
- const renderHeader = showHeader === true || showHeader !== false && headerCustomised;
3150
- if (!renderHeader) return null;
4245
+ if (!headerWillRender) return null;
4246
+ const showHeaderReopen = !!intro && dismissed && resolvedReopenAffordance === "header";
4247
+ const reopenLabel = intro?.reopenLabel ?? `How ${label.toLowerCase()} works`;
3151
4248
  return /* @__PURE__ */ jsx(
3152
4249
  ShellHeader,
3153
4250
  {
@@ -3165,18 +4262,32 @@ function RecordsAdminShell(props) {
3165
4262
  },
3166
4263
  statsItems,
3167
4264
  statsTitle,
3168
- statsIcon
4265
+ statsIcon,
4266
+ trailingSlot: showHeaderReopen ? /* @__PURE__ */ jsx(
4267
+ "button",
4268
+ {
4269
+ type: "button",
4270
+ onClick: undismiss,
4271
+ className: "ra-btn",
4272
+ "data-variant": "ghost",
4273
+ "aria-label": reopenLabel,
4274
+ title: reopenLabel,
4275
+ style: { width: "2rem", height: "2rem", padding: 0, justifyContent: "center" },
4276
+ children: /* @__PURE__ */ jsx(HelpCircle, { className: "w-4 h-4" })
4277
+ }
4278
+ ) : void 0
3169
4279
  }
3170
4280
  );
3171
4281
  })(),
3172
- /* @__PURE__ */ jsx(
4282
+ resolvedReopenAffordance === "inline" || resolvedReopenAffordance === "footer" ? /* @__PURE__ */ jsx(
3173
4283
  UtilityRow,
3174
4284
  {
3175
- label,
4285
+ label: intro?.reopenLabel ? "" : label,
4286
+ customLabel: intro?.reopenLabel,
3176
4287
  introHidden: dismissed && !!intro,
3177
4288
  onShowIntro: undismiss
3178
4289
  }
3179
- ),
4290
+ ) : null,
3180
4291
  editorCtx.isDirty && /* @__PURE__ */ jsx(
3181
4292
  UnsavedBanner,
3182
4293
  {
@@ -3189,8 +4300,10 @@ function RecordsAdminShell(props) {
3189
4300
  });
3190
4301
  },
3191
4302
  onDiscard: editorCtx.reset,
3192
- saveLabel: i18n.save,
3193
- discardLabel: i18n.discard,
4303
+ saveLabel: actionLabels?.save ?? i18n.save,
4304
+ discardLabel: actionLabels?.discard ?? i18n.discard,
4305
+ SaveIcon: actionIcons?.save,
4306
+ DiscardIcon: actionIcons?.discard,
3194
4307
  savingLabel: i18n.saving,
3195
4308
  errorLabel: i18n.saveError,
3196
4309
  bodyTemplate: i18n.unsavedBannerBody
@@ -3203,7 +4316,18 @@ function RecordsAdminShell(props) {
3203
4316
  className: "flex-1 grid border-t overflow-hidden",
3204
4317
  style: { gridTemplateColumns: "minmax(260px, 320px) 1fr", borderColor: "hsl(var(--ra-border))", marginTop: "0.75rem" },
3205
4318
  children: [
3206
- /* @__PURE__ */ jsxs("aside", { className: "border-r overflow-hidden flex flex-col", style: { borderColor: "hsl(var(--ra-border))", background: "hsl(var(--ra-surface))" }, children: [
4319
+ /* @__PURE__ */ jsx("aside", { className: "border-r overflow-hidden flex flex-col", style: { borderColor: "hsl(var(--ra-border))", background: "hsl(var(--ra-surface))" }, children: isCollection && selectedItemId && collectionRailMode === "siblings" ? /* @__PURE__ */ jsx(
4320
+ SiblingRail,
4321
+ {
4322
+ items: collectionItems.items,
4323
+ selectedItemId,
4324
+ isLoading: collectionItems.isLoading,
4325
+ error: collectionItems.error,
4326
+ onBack: onItemBack,
4327
+ onSelect: onItemOpen,
4328
+ i18n
4329
+ }
4330
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
3207
4331
  /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
3208
4332
  ScopeTabs,
3209
4333
  {
@@ -3258,27 +4382,6 @@ function RecordsAdminShell(props) {
3258
4382
  hideZero: ["partial"],
3259
4383
  i18n
3260
4384
  }
3261
- ),
3262
- cardinality === "collection" && !isProductTab && editingScope && /* @__PURE__ */ jsxs(
3263
- "button",
3264
- {
3265
- type: "button",
3266
- onClick: () => {
3267
- void runWithGuard(() => {
3268
- const id = generateItemId ? generateItemId() : defaultItemId();
3269
- const baseRef = editingScope.raw;
3270
- const itemRef = baseRef ? `${baseRef}/item:${id}` : `item:${id}`;
3271
- setSelectedFacetRef(itemRef);
3272
- onTelemetry?.({ type: "item.create", recordType, scopeRef: baseRef });
3273
- });
3274
- },
3275
- className: "w-full inline-flex items-center justify-center gap-1.5 text-xs py-1.5 rounded-md border transition-colors hover:bg-[hsl(var(--ra-muted))]",
3276
- style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
3277
- children: [
3278
- /* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5" }),
3279
- i18n.newItem || `New ${itemNoun}`
3280
- ]
3281
- }
3282
4385
  )
3283
4386
  ] }),
3284
4387
  /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
@@ -3302,8 +4405,8 @@ function RecordsAdminShell(props) {
3302
4405
  dirtyRef: editorCtx.isDirty ? editingScope?.raw : void 0,
3303
4406
  presentation: effectivePresentation,
3304
4407
  renderListRow,
3305
- renderCard,
3306
- groupBy: effectiveGroupBy
4408
+ groupBy: effectiveGroupBy,
4409
+ rowClipboard
3307
4410
  }
3308
4411
  ),
3309
4412
  isProductTab && !productPinned && productBrowse.hasNextPage && /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
@@ -3321,16 +4424,35 @@ function RecordsAdminShell(props) {
3321
4424
  ) })
3322
4425
  ] })
3323
4426
  ] })
3324
- ] }),
4427
+ ] }) }),
3325
4428
  /* @__PURE__ */ jsxs("main", { className: "overflow-hidden", children: [
3326
- !editingScope && activeScope === "product" && !selectedProductId && /* @__PURE__ */ jsx(EmptyState, { title: i18n.emptyTitle, body: i18n.emptyBody }),
3327
- !editingScope && activeScope === "facet" && /* @__PURE__ */ jsx(EmptyState, { title: i18n.emptyTitle, body: i18n.emptyBody }),
3328
- isProductTab && selectedProductId && /* @__PURE__ */ jsx(
4429
+ isCollection && editingScope && !selectedItemId && /* @__PURE__ */ jsx(
4430
+ ItemListView,
4431
+ {
4432
+ items: collectionItems.items,
4433
+ isLoading: collectionItems.isLoading,
4434
+ error: collectionItems.error,
4435
+ ctx: itemViewCtx,
4436
+ itemNoun: itemNounLabel,
4437
+ view: itemView,
4438
+ views: itemViews,
4439
+ onViewChange: onItemViewChange,
4440
+ renderItemList,
4441
+ renderItemCard,
4442
+ renderItemEmpty,
4443
+ itemColumns,
4444
+ i18n
4445
+ }
4446
+ ),
4447
+ !isCollection && !editingScope && activeScope === "product" && !selectedProductId && /* @__PURE__ */ jsx(EmptyState, { title: i18n.emptyTitle, body: i18n.emptyBody }),
4448
+ !isCollection && !editingScope && activeScope === "facet" && /* @__PURE__ */ jsx(EmptyState, { title: i18n.emptyTitle, body: i18n.emptyBody }),
4449
+ isProductTab && selectedProductId && (!isCollection || selectedItemId) && /* @__PURE__ */ jsx(
3329
4450
  ProductDrillDown,
3330
4451
  {
3331
4452
  productLabel: productBrowse.items.find((p) => p.id === selectedProductId)?.name ?? selectedProductId,
3332
4453
  showVariants: drillVariantsAllowed,
3333
4454
  showBatches: drillBatchesAllowed,
4455
+ hideSingleTab: editorTabs === "off" || editorTabs === "multi",
3334
4456
  active: drillTab,
3335
4457
  onChange: (t) => {
3336
4458
  void runWithGuard(() => {
@@ -3352,7 +4474,7 @@ function RecordsAdminShell(props) {
3352
4474
  batches: batchChildren.items,
3353
4475
  variantsLoading: variantChildren.isLoading,
3354
4476
  batchesLoading: batchChildren.isLoading,
3355
- children: editingScope ? renderEditorWithPreview() : /* @__PURE__ */ jsx(
4477
+ children: editingTargetScope ? renderEditorWithPreview() : /* @__PURE__ */ jsx(
3356
4478
  EmptyState,
3357
4479
  {
3358
4480
  title: drillTab === "variant" ? "Pick a variant" : "Pick a batch",
@@ -3361,7 +4483,7 @@ function RecordsAdminShell(props) {
3361
4483
  )
3362
4484
  }
3363
4485
  ),
3364
- !isProductTab && editingScope && renderEditorWithPreview()
4486
+ !isProductTab && editingTargetScope && (!isCollection || selectedItemId) && renderEditorWithPreview()
3365
4487
  ] })
3366
4488
  ]
3367
4489
  }
@@ -3433,6 +4555,87 @@ var RecordBrowser = ({
3433
4555
  ] })
3434
4556
  ] });
3435
4557
  };
4558
+ var initials2 = (s) => s.split(/\s+/).filter(Boolean).slice(0, 2).map((p) => p[0]?.toUpperCase() ?? "").join("") || "?";
4559
+ var DefaultRecordCard = ({ record, ctx, variant = "grid" }) => {
4560
+ const { selected, onSelect, isDirty, onCopy, onPaste, canPaste, pasteWillReplace, clipboardSourceLabel } = ctx;
4561
+ const aspect = variant === "gallery" ? "aspect-video" : "aspect-square";
4562
+ return /* @__PURE__ */ jsxs(
4563
+ "button",
4564
+ {
4565
+ type: "button",
4566
+ onClick: onSelect,
4567
+ className: cn(
4568
+ "group flex flex-col text-left rounded-md overflow-hidden border ra-card-hover",
4569
+ selected && "ring-2"
4570
+ ),
4571
+ style: {
4572
+ background: "hsl(var(--ra-surface))",
4573
+ borderColor: selected ? "var(--ra-row-active-bd)" : "hsl(var(--ra-border))",
4574
+ boxShadow: selected ? `0 0 0 2px hsl(var(--ra-accent) / 0.45), var(--ra-card-shadow)` : "var(--ra-card-shadow)"
4575
+ },
4576
+ children: [
4577
+ /* @__PURE__ */ jsxs(
4578
+ "div",
4579
+ {
4580
+ className: cn(aspect, "relative w-full flex items-center justify-center overflow-hidden"),
4581
+ style: { background: "hsl(var(--ra-muted))" },
4582
+ children: [
4583
+ record.thumbnail ? /* @__PURE__ */ jsx(
4584
+ "img",
4585
+ {
4586
+ src: record.thumbnail,
4587
+ alt: "",
4588
+ loading: "lazy",
4589
+ className: "w-full h-full object-cover"
4590
+ }
4591
+ ) : /* @__PURE__ */ jsx(
4592
+ "span",
4593
+ {
4594
+ className: "text-2xl ra-display",
4595
+ style: { color: "hsl(var(--ra-muted-text))" },
4596
+ children: initials2(record.label)
4597
+ }
4598
+ ),
4599
+ /* @__PURE__ */ jsx("div", { className: "absolute top-1.5 left-1.5", children: /* @__PURE__ */ jsx(StatusDot, { status: record.status }) }),
4600
+ isDirty && /* @__PURE__ */ jsx(
4601
+ "span",
4602
+ {
4603
+ title: "Unsaved changes",
4604
+ "aria-label": "Unsaved changes",
4605
+ className: "ra-status-dot ra-status-shared absolute top-1.5 right-1.5"
4606
+ }
4607
+ )
4608
+ ]
4609
+ }
4610
+ ),
4611
+ /* @__PURE__ */ jsxs("div", { className: "p-2.5 min-w-0", children: [
4612
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-1.5 min-w-0", children: [
4613
+ /* @__PURE__ */ jsx("div", { className: "ra-row-title flex-1 min-w-0", children: record.label }),
4614
+ (onCopy || onPaste) && /* @__PURE__ */ jsx(
4615
+ RowContextMenu,
4616
+ {
4617
+ onCopy,
4618
+ onPaste,
4619
+ canPaste,
4620
+ pasteWillReplace,
4621
+ pasteSourceLabel: clipboardSourceLabel,
4622
+ i18n: {
4623
+ copy: DEFAULT_I18N.copy,
4624
+ paste: DEFAULT_I18N.paste,
4625
+ pasteFrom: DEFAULT_I18N.pasteFrom,
4626
+ pasteReplace: DEFAULT_I18N.pasteReplace,
4627
+ clipboardEmpty: DEFAULT_I18N.clipboardEmpty
4628
+ }
4629
+ }
4630
+ )
4631
+ ] }),
4632
+ variant === "gallery" && record.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: record.subtitle }),
4633
+ record.badges && record.badges.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex gap-1 mt-1.5 flex-wrap", children: record.badges.slice(0, 3).map((b, i) => /* @__PURE__ */ jsx("span", { className: "ra-chip", "data-tone": "muted", children: b.label }, `${b.label}-${i}`)) })
4634
+ ] })
4635
+ ]
4636
+ }
4637
+ );
4638
+ };
3436
4639
  var Ctx = createContext({});
3437
4640
  var InheritanceProvider = ({
3438
4641
  parentValue,
@@ -3763,6 +4966,6 @@ function useMergedRecord(args) {
3763
4966
  };
3764
4967
  }
3765
4968
 
3766
- export { ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_I18N, DEFAULT_ICONS, DefaultRecordCard, DefaultRecordRow, DeleteButton, DrawerPreview, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SidePreview, StatusDot, StatusFilterPills, TabbedPreview, UtilityRow, VariantList, buildRef, bulkDelete, bulkUpsert, deleteRecord, downloadBlob, exportCsv, getRecordByRef, importCsv, listRecords, matchRecords, mergeIcons, parseRef, parsedRefToScope, parsedRefToTarget, pickHeaderIcon, resolutionChain, resolveRecord, restoreRecord, scopesEqual, upsertRecord, useCollectedRecords, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeProbe, useUnsavedGuard };
4969
+ 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, TabbedPreview, UtilityRow, VariantList, buildItemRef, buildRef, checkPasteCompatibility, cloneValue, createDefaultDeepLinkAdapter, downloadBlob, exportCsv, importCsv, mergeIcons, parseRef, pickHeaderIcon, resolutionChain, resolveRecord, splitItemRef, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeProbe, useUnsavedGuard };
3767
4970
  //# sourceMappingURL=index.js.map
3768
4971
  //# sourceMappingURL=index.js.map