@declarion/react 0.1.85 → 0.1.86

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,4 +1,4 @@
1
- import { Gt as e, Kt as t, Wt as n, n as r, ot as i, t as a } from "./useUserLocale-B3bnZHMZ.js";
1
+ import { Gt as e, Kt as t, Wt as n, n as r, ot as i, t as a } from "./useUserLocale-zgHDdn6b.js";
2
2
  import { useCallback as o, useMemo as s, useRef as c } from "react";
3
3
  import { jsx as l, jsxs as u } from "react/jsx-runtime";
4
4
  import { DndContext as d, PointerSensor as f, closestCenter as p, useSensor as m, useSensors as h } from "@dnd-kit/core";
@@ -278,4 +278,4 @@ function x({ row: e, columns: i, editableColumns: o, displayOnlyColumns: s, chil
278
278
  //#endregion
279
279
  export { b as DraggableChildrenTable };
280
280
 
281
- //# sourceMappingURL=DraggableChildrenTable-CVdCUPGE.js.map
281
+ //# sourceMappingURL=DraggableChildrenTable-4GAn4MhZ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DraggableChildrenTable-CVdCUPGE.js","names":[],"sources":["../src/components/detail-layout/DraggableChildrenTable.tsx"],"sourcesContent":["import { useCallback, useMemo, useRef } from \"react\";\nimport {\n DndContext,\n closestCenter,\n PointerSensor,\n useSensor,\n useSensors,\n type DragEndEvent,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n verticalListSortingStrategy,\n useSortable,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { Btn, Icon, IconBtn } from \"@/components/primitives\";\nimport { fieldDisplayName } from \"@/types/schema\";\nimport type { Entity, Schema } from \"@/types/schema\";\nimport { renderField } from \"@/components/fields\";\nimport type { RefsMap } from \"@/components/fields\";\nimport { useUserLocale } from \"@/hooks/useUserLocale\";\nimport type { PendingChildRow } from \"./LayoutRenderer\";\nimport type { ResolvedChildConfig } from \"@/lib/child-config\";\n\ninterface DraggableChildrenTableProps {\n config: ResolvedChildConfig;\n childEntity: Entity;\n schema: Schema;\n rows: PendingChildRow[];\n onChange: (rows: PendingChildRow[]) => void;\n validationErrors?: Record<string, string[]>;\n refs?: RefsMap;\n}\n\n// DraggableChildrenTable renders child rows with drag handles for reordering.\n// Used when position_field is configured on a child relation.\nexport function DraggableChildrenTable({\n config,\n childEntity,\n schema,\n rows,\n onChange,\n validationErrors,\n refs,\n}: DraggableChildrenTableProps) {\n const tableRef = useRef<HTMLTableElement>(null);\n const positionField = config.position_field!;\n const columns = config.columns;\n\n // distance: 5 separates click from drag.\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n );\n\n // Editable columns: exclude FK, auto, primary, and position_field.\n const fkSet = new Set(Array.isArray(config.foreign_key) ? config.foreign_key : [config.foreign_key]);\n const editableColumns = columns.filter((col) => {\n if (fkSet.has(col)) return false;\n if (col === positionField) return false;\n const field = childEntity.fields.get(col);\n if (!field) return false;\n if (field.auto || field.primary) return false;\n return true;\n });\n\n // Display-only columns (auto/primary but visible in column list, or position_field).\n const displayOnlyColumns = new Set(\n columns.filter((col) => {\n if (col === positionField) return true;\n const field = childEntity.fields.get(col);\n return field && (field.auto || field.primary);\n }),\n );\n\n // Visible columns: exclude position_field from display since it's managed by drag.\n const visibleColumns = columns.filter((col) => col !== positionField);\n\n // Row IDs for SortableContext - only non-deleted rows participate in drag.\n const rowIds = useMemo(\n () => rows.filter((r) => !r._deleted).map((r) => r._key),\n [rows],\n );\n\n const handleCellChange = useCallback(\n (rowKey: string, fieldName: string, value: unknown) => {\n const updated = rows.map((row) =>\n row._key === rowKey\n ? { ...row, [fieldName]: value, _dirty: true }\n : row,\n );\n onChange(updated);\n },\n [rows, onChange],\n );\n\n const handleAddRow = useCallback(() => {\n const maxPosition = rows\n .filter((r) => !r._deleted)\n .reduce((max, r) => {\n const pos = typeof r[positionField] === \"number\" ? (r[positionField] as number) : -1;\n return Math.max(max, pos);\n }, -1);\n\n const newRow: PendingChildRow = {\n _key: crypto.randomUUID(),\n _dirty: true,\n [positionField]: maxPosition + 1,\n };\n // Pre-fill from quick_add.defaults first, then field-level defaults.\n const quickDefaults = config.quick_add?.defaults ?? {};\n for (const col of editableColumns) {\n const field = childEntity.fields.get(col);\n if (!field) continue;\n if (quickDefaults[col] !== undefined) {\n newRow[col] = quickDefaults[col];\n } else if (field.default !== undefined) {\n newRow[col] = field.default;\n } else if (field.type === \"bool\") {\n newRow[col] = false;\n }\n }\n onChange([...rows, newRow]);\n }, [rows, onChange, editableColumns, childEntity, config.quick_add?.defaults, positionField]);\n\n const handleDeleteRow = useCallback(\n (rowKey: string) => {\n const updated = rows.map((row) =>\n row._key === rowKey ? { ...row, _deleted: true } : row,\n );\n onChange(updated);\n },\n [rows, onChange],\n );\n\n const handleUndoDelete = useCallback(\n (rowKey: string) => {\n const updated = rows.map((row) =>\n row._key === rowKey ? { ...row, _deleted: false } : row,\n );\n onChange(updated);\n },\n [rows, onChange],\n );\n\n const handleDragEnd = useCallback(\n (event: DragEndEvent) => {\n const { active, over } = event;\n if (!over || active.id === over.id) return;\n\n // Reorder non-deleted rows.\n const nonDeleted = rows.filter((r) => !r._deleted);\n const deleted = rows.filter((r) => r._deleted);\n\n const oldIndex = nonDeleted.findIndex((r) => r._key === String(active.id));\n const newIndex = nonDeleted.findIndex((r) => r._key === String(over.id));\n if (oldIndex === -1 || newIndex === -1) return;\n\n // Move the row.\n const reordered = [...nonDeleted];\n const [moved] = reordered.splice(oldIndex, 1);\n reordered.splice(newIndex, 0, moved);\n\n // Re-assign sequential position values and mark dirty only if position changed.\n const withPositions = reordered.map((row, index) => ({\n ...row,\n [positionField]: index,\n _dirty: row[positionField] !== index ? true : row._dirty,\n }));\n\n // Append deleted rows at the end (they'll be excluded from payload).\n onChange([...withPositions, ...deleted]);\n },\n [rows, onChange, positionField],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTableElement>) => {\n const target = e.target as HTMLElement;\n const cell = target.closest(\"td\");\n if (!cell) return;\n const row = cell.closest(\"tr\");\n if (!row) return;\n const tbody = row.closest(\"tbody\");\n if (!tbody) return;\n\n const cellIndex = Array.from(row.cells).indexOf(cell as HTMLTableCellElement);\n const rowIndex = Array.from(tbody.rows).indexOf(row as HTMLTableRowElement);\n\n if (e.key === \"Tab\") {\n const direction = e.shiftKey ? -1 : 1;\n const allRows = Array.from(tbody.rows);\n let nextRow = rowIndex;\n let nextCell = cellIndex + direction;\n\n while (nextRow >= 0 && nextRow < allRows.length) {\n if (nextCell >= 0 && nextCell < allRows[nextRow].cells.length) {\n const nextTd = allRows[nextRow].cells[nextCell];\n const input = nextTd.querySelector(\"input, select, textarea, [tabindex]\") as HTMLElement | null;\n if (input) {\n e.preventDefault();\n input.focus();\n return;\n }\n nextCell += direction;\n } else {\n nextRow += direction;\n nextCell = direction > 0 ? 0 : (allRows[nextRow]?.cells.length ?? 1) - 1;\n }\n }\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n const allRows = Array.from(tbody.rows);\n if (rowIndex < allRows.length - 1) {\n const nextTd = allRows[rowIndex + 1].cells[cellIndex];\n const input = nextTd?.querySelector(\"input, select, textarea, [tabindex]\") as HTMLElement | null;\n if (input) input.focus();\n } else {\n handleAddRow();\n requestAnimationFrame(() => {\n const newRows = tbody.querySelectorAll(\"tr\");\n const lastRow = newRows[newRows.length - 1];\n if (lastRow) {\n const firstInput = lastRow.querySelector(\"input, select, textarea, [tabindex]\") as HTMLElement | null;\n if (firstInput) firstInput.focus();\n }\n });\n }\n } else if (e.key === \"Escape\") {\n (target as HTMLElement).blur?.();\n }\n },\n [handleAddRow],\n );\n\n const thStyle: React.CSSProperties = {\n height: 30,\n padding: \"0 12px\",\n textAlign: \"left\",\n fontWeight: 600,\n fontSize: 11,\n letterSpacing: \"0.04em\",\n color: \"var(--text-3)\",\n textTransform: \"uppercase\",\n borderBottom: \"1px solid var(--divider)\",\n };\n\n return (\n <div>\n <div style={{ overflowX: \"auto\" }}>\n <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>\n <table\n ref={tableRef}\n style={{ width: \"100%\", fontSize: 12.5, borderCollapse: \"separate\", borderSpacing: 0 }}\n onKeyDown={handleKeyDown}\n >\n <thead>\n <tr>\n <th style={{ ...thStyle, width: 32, padding: \"0 4px\" }} />\n {visibleColumns.map((col) => {\n const field = childEntity.fields.get(col);\n return (\n <th key={col} style={thStyle}>\n {field ? fieldDisplayName(field, col, schema.entities) : col}\n </th>\n );\n })}\n <th style={{ ...thStyle, width: 40 }} />\n </tr>\n </thead>\n <SortableContext items={rowIds} strategy={verticalListSortingStrategy}>\n <tbody>\n {rows.map((row) => (\n <SortableRow\n key={row._key}\n row={row}\n columns={visibleColumns}\n editableColumns={editableColumns}\n displayOnlyColumns={displayOnlyColumns}\n childEntity={childEntity}\n validationErrors={validationErrors}\n refs={refs}\n onCellChange={handleCellChange}\n onDelete={handleDeleteRow}\n onUndoDelete={handleUndoDelete}\n />\n ))}\n </tbody>\n </SortableContext>\n </table>\n </DndContext>\n </div>\n <div style={{ marginTop: 8 }}>\n <Btn kind=\"ghost\" size=\"xs\" icon={<Icon.plus size={12} />} onClick={handleAddRow}>\n Add row\n </Btn>\n </div>\n </div>\n );\n}\n\n// SortableRow wraps a table row with drag-and-drop support.\ninterface SortableRowProps {\n row: PendingChildRow;\n columns: string[];\n editableColumns: string[];\n displayOnlyColumns: Set<string>;\n childEntity: Entity;\n validationErrors?: Record<string, string[]>;\n refs?: RefsMap;\n onCellChange: (rowKey: string, fieldName: string, value: unknown) => void;\n onDelete: (rowKey: string) => void;\n onUndoDelete: (rowKey: string) => void;\n}\n\nfunction SortableRow({\n row,\n columns,\n editableColumns,\n displayOnlyColumns,\n childEntity,\n validationErrors,\n refs,\n onCellChange,\n onDelete,\n onUndoDelete,\n}: SortableRowProps) {\n const userLocale = useUserLocale();\n const isDeleted = !!row._deleted;\n const rowErrors = validationErrors?.[row._key];\n\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: row._key, disabled: isDeleted });\n\n const style = {\n transform: CSS.Translate.toString(transform),\n transition,\n zIndex: isDragging ? 10 : undefined,\n opacity: isDragging ? 0.5 : undefined,\n };\n\n const cellStyle: React.CSSProperties = {\n padding: \"6px 12px\",\n borderBottom: \"1px solid var(--divider)\",\n verticalAlign: \"middle\",\n color: \"var(--text-2)\",\n };\n const editCellStyle: React.CSSProperties = {\n padding: \"4px 4px\",\n borderBottom: \"1px solid var(--divider)\",\n verticalAlign: \"middle\",\n };\n\n return (\n <tr ref={setNodeRef} style={{ ...style, opacity: isDeleted ? 0.5 : style?.opacity ?? 1 }}>\n <td style={{ padding: \"4px 4px\", borderBottom: \"1px solid var(--divider)\", width: 32, verticalAlign: \"middle\" }}>\n {!isDeleted && (\n <button\n type=\"button\"\n style={{\n cursor: \"grab\",\n padding: 4,\n color: \"var(--text-3)\",\n background: \"transparent\",\n border: 0,\n display: \"inline-flex\",\n }}\n {...attributes}\n {...listeners}\n >\n <Icon.grid size={14} />\n </button>\n )}\n </td>\n {columns.map((col) => {\n const field = childEntity.fields.get(col);\n const hasError = rowErrors?.includes(col);\n const isDisplayOnly = displayOnlyColumns.has(col);\n const isEditable = editableColumns.includes(col);\n\n if (isDeleted || isDisplayOnly || !isEditable) {\n return (\n <td\n key={col}\n style={{\n ...cellStyle,\n textDecoration: isDeleted ? \"line-through\" : \"none\",\n }}\n >\n {field\n ? renderField({\n field,\n fieldName: col,\n value: row[col],\n mode: \"display\",\n record: row as Record<string, unknown>,\n refs,\n locale: userLocale,\n })\n : String(row[col] ?? \"\")}\n </td>\n );\n }\n\n return (\n <td\n key={col}\n style={{\n ...editCellStyle,\n outline: hasError ? \"1px solid var(--danger)\" : \"none\",\n outlineOffset: -1,\n borderRadius: hasError ? 4 : 0,\n }}\n title={hasError ? `${col} is required` : undefined}\n >\n {field\n ? renderField({\n field,\n fieldName: col,\n value: row[col],\n mode: \"edit\",\n onChange: (val) => onCellChange(row._key, col, val),\n record: row as Record<string, unknown>,\n refs,\n locale: userLocale,\n })\n : String(row[col] ?? \"\")}\n </td>\n );\n })}\n <td style={{ padding: \"4px 8px\", borderBottom: \"1px solid var(--divider)\", verticalAlign: \"middle\" }}>\n {isDeleted ? (\n <IconBtn\n size={24}\n icon={<Icon.refresh size={12} />}\n onClick={() => onUndoDelete(row._key)}\n title=\"Undo delete\"\n />\n ) : (\n <IconBtn\n size={24}\n icon={<Icon.trash size={12} />}\n onClick={() => onDelete(row._key)}\n title=\"Delete row\"\n />\n )}\n </td>\n </tr>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DraggableChildrenTable-4GAn4MhZ.js","names":[],"sources":["../src/components/detail-layout/DraggableChildrenTable.tsx"],"sourcesContent":["import { useCallback, useMemo, useRef } from \"react\";\nimport {\n DndContext,\n closestCenter,\n PointerSensor,\n useSensor,\n useSensors,\n type DragEndEvent,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n verticalListSortingStrategy,\n useSortable,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { Btn, Icon, IconBtn } from \"@/components/primitives\";\nimport { fieldDisplayName } from \"@/types/schema\";\nimport type { Entity, Schema } from \"@/types/schema\";\nimport { renderField } from \"@/components/fields\";\nimport type { RefsMap } from \"@/components/fields\";\nimport { useUserLocale } from \"@/hooks/useUserLocale\";\nimport type { PendingChildRow } from \"./LayoutRenderer\";\nimport type { ResolvedChildConfig } from \"@/lib/child-config\";\n\ninterface DraggableChildrenTableProps {\n config: ResolvedChildConfig;\n childEntity: Entity;\n schema: Schema;\n rows: PendingChildRow[];\n onChange: (rows: PendingChildRow[]) => void;\n validationErrors?: Record<string, string[]>;\n refs?: RefsMap;\n}\n\n// DraggableChildrenTable renders child rows with drag handles for reordering.\n// Used when position_field is configured on a child relation.\nexport function DraggableChildrenTable({\n config,\n childEntity,\n schema,\n rows,\n onChange,\n validationErrors,\n refs,\n}: DraggableChildrenTableProps) {\n const tableRef = useRef<HTMLTableElement>(null);\n const positionField = config.position_field!;\n const columns = config.columns;\n\n // distance: 5 separates click from drag.\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n );\n\n // Editable columns: exclude FK, auto, primary, and position_field.\n const fkSet = new Set(Array.isArray(config.foreign_key) ? config.foreign_key : [config.foreign_key]);\n const editableColumns = columns.filter((col) => {\n if (fkSet.has(col)) return false;\n if (col === positionField) return false;\n const field = childEntity.fields.get(col);\n if (!field) return false;\n if (field.auto || field.primary) return false;\n return true;\n });\n\n // Display-only columns (auto/primary but visible in column list, or position_field).\n const displayOnlyColumns = new Set(\n columns.filter((col) => {\n if (col === positionField) return true;\n const field = childEntity.fields.get(col);\n return field && (field.auto || field.primary);\n }),\n );\n\n // Visible columns: exclude position_field from display since it's managed by drag.\n const visibleColumns = columns.filter((col) => col !== positionField);\n\n // Row IDs for SortableContext - only non-deleted rows participate in drag.\n const rowIds = useMemo(\n () => rows.filter((r) => !r._deleted).map((r) => r._key),\n [rows],\n );\n\n const handleCellChange = useCallback(\n (rowKey: string, fieldName: string, value: unknown) => {\n const updated = rows.map((row) =>\n row._key === rowKey\n ? { ...row, [fieldName]: value, _dirty: true }\n : row,\n );\n onChange(updated);\n },\n [rows, onChange],\n );\n\n const handleAddRow = useCallback(() => {\n const maxPosition = rows\n .filter((r) => !r._deleted)\n .reduce((max, r) => {\n const pos = typeof r[positionField] === \"number\" ? (r[positionField] as number) : -1;\n return Math.max(max, pos);\n }, -1);\n\n const newRow: PendingChildRow = {\n _key: crypto.randomUUID(),\n _dirty: true,\n [positionField]: maxPosition + 1,\n };\n // Pre-fill from quick_add.defaults first, then field-level defaults.\n const quickDefaults = config.quick_add?.defaults ?? {};\n for (const col of editableColumns) {\n const field = childEntity.fields.get(col);\n if (!field) continue;\n if (quickDefaults[col] !== undefined) {\n newRow[col] = quickDefaults[col];\n } else if (field.default !== undefined) {\n newRow[col] = field.default;\n } else if (field.type === \"bool\") {\n newRow[col] = false;\n }\n }\n onChange([...rows, newRow]);\n }, [rows, onChange, editableColumns, childEntity, config.quick_add?.defaults, positionField]);\n\n const handleDeleteRow = useCallback(\n (rowKey: string) => {\n const updated = rows.map((row) =>\n row._key === rowKey ? { ...row, _deleted: true } : row,\n );\n onChange(updated);\n },\n [rows, onChange],\n );\n\n const handleUndoDelete = useCallback(\n (rowKey: string) => {\n const updated = rows.map((row) =>\n row._key === rowKey ? { ...row, _deleted: false } : row,\n );\n onChange(updated);\n },\n [rows, onChange],\n );\n\n const handleDragEnd = useCallback(\n (event: DragEndEvent) => {\n const { active, over } = event;\n if (!over || active.id === over.id) return;\n\n // Reorder non-deleted rows.\n const nonDeleted = rows.filter((r) => !r._deleted);\n const deleted = rows.filter((r) => r._deleted);\n\n const oldIndex = nonDeleted.findIndex((r) => r._key === String(active.id));\n const newIndex = nonDeleted.findIndex((r) => r._key === String(over.id));\n if (oldIndex === -1 || newIndex === -1) return;\n\n // Move the row.\n const reordered = [...nonDeleted];\n const [moved] = reordered.splice(oldIndex, 1);\n reordered.splice(newIndex, 0, moved);\n\n // Re-assign sequential position values and mark dirty only if position changed.\n const withPositions = reordered.map((row, index) => ({\n ...row,\n [positionField]: index,\n _dirty: row[positionField] !== index ? true : row._dirty,\n }));\n\n // Append deleted rows at the end (they'll be excluded from payload).\n onChange([...withPositions, ...deleted]);\n },\n [rows, onChange, positionField],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTableElement>) => {\n const target = e.target as HTMLElement;\n const cell = target.closest(\"td\");\n if (!cell) return;\n const row = cell.closest(\"tr\");\n if (!row) return;\n const tbody = row.closest(\"tbody\");\n if (!tbody) return;\n\n const cellIndex = Array.from(row.cells).indexOf(cell as HTMLTableCellElement);\n const rowIndex = Array.from(tbody.rows).indexOf(row as HTMLTableRowElement);\n\n if (e.key === \"Tab\") {\n const direction = e.shiftKey ? -1 : 1;\n const allRows = Array.from(tbody.rows);\n let nextRow = rowIndex;\n let nextCell = cellIndex + direction;\n\n while (nextRow >= 0 && nextRow < allRows.length) {\n if (nextCell >= 0 && nextCell < allRows[nextRow].cells.length) {\n const nextTd = allRows[nextRow].cells[nextCell];\n const input = nextTd.querySelector(\"input, select, textarea, [tabindex]\") as HTMLElement | null;\n if (input) {\n e.preventDefault();\n input.focus();\n return;\n }\n nextCell += direction;\n } else {\n nextRow += direction;\n nextCell = direction > 0 ? 0 : (allRows[nextRow]?.cells.length ?? 1) - 1;\n }\n }\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n const allRows = Array.from(tbody.rows);\n if (rowIndex < allRows.length - 1) {\n const nextTd = allRows[rowIndex + 1].cells[cellIndex];\n const input = nextTd?.querySelector(\"input, select, textarea, [tabindex]\") as HTMLElement | null;\n if (input) input.focus();\n } else {\n handleAddRow();\n requestAnimationFrame(() => {\n const newRows = tbody.querySelectorAll(\"tr\");\n const lastRow = newRows[newRows.length - 1];\n if (lastRow) {\n const firstInput = lastRow.querySelector(\"input, select, textarea, [tabindex]\") as HTMLElement | null;\n if (firstInput) firstInput.focus();\n }\n });\n }\n } else if (e.key === \"Escape\") {\n (target as HTMLElement).blur?.();\n }\n },\n [handleAddRow],\n );\n\n const thStyle: React.CSSProperties = {\n height: 30,\n padding: \"0 12px\",\n textAlign: \"left\",\n fontWeight: 600,\n fontSize: 11,\n letterSpacing: \"0.04em\",\n color: \"var(--text-3)\",\n textTransform: \"uppercase\",\n borderBottom: \"1px solid var(--divider)\",\n };\n\n return (\n <div>\n <div style={{ overflowX: \"auto\" }}>\n <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>\n <table\n ref={tableRef}\n style={{ width: \"100%\", fontSize: 12.5, borderCollapse: \"separate\", borderSpacing: 0 }}\n onKeyDown={handleKeyDown}\n >\n <thead>\n <tr>\n <th style={{ ...thStyle, width: 32, padding: \"0 4px\" }} />\n {visibleColumns.map((col) => {\n const field = childEntity.fields.get(col);\n return (\n <th key={col} style={thStyle}>\n {field ? fieldDisplayName(field, col, schema.entities) : col}\n </th>\n );\n })}\n <th style={{ ...thStyle, width: 40 }} />\n </tr>\n </thead>\n <SortableContext items={rowIds} strategy={verticalListSortingStrategy}>\n <tbody>\n {rows.map((row) => (\n <SortableRow\n key={row._key}\n row={row}\n columns={visibleColumns}\n editableColumns={editableColumns}\n displayOnlyColumns={displayOnlyColumns}\n childEntity={childEntity}\n validationErrors={validationErrors}\n refs={refs}\n onCellChange={handleCellChange}\n onDelete={handleDeleteRow}\n onUndoDelete={handleUndoDelete}\n />\n ))}\n </tbody>\n </SortableContext>\n </table>\n </DndContext>\n </div>\n <div style={{ marginTop: 8 }}>\n <Btn kind=\"ghost\" size=\"xs\" icon={<Icon.plus size={12} />} onClick={handleAddRow}>\n Add row\n </Btn>\n </div>\n </div>\n );\n}\n\n// SortableRow wraps a table row with drag-and-drop support.\ninterface SortableRowProps {\n row: PendingChildRow;\n columns: string[];\n editableColumns: string[];\n displayOnlyColumns: Set<string>;\n childEntity: Entity;\n validationErrors?: Record<string, string[]>;\n refs?: RefsMap;\n onCellChange: (rowKey: string, fieldName: string, value: unknown) => void;\n onDelete: (rowKey: string) => void;\n onUndoDelete: (rowKey: string) => void;\n}\n\nfunction SortableRow({\n row,\n columns,\n editableColumns,\n displayOnlyColumns,\n childEntity,\n validationErrors,\n refs,\n onCellChange,\n onDelete,\n onUndoDelete,\n}: SortableRowProps) {\n const userLocale = useUserLocale();\n const isDeleted = !!row._deleted;\n const rowErrors = validationErrors?.[row._key];\n\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: row._key, disabled: isDeleted });\n\n const style = {\n transform: CSS.Translate.toString(transform),\n transition,\n zIndex: isDragging ? 10 : undefined,\n opacity: isDragging ? 0.5 : undefined,\n };\n\n const cellStyle: React.CSSProperties = {\n padding: \"6px 12px\",\n borderBottom: \"1px solid var(--divider)\",\n verticalAlign: \"middle\",\n color: \"var(--text-2)\",\n };\n const editCellStyle: React.CSSProperties = {\n padding: \"4px 4px\",\n borderBottom: \"1px solid var(--divider)\",\n verticalAlign: \"middle\",\n };\n\n return (\n <tr ref={setNodeRef} style={{ ...style, opacity: isDeleted ? 0.5 : style?.opacity ?? 1 }}>\n <td style={{ padding: \"4px 4px\", borderBottom: \"1px solid var(--divider)\", width: 32, verticalAlign: \"middle\" }}>\n {!isDeleted && (\n <button\n type=\"button\"\n style={{\n cursor: \"grab\",\n padding: 4,\n color: \"var(--text-3)\",\n background: \"transparent\",\n border: 0,\n display: \"inline-flex\",\n }}\n {...attributes}\n {...listeners}\n >\n <Icon.grid size={14} />\n </button>\n )}\n </td>\n {columns.map((col) => {\n const field = childEntity.fields.get(col);\n const hasError = rowErrors?.includes(col);\n const isDisplayOnly = displayOnlyColumns.has(col);\n const isEditable = editableColumns.includes(col);\n\n if (isDeleted || isDisplayOnly || !isEditable) {\n return (\n <td\n key={col}\n style={{\n ...cellStyle,\n textDecoration: isDeleted ? \"line-through\" : \"none\",\n }}\n >\n {field\n ? renderField({\n field,\n fieldName: col,\n value: row[col],\n mode: \"display\",\n record: row as Record<string, unknown>,\n refs,\n locale: userLocale,\n })\n : String(row[col] ?? \"\")}\n </td>\n );\n }\n\n return (\n <td\n key={col}\n style={{\n ...editCellStyle,\n outline: hasError ? \"1px solid var(--danger)\" : \"none\",\n outlineOffset: -1,\n borderRadius: hasError ? 4 : 0,\n }}\n title={hasError ? `${col} is required` : undefined}\n >\n {field\n ? renderField({\n field,\n fieldName: col,\n value: row[col],\n mode: \"edit\",\n onChange: (val) => onCellChange(row._key, col, val),\n record: row as Record<string, unknown>,\n refs,\n locale: userLocale,\n })\n : String(row[col] ?? \"\")}\n </td>\n );\n })}\n <td style={{ padding: \"4px 8px\", borderBottom: \"1px solid var(--divider)\", verticalAlign: \"middle\" }}>\n {isDeleted ? (\n <IconBtn\n size={24}\n icon={<Icon.refresh size={12} />}\n onClick={() => onUndoDelete(row._key)}\n title=\"Undo delete\"\n />\n ) : (\n <IconBtn\n size={24}\n icon={<Icon.trash size={12} />}\n onClick={() => onDelete(row._key)}\n title=\"Delete row\"\n />\n )}\n </td>\n </tr>\n );\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { _ as e, g as t, h as n, i as r, l as i, m as a, t as o, v as s } from "./value-DgzPSFZM.js";
1
+ import { _ as e, g as t, h as n, i as r, l as i, m as a, t as o, v as s } from "./value-ByObsKvK.js";
2
2
  import { useCallback as c, useEffect as l, useMemo as u, useRef as d, useState as f } from "react";
3
3
  import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
4
4
  import { DndContext as g, PointerSensor as _, closestCenter as v, useSensor as y, useSensors as ee } from "@dnd-kit/core";
@@ -402,4 +402,4 @@ function D({ file: e, hasPrev: n, hasNext: r, onPrev: i, onNext: a, onClose: o }
402
402
  //#endregion
403
403
  export { T as Grid };
404
404
 
405
- //# sourceMappingURL=Grid-By_Ere-W.js.map
405
+ //# sourceMappingURL=Grid-Czmg00YR.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Grid-By_Ere-W.js","names":[],"sources":["../src/components/file-widgets/Grid.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { CSSProperties, DragEvent, KeyboardEvent } from \"react\";\nimport {\n DndContext,\n closestCenter,\n PointerSensor,\n useSensor,\n useSensors,\n type DragEndEvent,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n rectSortingStrategy,\n useSortable,\n arrayMove,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport {\n uploadFile,\n discardFile,\n validateClientSide,\n formatBytes,\n UploadError,\n} from \"./upload\";\nimport { useDraftRegistration } from \"./draft-scope\";\nimport { preferredListThumbnailURL } from \"./helpers\";\nimport { fileArrayFromValue } from \"./value\";\nimport type {\n FileWidgetProps,\n HydratedFile,\n UploadProgress,\n} from \"./types\";\n\n// Grid widget: thumbnail grid for `mode: array` files. Per einstein §6.4.\n//\n// Behaviors:\n// - drag-drop multi-upload (each file gets its own progress tile)\n// - per-item hover overlay (View / Metadata / Delete)\n// - drag-handle reorder via @dnd-kit\n// - multi-select toolbar with Bulk Delete\n// - click → lightbox with prev/next + keyboard nav\n// - IntersectionObserver lazy thumbnail loading\n// - per-tile thumbnail prefers the schema-selected list derivation, then\n// falls back to built-in thumbs or the primary file URL\n//\n// Value contract: array of HydratedFile. onChange emits the full new array\n// (callers persist it via the entity's $files payload on save).\n\ninterface InFlightTile {\n // Local-only tiles representing uploads in progress. Once finished they\n // are appended to the value array and removed from this list.\n localId: string;\n filename: string;\n progress: UploadProgress | null;\n error: { code: string; message: string } | null;\n abort: () => void;\n}\n\nfunction thumbUrl(f: HydratedFile, preferredDerivationKey?: string): string | undefined {\n return preferredListThumbnailURL(f, preferredDerivationKey);\n}\n\nexport function Grid(props: FileWidgetProps) {\n const { field, fieldName, value, onChange, mode, disabled } = props;\n const items = fileArrayFromValue(value);\n const [tiles, setTiles] = useState<InFlightTile[]>([]);\n const [selected, setSelected] = useState<Set<string>>(new Set());\n const [lightbox, setLightbox] = useState<number | null>(null);\n const { register, unregister, isDraft } = useDraftRegistration();\n const cancelledUploadsRef = useRef<Set<string>>(new Set());\n const tilesRef = useRef<InFlightTile[]>([]);\n tilesRef.current = tiles;\n // valueRef snapshots the current value array so parallel uploads append\n // against the most recent state, not the closure they were created with.\n const valueRef = useRef<HydratedFile[]>(items);\n valueRef.current = items;\n\n // Cleanup all in-flight uploads on unmount.\n useEffect(() => {\n return () => {\n tilesRef.current.forEach((t) => t.abort());\n };\n }, []);\n\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n );\n\n const ariaLabel = field.display?.placeholder || fieldName;\n const accept = (field.accepts ?? [\"image/*\"]).join(\",\");\n const reorderable = field.display?.reorderable !== false;\n const preferredThumbnail = field.display?.listable_thumbnail;\n\n const startUpload = useCallback(\n async (raw: File) => {\n const v = validateClientSide(raw, field.accepts, field.max_size_bytes);\n const localId = `tile-${Math.random().toString(36).slice(2)}-${Date.now()}`;\n const ctrl = new AbortController();\n\n if (v) {\n setTiles((prev) => [\n ...prev,\n {\n localId,\n filename: raw.name,\n progress: null,\n error: v,\n abort: () => {},\n },\n ]);\n return;\n }\n\n setTiles((prev) => [\n ...prev,\n {\n localId,\n filename: raw.name,\n progress: { loaded: 0, total: raw.size, pct: 0 },\n error: null,\n abort: () => ctrl.abort(),\n },\n ]);\n\n try {\n const result = await uploadFile({\n file: raw,\n entityCode: props.entityCode,\n fieldCode: fieldName,\n signal: ctrl.signal,\n onProgress: (p) =>\n setTiles((prev) =>\n prev.map((t) =>\n t.localId === localId ? { ...t, progress: p } : t,\n ),\n ),\n });\n if (cancelledUploadsRef.current.delete(localId)) {\n void discardFile(result.id).catch(() => {});\n unregister(result.id);\n return;\n }\n register(result.id, () => discardFile(result.id));\n const next: HydratedFile = {\n id: result.id,\n filename: result.filename,\n content_type: result.content_type,\n size_bytes: result.size_bytes,\n sha256: result.sha256,\n width: result.width,\n height: result.height,\n url: result.url,\n metadata: result.metadata,\n };\n const merged = [...valueRef.current, next];\n valueRef.current = merged;\n onChange?.(merged);\n setTiles((prev) => prev.filter((t) => t.localId !== localId));\n } catch (err) {\n if (err instanceof UploadError && err.code === \"ABORTED\") {\n setTiles((prev) => prev.filter((t) => t.localId !== localId));\n return;\n }\n const e =\n err instanceof UploadError\n ? { code: err.code, message: err.message }\n : {\n code: \"UNKNOWN\",\n message: err instanceof Error ? err.message : \"Upload failed\",\n };\n setTiles((prev) =>\n prev.map((t) =>\n t.localId === localId\n ? { ...t, error: e, progress: null, abort: () => {} }\n : t,\n ),\n );\n }\n },\n [field.accepts, field.max_size_bytes, fieldName, onChange, props.entityCode, register, unregister],\n );\n\n const handleFiles = useCallback(\n (files: FileList | File[]) => {\n const arr = Array.from(files);\n arr.forEach((f) => void startUpload(f));\n },\n [startUpload],\n );\n\n const fileInputRef = useRef<HTMLInputElement | null>(null);\n const onPick = useCallback(() => {\n if (disabled) return;\n fileInputRef.current?.click();\n }, [disabled]);\n\n const onDragOver = useCallback(\n (e: DragEvent<HTMLDivElement>) => {\n if (disabled) return;\n e.preventDefault();\n e.dataTransfer.dropEffect = \"copy\";\n },\n [disabled],\n );\n\n const onDrop = useCallback(\n (e: DragEvent<HTMLDivElement>) => {\n if (disabled) return;\n e.preventDefault();\n const files = e.dataTransfer.files;\n if (files && files.length > 0) handleFiles(files);\n },\n [disabled, handleFiles],\n );\n\n const onChangeFile = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = e.target.files;\n e.target.value = \"\";\n if (files && files.length > 0) handleFiles(files);\n },\n [handleFiles],\n );\n\n const handleRemove = useCallback(\n (id: string) => {\n if (isDraft(id)) {\n void discardFile(id).catch(() => {});\n unregister(id);\n }\n const next = items.filter((f) => f.id !== id);\n onChange?.(next);\n setSelected((prev) => {\n const n = new Set(prev);\n n.delete(id);\n return n;\n });\n },\n [isDraft, items, onChange, unregister],\n );\n\n const handleBulkDelete = useCallback(() => {\n if (selected.size === 0) return;\n const ids = Array.from(selected);\n ids.forEach((id) => {\n if (isDraft(id)) {\n void discardFile(id).catch(() => {});\n unregister(id);\n }\n });\n onChange?.(items.filter((f) => !selected.has(f.id)));\n setSelected(new Set());\n }, [isDraft, items, selected, onChange, unregister]);\n\n const handleDragEnd = useCallback(\n (event: DragEndEvent) => {\n const { active, over } = event;\n if (!over || active.id === over.id) return;\n const oldIdx = items.findIndex((f) => f.id === active.id);\n const newIdx = items.findIndex((f) => f.id === over.id);\n if (oldIdx < 0 || newIdx < 0) return;\n onChange?.(arrayMove(items, oldIdx, newIdx));\n },\n [items, onChange],\n );\n\n const toggleSelect = useCallback((id: string) => {\n setSelected((prev) => {\n const n = new Set(prev);\n if (n.has(id)) n.delete(id);\n else n.add(id);\n return n;\n });\n }, []);\n\n const lightboxFile = lightbox != null ? items[lightbox] : null;\n const lightboxNext = useCallback(() => {\n setLightbox((cur) =>\n cur == null ? cur : Math.min(items.length - 1, cur + 1),\n );\n }, [items.length]);\n const lightboxPrev = useCallback(() => {\n setLightbox((cur) => (cur == null ? cur : Math.max(0, cur - 1)));\n }, []);\n const lightboxClose = useCallback(() => setLightbox(null), []);\n\n useEffect(() => {\n if (lightbox == null) return;\n const handler = (e: globalThis.KeyboardEvent) => {\n if (e.key === \"Escape\") lightboxClose();\n else if (e.key === \"ArrowRight\") lightboxNext();\n else if (e.key === \"ArrowLeft\") lightboxPrev();\n };\n window.addEventListener(\"keydown\", handler);\n return () => window.removeEventListener(\"keydown\", handler);\n }, [lightbox, lightboxClose, lightboxNext, lightboxPrev]);\n\n const onGridKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return;\n if (e.key === \"Enter\" || e.key === \" \") {\n if (e.target === e.currentTarget) {\n e.preventDefault();\n onPick();\n }\n }\n },\n [disabled, onPick],\n );\n\n const isDisplay = mode === \"display\";\n\n const sortableIds = useMemo(() => items.map((f) => f.id), [items]);\n\n return (\n <div data-testid={`file-widget-${fieldName}`} className=\"flex flex-col gap-2\">\n {!isDisplay && selected.size > 0 && (\n <div\n className=\"flex items-center gap-2 rounded-md border border-border bg-surface-2 p-2 text-sm\"\n role=\"toolbar\"\n aria-label=\"Bulk actions\"\n >\n <span className=\"text-foreground\">{selected.size} selected</span>\n <button\n type=\"button\"\n className=\"rounded-sm border border-border bg-card px-2 py-1 text-xs text-destructive hover:bg-surface-2\"\n onClick={handleBulkDelete}\n data-testid=\"bulk-delete\"\n >\n Delete\n </button>\n <button\n type=\"button\"\n className=\"rounded-sm border border-border bg-card px-2 py-1 text-xs text-foreground hover:bg-surface-2\"\n onClick={() => setSelected(new Set())}\n >\n Clear\n </button>\n </div>\n )}\n\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n onDragEnd={handleDragEnd}\n >\n <SortableContext items={sortableIds} strategy={rectSortingStrategy}>\n <div\n className=\"grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-3 rounded-md border border-dashed border-border bg-surface p-3 outline-none focus-visible:outline-2 focus-visible:outline-accent\"\n role=\"grid\"\n aria-label={ariaLabel}\n tabIndex={isDisplay || disabled ? -1 : 0}\n onDragOver={onDragOver}\n onDrop={onDrop}\n onKeyDown={onGridKeyDown}\n data-testid=\"grid-container\"\n >\n {items.map((f, idx) => (\n <SortableTile\n key={f.id}\n file={f}\n selected={selected.has(f.id)}\n disabled={disabled || isDisplay}\n reorderable={reorderable && !isDisplay}\n preferredThumbnail={preferredThumbnail}\n onSelect={() => toggleSelect(f.id)}\n onRemove={() => handleRemove(f.id)}\n onPreview={() => setLightbox(idx)}\n />\n ))}\n {tiles.map((t) => (\n <PendingTile\n key={t.localId}\n tile={t}\n onCancel={() => {\n t.abort();\n cancelledUploadsRef.current.add(t.localId);\n setTiles((prev) =>\n prev.filter((x) => x.localId !== t.localId),\n );\n }}\n onDismiss={() =>\n setTiles((prev) =>\n prev.filter((x) => x.localId !== t.localId),\n )\n }\n />\n ))}\n {items.length === 0 && tiles.length === 0 && (\n <div\n className=\"col-span-full flex h-24 cursor-pointer items-center justify-center text-sm text-muted-foreground\"\n onClick={onPick}\n data-testid=\"grid-empty\"\n >\n {field.display?.placeholder || \"Drop files here or click to browse\"}\n </div>\n )}\n </div>\n </SortableContext>\n </DndContext>\n\n {!isDisplay && (\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={accept}\n multiple\n onChange={onChangeFile}\n style={{ display: \"none\" }}\n data-testid={`file-input-${fieldName}`}\n />\n )}\n\n {lightboxFile && (\n <Lightbox\n file={lightboxFile}\n hasPrev={lightbox! > 0}\n hasNext={lightbox! < items.length - 1}\n onPrev={lightboxPrev}\n onNext={lightboxNext}\n onClose={lightboxClose}\n />\n )}\n </div>\n );\n}\n\nfunction SortableTile({\n file,\n selected,\n disabled,\n reorderable,\n preferredThumbnail,\n onSelect,\n onRemove,\n onPreview,\n}: {\n file: HydratedFile;\n selected: boolean;\n disabled?: boolean;\n reorderable: boolean;\n preferredThumbnail?: string;\n onSelect: () => void;\n onRemove: () => void;\n onPreview: () => void;\n}) {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: file.id, disabled: !reorderable });\n const style: CSSProperties = {\n transform: CSS.Transform.toString(transform),\n transition,\n opacity: isDragging ? 0.5 : 1,\n };\n const url = thumbUrl(file, preferredThumbnail);\n return (\n <div\n ref={setNodeRef}\n style={style}\n className={`group relative aspect-square overflow-hidden rounded-md border ${\n selected ? \"border-accent\" : \"border-border\"\n } bg-surface-2`}\n data-testid={`grid-tile-${file.id}`}\n data-selected={selected || undefined}\n >\n {/* Lazy thumb: native loading=\"lazy\" approximates IntersectionObserver\n and is what the rest of the SDK uses (see ImageWidget). */}\n {url ? (\n <img\n src={url}\n alt={file.filename}\n className=\"h-full w-full cursor-pointer object-cover\"\n loading=\"lazy\"\n onClick={onPreview}\n />\n ) : (\n <div\n className=\"flex h-full w-full cursor-pointer items-center justify-center bg-surface-3 text-xs text-muted-foreground\"\n onClick={onPreview}\n >\n {file.filename}\n </div>\n )}\n {!disabled && (\n <>\n <input\n type=\"checkbox\"\n className=\"absolute left-1 top-1 h-4 w-4 cursor-pointer\"\n checked={selected}\n onChange={onSelect}\n aria-label={`Select ${file.filename}`}\n data-testid={`select-${file.id}`}\n onClick={(e) => e.stopPropagation()}\n />\n {reorderable && (\n <button\n type=\"button\"\n className=\"absolute right-1 top-1 cursor-grab rounded-sm border border-border bg-card px-1 text-xs\"\n aria-label={`Drag to reorder ${file.filename}`}\n data-testid={`drag-${file.id}`}\n {...attributes}\n {...listeners}\n >\n ⋮⋮\n </button>\n )}\n <div className=\"absolute inset-x-0 bottom-0 flex items-center justify-end gap-1 bg-black/50 p-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100\">\n <button\n type=\"button\"\n className=\"rounded-sm border border-border bg-card px-2 py-0.5 text-xs\"\n onClick={onPreview}\n >\n View\n </button>\n <button\n type=\"button\"\n className=\"rounded-sm border border-border bg-card px-2 py-0.5 text-xs text-destructive\"\n onClick={onRemove}\n data-testid={`remove-${file.id}`}\n >\n Delete\n </button>\n </div>\n </>\n )}\n </div>\n );\n}\n\nfunction PendingTile({\n tile,\n onCancel,\n onDismiss,\n}: {\n tile: InFlightTile;\n onCancel: () => void;\n onDismiss: () => void;\n}) {\n return (\n <div\n className={`relative flex aspect-square flex-col items-center justify-center rounded-md border ${\n tile.error ? \"border-destructive\" : \"border-border\"\n } bg-surface-2 p-2 text-center text-xs`}\n data-testid={`pending-tile-${tile.localId}`}\n >\n <span className=\"truncate\" title={tile.filename}>\n {tile.filename}\n </span>\n {tile.progress && !tile.error && (\n <span\n className=\"mt-1 text-muted-foreground\"\n role=\"progressbar\"\n aria-valuenow={tile.progress.pct}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n {tile.progress.pct}%\n </span>\n )}\n {tile.error && (\n <div role=\"alert\" className=\"mt-1 text-destructive\">\n {tile.error.message}\n </div>\n )}\n <button\n type=\"button\"\n className=\"mt-1 rounded-sm border border-border bg-card px-2 py-0.5\"\n onClick={tile.error ? onDismiss : onCancel}\n >\n {tile.error ? \"Dismiss\" : \"Cancel\"}\n </button>\n </div>\n );\n}\n\nfunction Lightbox({\n file,\n hasPrev,\n hasNext,\n onPrev,\n onNext,\n onClose,\n}: {\n file: HydratedFile;\n hasPrev: boolean;\n hasNext: boolean;\n onPrev: () => void;\n onNext: () => void;\n onClose: () => void;\n}) {\n const url = file.presigned_url ?? file.url ?? thumbUrl(file);\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/80\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={file.filename}\n data-testid=\"lightbox\"\n onClick={onClose}\n >\n <button\n type=\"button\"\n className=\"absolute right-4 top-4 rounded-sm border border-border bg-card px-3 py-1 text-foreground\"\n onClick={(e) => {\n e.stopPropagation();\n onClose();\n }}\n data-testid=\"lightbox-close\"\n >\n Close\n </button>\n {hasPrev && (\n <button\n type=\"button\"\n className=\"absolute left-4 rounded-sm border border-border bg-card px-3 py-2 text-foreground\"\n onClick={(e) => {\n e.stopPropagation();\n onPrev();\n }}\n data-testid=\"lightbox-prev\"\n >\n ‹\n </button>\n )}\n {hasNext && (\n <button\n type=\"button\"\n className=\"absolute right-4 bottom-4 rounded-sm border border-border bg-card px-3 py-2 text-foreground\"\n onClick={(e) => {\n e.stopPropagation();\n onNext();\n }}\n data-testid=\"lightbox-next\"\n >\n ›\n </button>\n )}\n {url ? (\n <img\n src={url}\n alt={file.filename}\n className=\"max-h-[90vh] max-w-[90vw] object-contain\"\n onClick={(e) => e.stopPropagation()}\n />\n ) : (\n <div className=\"rounded-md bg-card p-4 text-foreground\">\n {file.filename} ({formatBytes(file.size_bytes)})\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Grid-Czmg00YR.js","names":[],"sources":["../src/components/file-widgets/Grid.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { CSSProperties, DragEvent, KeyboardEvent } from \"react\";\nimport {\n DndContext,\n closestCenter,\n PointerSensor,\n useSensor,\n useSensors,\n type DragEndEvent,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n rectSortingStrategy,\n useSortable,\n arrayMove,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport {\n uploadFile,\n discardFile,\n validateClientSide,\n formatBytes,\n UploadError,\n} from \"./upload\";\nimport { useDraftRegistration } from \"./draft-scope\";\nimport { preferredListThumbnailURL } from \"./helpers\";\nimport { fileArrayFromValue } from \"./value\";\nimport type {\n FileWidgetProps,\n HydratedFile,\n UploadProgress,\n} from \"./types\";\n\n// Grid widget: thumbnail grid for `mode: array` files. Per einstein §6.4.\n//\n// Behaviors:\n// - drag-drop multi-upload (each file gets its own progress tile)\n// - per-item hover overlay (View / Metadata / Delete)\n// - drag-handle reorder via @dnd-kit\n// - multi-select toolbar with Bulk Delete\n// - click → lightbox with prev/next + keyboard nav\n// - IntersectionObserver lazy thumbnail loading\n// - per-tile thumbnail prefers the schema-selected list derivation, then\n// falls back to built-in thumbs or the primary file URL\n//\n// Value contract: array of HydratedFile. onChange emits the full new array\n// (callers persist it via the entity's $files payload on save).\n\ninterface InFlightTile {\n // Local-only tiles representing uploads in progress. Once finished they\n // are appended to the value array and removed from this list.\n localId: string;\n filename: string;\n progress: UploadProgress | null;\n error: { code: string; message: string } | null;\n abort: () => void;\n}\n\nfunction thumbUrl(f: HydratedFile, preferredDerivationKey?: string): string | undefined {\n return preferredListThumbnailURL(f, preferredDerivationKey);\n}\n\nexport function Grid(props: FileWidgetProps) {\n const { field, fieldName, value, onChange, mode, disabled } = props;\n const items = fileArrayFromValue(value);\n const [tiles, setTiles] = useState<InFlightTile[]>([]);\n const [selected, setSelected] = useState<Set<string>>(new Set());\n const [lightbox, setLightbox] = useState<number | null>(null);\n const { register, unregister, isDraft } = useDraftRegistration();\n const cancelledUploadsRef = useRef<Set<string>>(new Set());\n const tilesRef = useRef<InFlightTile[]>([]);\n tilesRef.current = tiles;\n // valueRef snapshots the current value array so parallel uploads append\n // against the most recent state, not the closure they were created with.\n const valueRef = useRef<HydratedFile[]>(items);\n valueRef.current = items;\n\n // Cleanup all in-flight uploads on unmount.\n useEffect(() => {\n return () => {\n tilesRef.current.forEach((t) => t.abort());\n };\n }, []);\n\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n );\n\n const ariaLabel = field.display?.placeholder || fieldName;\n const accept = (field.accepts ?? [\"image/*\"]).join(\",\");\n const reorderable = field.display?.reorderable !== false;\n const preferredThumbnail = field.display?.listable_thumbnail;\n\n const startUpload = useCallback(\n async (raw: File) => {\n const v = validateClientSide(raw, field.accepts, field.max_size_bytes);\n const localId = `tile-${Math.random().toString(36).slice(2)}-${Date.now()}`;\n const ctrl = new AbortController();\n\n if (v) {\n setTiles((prev) => [\n ...prev,\n {\n localId,\n filename: raw.name,\n progress: null,\n error: v,\n abort: () => {},\n },\n ]);\n return;\n }\n\n setTiles((prev) => [\n ...prev,\n {\n localId,\n filename: raw.name,\n progress: { loaded: 0, total: raw.size, pct: 0 },\n error: null,\n abort: () => ctrl.abort(),\n },\n ]);\n\n try {\n const result = await uploadFile({\n file: raw,\n entityCode: props.entityCode,\n fieldCode: fieldName,\n signal: ctrl.signal,\n onProgress: (p) =>\n setTiles((prev) =>\n prev.map((t) =>\n t.localId === localId ? { ...t, progress: p } : t,\n ),\n ),\n });\n if (cancelledUploadsRef.current.delete(localId)) {\n void discardFile(result.id).catch(() => {});\n unregister(result.id);\n return;\n }\n register(result.id, () => discardFile(result.id));\n const next: HydratedFile = {\n id: result.id,\n filename: result.filename,\n content_type: result.content_type,\n size_bytes: result.size_bytes,\n sha256: result.sha256,\n width: result.width,\n height: result.height,\n url: result.url,\n metadata: result.metadata,\n };\n const merged = [...valueRef.current, next];\n valueRef.current = merged;\n onChange?.(merged);\n setTiles((prev) => prev.filter((t) => t.localId !== localId));\n } catch (err) {\n if (err instanceof UploadError && err.code === \"ABORTED\") {\n setTiles((prev) => prev.filter((t) => t.localId !== localId));\n return;\n }\n const e =\n err instanceof UploadError\n ? { code: err.code, message: err.message }\n : {\n code: \"UNKNOWN\",\n message: err instanceof Error ? err.message : \"Upload failed\",\n };\n setTiles((prev) =>\n prev.map((t) =>\n t.localId === localId\n ? { ...t, error: e, progress: null, abort: () => {} }\n : t,\n ),\n );\n }\n },\n [field.accepts, field.max_size_bytes, fieldName, onChange, props.entityCode, register, unregister],\n );\n\n const handleFiles = useCallback(\n (files: FileList | File[]) => {\n const arr = Array.from(files);\n arr.forEach((f) => void startUpload(f));\n },\n [startUpload],\n );\n\n const fileInputRef = useRef<HTMLInputElement | null>(null);\n const onPick = useCallback(() => {\n if (disabled) return;\n fileInputRef.current?.click();\n }, [disabled]);\n\n const onDragOver = useCallback(\n (e: DragEvent<HTMLDivElement>) => {\n if (disabled) return;\n e.preventDefault();\n e.dataTransfer.dropEffect = \"copy\";\n },\n [disabled],\n );\n\n const onDrop = useCallback(\n (e: DragEvent<HTMLDivElement>) => {\n if (disabled) return;\n e.preventDefault();\n const files = e.dataTransfer.files;\n if (files && files.length > 0) handleFiles(files);\n },\n [disabled, handleFiles],\n );\n\n const onChangeFile = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = e.target.files;\n e.target.value = \"\";\n if (files && files.length > 0) handleFiles(files);\n },\n [handleFiles],\n );\n\n const handleRemove = useCallback(\n (id: string) => {\n if (isDraft(id)) {\n void discardFile(id).catch(() => {});\n unregister(id);\n }\n const next = items.filter((f) => f.id !== id);\n onChange?.(next);\n setSelected((prev) => {\n const n = new Set(prev);\n n.delete(id);\n return n;\n });\n },\n [isDraft, items, onChange, unregister],\n );\n\n const handleBulkDelete = useCallback(() => {\n if (selected.size === 0) return;\n const ids = Array.from(selected);\n ids.forEach((id) => {\n if (isDraft(id)) {\n void discardFile(id).catch(() => {});\n unregister(id);\n }\n });\n onChange?.(items.filter((f) => !selected.has(f.id)));\n setSelected(new Set());\n }, [isDraft, items, selected, onChange, unregister]);\n\n const handleDragEnd = useCallback(\n (event: DragEndEvent) => {\n const { active, over } = event;\n if (!over || active.id === over.id) return;\n const oldIdx = items.findIndex((f) => f.id === active.id);\n const newIdx = items.findIndex((f) => f.id === over.id);\n if (oldIdx < 0 || newIdx < 0) return;\n onChange?.(arrayMove(items, oldIdx, newIdx));\n },\n [items, onChange],\n );\n\n const toggleSelect = useCallback((id: string) => {\n setSelected((prev) => {\n const n = new Set(prev);\n if (n.has(id)) n.delete(id);\n else n.add(id);\n return n;\n });\n }, []);\n\n const lightboxFile = lightbox != null ? items[lightbox] : null;\n const lightboxNext = useCallback(() => {\n setLightbox((cur) =>\n cur == null ? cur : Math.min(items.length - 1, cur + 1),\n );\n }, [items.length]);\n const lightboxPrev = useCallback(() => {\n setLightbox((cur) => (cur == null ? cur : Math.max(0, cur - 1)));\n }, []);\n const lightboxClose = useCallback(() => setLightbox(null), []);\n\n useEffect(() => {\n if (lightbox == null) return;\n const handler = (e: globalThis.KeyboardEvent) => {\n if (e.key === \"Escape\") lightboxClose();\n else if (e.key === \"ArrowRight\") lightboxNext();\n else if (e.key === \"ArrowLeft\") lightboxPrev();\n };\n window.addEventListener(\"keydown\", handler);\n return () => window.removeEventListener(\"keydown\", handler);\n }, [lightbox, lightboxClose, lightboxNext, lightboxPrev]);\n\n const onGridKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return;\n if (e.key === \"Enter\" || e.key === \" \") {\n if (e.target === e.currentTarget) {\n e.preventDefault();\n onPick();\n }\n }\n },\n [disabled, onPick],\n );\n\n const isDisplay = mode === \"display\";\n\n const sortableIds = useMemo(() => items.map((f) => f.id), [items]);\n\n return (\n <div data-testid={`file-widget-${fieldName}`} className=\"flex flex-col gap-2\">\n {!isDisplay && selected.size > 0 && (\n <div\n className=\"flex items-center gap-2 rounded-md border border-border bg-surface-2 p-2 text-sm\"\n role=\"toolbar\"\n aria-label=\"Bulk actions\"\n >\n <span className=\"text-foreground\">{selected.size} selected</span>\n <button\n type=\"button\"\n className=\"rounded-sm border border-border bg-card px-2 py-1 text-xs text-destructive hover:bg-surface-2\"\n onClick={handleBulkDelete}\n data-testid=\"bulk-delete\"\n >\n Delete\n </button>\n <button\n type=\"button\"\n className=\"rounded-sm border border-border bg-card px-2 py-1 text-xs text-foreground hover:bg-surface-2\"\n onClick={() => setSelected(new Set())}\n >\n Clear\n </button>\n </div>\n )}\n\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n onDragEnd={handleDragEnd}\n >\n <SortableContext items={sortableIds} strategy={rectSortingStrategy}>\n <div\n className=\"grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-3 rounded-md border border-dashed border-border bg-surface p-3 outline-none focus-visible:outline-2 focus-visible:outline-accent\"\n role=\"grid\"\n aria-label={ariaLabel}\n tabIndex={isDisplay || disabled ? -1 : 0}\n onDragOver={onDragOver}\n onDrop={onDrop}\n onKeyDown={onGridKeyDown}\n data-testid=\"grid-container\"\n >\n {items.map((f, idx) => (\n <SortableTile\n key={f.id}\n file={f}\n selected={selected.has(f.id)}\n disabled={disabled || isDisplay}\n reorderable={reorderable && !isDisplay}\n preferredThumbnail={preferredThumbnail}\n onSelect={() => toggleSelect(f.id)}\n onRemove={() => handleRemove(f.id)}\n onPreview={() => setLightbox(idx)}\n />\n ))}\n {tiles.map((t) => (\n <PendingTile\n key={t.localId}\n tile={t}\n onCancel={() => {\n t.abort();\n cancelledUploadsRef.current.add(t.localId);\n setTiles((prev) =>\n prev.filter((x) => x.localId !== t.localId),\n );\n }}\n onDismiss={() =>\n setTiles((prev) =>\n prev.filter((x) => x.localId !== t.localId),\n )\n }\n />\n ))}\n {items.length === 0 && tiles.length === 0 && (\n <div\n className=\"col-span-full flex h-24 cursor-pointer items-center justify-center text-sm text-muted-foreground\"\n onClick={onPick}\n data-testid=\"grid-empty\"\n >\n {field.display?.placeholder || \"Drop files here or click to browse\"}\n </div>\n )}\n </div>\n </SortableContext>\n </DndContext>\n\n {!isDisplay && (\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={accept}\n multiple\n onChange={onChangeFile}\n style={{ display: \"none\" }}\n data-testid={`file-input-${fieldName}`}\n />\n )}\n\n {lightboxFile && (\n <Lightbox\n file={lightboxFile}\n hasPrev={lightbox! > 0}\n hasNext={lightbox! < items.length - 1}\n onPrev={lightboxPrev}\n onNext={lightboxNext}\n onClose={lightboxClose}\n />\n )}\n </div>\n );\n}\n\nfunction SortableTile({\n file,\n selected,\n disabled,\n reorderable,\n preferredThumbnail,\n onSelect,\n onRemove,\n onPreview,\n}: {\n file: HydratedFile;\n selected: boolean;\n disabled?: boolean;\n reorderable: boolean;\n preferredThumbnail?: string;\n onSelect: () => void;\n onRemove: () => void;\n onPreview: () => void;\n}) {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: file.id, disabled: !reorderable });\n const style: CSSProperties = {\n transform: CSS.Transform.toString(transform),\n transition,\n opacity: isDragging ? 0.5 : 1,\n };\n const url = thumbUrl(file, preferredThumbnail);\n return (\n <div\n ref={setNodeRef}\n style={style}\n className={`group relative aspect-square overflow-hidden rounded-md border ${\n selected ? \"border-accent\" : \"border-border\"\n } bg-surface-2`}\n data-testid={`grid-tile-${file.id}`}\n data-selected={selected || undefined}\n >\n {/* Lazy thumb: native loading=\"lazy\" approximates IntersectionObserver\n and is what the rest of the SDK uses (see ImageWidget). */}\n {url ? (\n <img\n src={url}\n alt={file.filename}\n className=\"h-full w-full cursor-pointer object-cover\"\n loading=\"lazy\"\n onClick={onPreview}\n />\n ) : (\n <div\n className=\"flex h-full w-full cursor-pointer items-center justify-center bg-surface-3 text-xs text-muted-foreground\"\n onClick={onPreview}\n >\n {file.filename}\n </div>\n )}\n {!disabled && (\n <>\n <input\n type=\"checkbox\"\n className=\"absolute left-1 top-1 h-4 w-4 cursor-pointer\"\n checked={selected}\n onChange={onSelect}\n aria-label={`Select ${file.filename}`}\n data-testid={`select-${file.id}`}\n onClick={(e) => e.stopPropagation()}\n />\n {reorderable && (\n <button\n type=\"button\"\n className=\"absolute right-1 top-1 cursor-grab rounded-sm border border-border bg-card px-1 text-xs\"\n aria-label={`Drag to reorder ${file.filename}`}\n data-testid={`drag-${file.id}`}\n {...attributes}\n {...listeners}\n >\n ⋮⋮\n </button>\n )}\n <div className=\"absolute inset-x-0 bottom-0 flex items-center justify-end gap-1 bg-black/50 p-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100\">\n <button\n type=\"button\"\n className=\"rounded-sm border border-border bg-card px-2 py-0.5 text-xs\"\n onClick={onPreview}\n >\n View\n </button>\n <button\n type=\"button\"\n className=\"rounded-sm border border-border bg-card px-2 py-0.5 text-xs text-destructive\"\n onClick={onRemove}\n data-testid={`remove-${file.id}`}\n >\n Delete\n </button>\n </div>\n </>\n )}\n </div>\n );\n}\n\nfunction PendingTile({\n tile,\n onCancel,\n onDismiss,\n}: {\n tile: InFlightTile;\n onCancel: () => void;\n onDismiss: () => void;\n}) {\n return (\n <div\n className={`relative flex aspect-square flex-col items-center justify-center rounded-md border ${\n tile.error ? \"border-destructive\" : \"border-border\"\n } bg-surface-2 p-2 text-center text-xs`}\n data-testid={`pending-tile-${tile.localId}`}\n >\n <span className=\"truncate\" title={tile.filename}>\n {tile.filename}\n </span>\n {tile.progress && !tile.error && (\n <span\n className=\"mt-1 text-muted-foreground\"\n role=\"progressbar\"\n aria-valuenow={tile.progress.pct}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n {tile.progress.pct}%\n </span>\n )}\n {tile.error && (\n <div role=\"alert\" className=\"mt-1 text-destructive\">\n {tile.error.message}\n </div>\n )}\n <button\n type=\"button\"\n className=\"mt-1 rounded-sm border border-border bg-card px-2 py-0.5\"\n onClick={tile.error ? onDismiss : onCancel}\n >\n {tile.error ? \"Dismiss\" : \"Cancel\"}\n </button>\n </div>\n );\n}\n\nfunction Lightbox({\n file,\n hasPrev,\n hasNext,\n onPrev,\n onNext,\n onClose,\n}: {\n file: HydratedFile;\n hasPrev: boolean;\n hasNext: boolean;\n onPrev: () => void;\n onNext: () => void;\n onClose: () => void;\n}) {\n const url = file.presigned_url ?? file.url ?? thumbUrl(file);\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/80\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={file.filename}\n data-testid=\"lightbox\"\n onClick={onClose}\n >\n <button\n type=\"button\"\n className=\"absolute right-4 top-4 rounded-sm border border-border bg-card px-3 py-1 text-foreground\"\n onClick={(e) => {\n e.stopPropagation();\n onClose();\n }}\n data-testid=\"lightbox-close\"\n >\n Close\n </button>\n {hasPrev && (\n <button\n type=\"button\"\n className=\"absolute left-4 rounded-sm border border-border bg-card px-3 py-2 text-foreground\"\n onClick={(e) => {\n e.stopPropagation();\n onPrev();\n }}\n data-testid=\"lightbox-prev\"\n >\n ‹\n </button>\n )}\n {hasNext && (\n <button\n type=\"button\"\n className=\"absolute right-4 bottom-4 rounded-sm border border-border bg-card px-3 py-2 text-foreground\"\n onClick={(e) => {\n e.stopPropagation();\n onNext();\n }}\n data-testid=\"lightbox-next\"\n >\n ›\n </button>\n )}\n {url ? (\n <img\n src={url}\n alt={file.filename}\n className=\"max-h-[90vh] max-w-[90vw] object-contain\"\n onClick={(e) => e.stopPropagation()}\n />\n ) : (\n <div className=\"rounded-md bg-card p-4 text-foreground\">\n {file.filename} ({formatBytes(file.size_bytes)})\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -29,7 +29,14 @@ export interface RunActionOptions {
29
29
  bulkSelection?: ReadonlyArray<Record<string, unknown>>;
30
30
  }
31
31
  interface ActionRunnerContextValue {
32
- run: (opts: RunActionOptions) => void;
32
+ /**
33
+ * Dispatch an action. Resolves when the action settles: for a direct-run
34
+ * action (no params, non-destructive) that is when `execute` finishes, so
35
+ * callers can await it to keep a trigger button disabled for the whole
36
+ * operation. For modal paths (params dialog / destructive confirm) it
37
+ * resolves immediately - the dialog owns its own pending UI.
38
+ */
39
+ run: (opts: RunActionOptions) => Promise<void>;
33
40
  }
34
41
  export declare function useActionRunner(): ActionRunnerContextValue;
35
42
  export declare function ActionRunnerProvider({ children }: {
@@ -26,6 +26,13 @@
26
26
  import type { ReactNode } from "react";
27
27
  import type { Action, Entity, Screen } from "../../types/schema";
28
28
  import type { ResolvedActionLayoutNode } from "../../lib/actions";
29
+ /**
30
+ * Action-trigger callback. Returns a promise when the caller dispatches an
31
+ * awaitable action (direct-run via ActionRunner); the bar awaits it so the
32
+ * button keeps its spinner/disabled state for the whole operation. Returns
33
+ * void for fire-and-forget caller paths.
34
+ */
35
+ export type ActionRunHandler = (code: string, action: Action) => void | Promise<void>;
29
36
  /**
30
37
  * Tab navigation options accepted by SDK tabNavigate. Kept loose here so the
31
38
  * caller can pass through the full TabMeta from useTabNavigate without forcing
@@ -102,7 +109,7 @@ export interface ResponsiveActionBarProps {
102
109
  /** Bulk context (list_toolbar with selection). */
103
110
  rowSelection?: unknown[];
104
111
  /** Called when the user triggers an action. */
105
- onRun: (code: string, action: Action) => void;
112
+ onRun: ActionRunHandler;
106
113
  /**
107
114
  * Width in px already consumed by caller-rendered edit/delete slots on the
108
115
  * right side of the container. The bar subtracts this before filling inline.
@@ -1,3 +1,3 @@
1
1
  /*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--color-black:#000;--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-medium:500;--font-weight-semibold:600;--radius-xs:var(--radius-xs);--radius-sm:var(--radius-sm);--radius-md:var(--radius-md);--radius-lg:var(--radius-lg);--radius-xl:var(--radius-xl);--shadow-xs:0 1px 2px 0 #0000000d;--shadow-md:0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;--shadow-lg:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.top-1{top:calc(var(--spacing) * 1)}.top-4{top:calc(var(--spacing) * 4)}.right-1{right:calc(var(--spacing) * 1)}.right-4{right:calc(var(--spacing) * 4)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-1{bottom:calc(var(--spacing) * 1)}.bottom-4{bottom:calc(var(--spacing) * 4)}.left-0{left:calc(var(--spacing) * 0)}.left-1{left:calc(var(--spacing) * 1)}.left-4{left:calc(var(--spacing) * 4)}.z-40{z-index:40}.z-50{z-index:50}.order-1{order:1}.col-span-full{grid-column:1/-1}.row-0{grid-row:0}.row-1{grid-row:1}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);margin-top:1.2em;margin-bottom:1.2em;font-size:1.25em;line-height:1.6}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em;list-style-type:decimal}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em;list-style-type:disc}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.25em;font-weight:600}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"“""”""‘""’";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em;font-style:italic;font-weight:500}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:0;margin-bottom:.888889em;font-size:2.25em;font-weight:800;line-height:1.11111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:2em;margin-bottom:1em;font-size:1.5em;font-weight:700;line-height:1.33333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.6em;margin-bottom:.6em;font-size:1.25em;font-weight:600;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.5em;margin-bottom:.5em;font-weight:600;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em;display:block}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-kbd);box-shadow:0 0 0 1px var(--tw-prose-kbd-shadows), 0 3px 0 var(--tw-prose-kbd-shadows);padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;border-radius:.3125rem;padding-inline-start:.375em;font-family:inherit;font-size:.875em;font-weight:500}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before,.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);padding-top:.857143em;padding-inline-end:1.14286em;padding-bottom:.857143em;border-radius:.375rem;margin-top:1.71429em;margin-bottom:1.71429em;padding-inline-start:1.14286em;font-size:.875em;font-weight:400;line-height:1.71429;overflow-x:auto}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit;background-color:#0000;border-width:0;border-radius:0;padding:0}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before,.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){table-layout:auto;width:100%;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.71429}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);vertical-align:bottom;padding-inline-end:.571429em;padding-bottom:.571429em;padding-inline-start:.571429em;font-weight:600}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);margin-top:.857143em;font-size:.875em;line-height:1.42857}.prose{--tw-prose-body:oklch(37.3% .034 259.733);--tw-prose-headings:oklch(21% .034 264.665);--tw-prose-lead:oklch(44.6% .03 256.802);--tw-prose-links:oklch(21% .034 264.665);--tw-prose-bold:oklch(21% .034 264.665);--tw-prose-counters:oklch(55.1% .027 264.364);--tw-prose-bullets:oklch(87.2% .01 258.338);--tw-prose-hr:oklch(92.8% .006 264.531);--tw-prose-quotes:oklch(21% .034 264.665);--tw-prose-quote-borders:oklch(92.8% .006 264.531);--tw-prose-captions:oklch(55.1% .027 264.364);--tw-prose-kbd:oklch(21% .034 264.665);--tw-prose-kbd-shadows:oklab(21% -.00316127 -.0338527/.1);--tw-prose-code:oklch(21% .034 264.665);--tw-prose-pre-code:oklch(92.8% .006 264.531);--tw-prose-pre-bg:oklch(27.8% .033 256.848);--tw-prose-th-borders:oklch(87.2% .01 258.338);--tw-prose-td-borders:oklch(92.8% .006 264.531);--tw-prose-invert-body:oklch(87.2% .01 258.338);--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:oklch(70.7% .022 261.325);--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:oklch(70.7% .022 261.325);--tw-prose-invert-bullets:oklch(44.6% .03 256.802);--tw-prose-invert-hr:oklch(37.3% .034 259.733);--tw-prose-invert-quotes:oklch(96.7% .003 264.542);--tw-prose-invert-quote-borders:oklch(37.3% .034 259.733);--tw-prose-invert-captions:oklch(70.7% .022 261.325);--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:#ffffff1a;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:oklch(87.2% .01 258.338);--tw-prose-invert-pre-bg:#00000080;--tw-prose-invert-th-borders:oklch(44.6% .03 256.802);--tw-prose-invert-td-borders:oklch(37.3% .034 259.733);font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.571429em;padding-inline-end:.571429em;padding-bottom:.571429em;padding-inline-start:.571429em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.71429}.prose-sm :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em;margin-bottom:1.14286em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.888889em;margin-bottom:.888889em;font-size:1.28571em;line-height:1.55556}.prose-sm :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.33333em;margin-bottom:1.33333em;padding-inline-start:1.11111em}.prose-sm :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:.8em;font-size:2.14286em;line-height:1.2}.prose-sm :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.6em;margin-bottom:.8em;font-size:1.42857em;line-height:1.4}.prose-sm :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.55556em;margin-bottom:.444444em;font-size:1.28571em;line-height:1.55556}.prose-sm :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.42857em;margin-bottom:.571429em;line-height:1.42857}.prose-sm :where(img):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.71429em;margin-bottom:1.71429em}.prose-sm :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.71429em;margin-bottom:1.71429em}.prose-sm :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.142857em;padding-inline-end:.357143em;padding-bottom:.142857em;border-radius:.3125rem;padding-inline-start:.357143em;font-size:.857143em}.prose-sm :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.857143em}.prose-sm :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.888889em}.prose-sm :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.666667em;padding-inline-end:1em;padding-bottom:.666667em;border-radius:.25rem;margin-top:1.66667em;margin-bottom:1.66667em;padding-inline-start:1em;font-size:.857143em;line-height:1.66667}.prose-sm :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em;margin-bottom:1.14286em;padding-inline-start:1.57143em}.prose-sm :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.285714em;margin-bottom:.285714em}.prose-sm :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.428571em}.prose-sm :where(.prose-sm>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.571429em;margin-bottom:.571429em}.prose-sm :where(.prose-sm>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em}.prose-sm :where(.prose-sm>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em}.prose-sm :where(.prose-sm>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em}.prose-sm :where(.prose-sm>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.571429em;margin-bottom:.571429em}.prose-sm :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em;margin-bottom:1.14286em}.prose-sm :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em}.prose-sm :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.285714em;padding-inline-start:1.57143em}.prose-sm :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2.85714em;margin-bottom:2.85714em}.prose-sm :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.857143em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.666667em;padding-inline-start:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.666667em;padding-inline-end:1em;padding-bottom:.666667em;padding-inline-start:1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.71429em;margin-bottom:1.71429em}.prose-sm :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.666667em;font-size:.857143em;line-height:1.33333}.prose-sm :where(.prose-sm>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose-sm>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.aspect-square{aspect-ratio:1}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-16{height:calc(var(--spacing) * 16)}.h-20{height:calc(var(--spacing) * 20)}.h-24{height:calc(var(--spacing) * 24)}.h-full{height:100%}.max-h-\[90vh\]{max-height:90vh}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-screen{min-height:100vh}.w-1{width:calc(var(--spacing) * 1)}.w-2{width:calc(var(--spacing) * 2)}.w-2\/3{width:66.6667%}.w-3{width:calc(var(--spacing) * 3)}.w-4{width:calc(var(--spacing) * 4)}.w-16{width:calc(var(--spacing) * 16)}.w-\[320px\]{width:320px}.w-full{width:100%}.max-w-\[90vw\]{max-width:90vw}.max-w-none{max-width:none}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.flex-none{flex:none}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-col-resize{cursor:col-resize}.cursor-grab{cursor:grab}.cursor-pointer{cursor:pointer}.resize{resize:both}.columns-3{columns:3}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-\[repeat\(auto-fill\,minmax\(140px\,1fr\)\)\]{grid-template-columns:repeat(auto-fill,minmax(140px,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-y-3{row-gap:calc(var(--spacing) * 3)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-divider>:not(:last-child)){border-color:var(--divider)}.self-start{align-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent{border-color:var(--accent)}.border-border{border-color:var(--border)}.border-destructive{border-color:var(--danger)}.border-divider{border-color:var(--divider)}.border-transparent{border-color:#0000}.border-white{border-color:var(--color-white)}.bg-black\/30{background-color:#0000004d}@supports (color:color-mix(in lab, red, red)){.bg-black\/30{background-color:color-mix(in oklab, var(--color-black) 30%, transparent)}}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab, red, red)){.bg-black\/40{background-color:color-mix(in oklab, var(--color-black) 40%, transparent)}}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab, red, red)){.bg-black\/50{background-color:color-mix(in oklab, var(--color-black) 50%, transparent)}}.bg-black\/70{background-color:#000000b3}@supports (color:color-mix(in lab, red, red)){.bg-black\/70{background-color:color-mix(in oklab, var(--color-black) 70%, transparent)}}.bg-black\/80{background-color:#000c}@supports (color:color-mix(in lab, red, red)){.bg-black\/80{background-color:color-mix(in oklab, var(--color-black) 80%, transparent)}}.bg-card{background-color:var(--surface)}.bg-destructive-soft{background-color:var(--danger-soft)}.bg-muted{background-color:var(--surface-2)}.bg-success-soft{background-color:var(--success-soft)}.bg-surface{background-color:var(--surface)}.bg-surface-2{background-color:var(--surface-2)}.bg-surface-3{background-color:var(--surface-3)}.bg-warning{background-color:var(--warn)}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.text-accent{color:var(--accent)}.text-destructive{color:var(--danger)}.text-foreground{color:var(--text)}.text-muted-foreground{color:var(--text-3)}.text-success{color:var(--success)}.text-text-3{color:var(--text-3)}.text-text-4{color:var(--text-4)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-text{-webkit-user-select:text;user-select:text}.inline-fit{inline-size:fit-content}.group-focus-within\:opacity-100:is(:where(.group):focus-within *){opacity:1}@media (hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.focus-within\:opacity-100:focus-within{opacity:1}@media (hover:hover){.hover\:border-border:hover{border-color:var(--border)}.hover\:bg-border:hover{background-color:var(--border)}.hover\:bg-surface:hover{background-color:var(--surface)}.hover\:bg-surface-2:hover{background-color:var(--surface-2)}.hover\:text-text-3:hover{color:var(--text-3)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}}.focus-visible\:outline:focus-visible{outline-style:var(--tw-outline-style);outline-width:1px}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-accent:focus-visible{outline-color:var(--accent)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media (width>=48rem){.md\:w-40{width:calc(var(--spacing) * 40)}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:pt-0\.5{padding-top:calc(var(--spacing) * .5)}}.dark\:prose-invert:where([data-theme=dark],[data-theme=dark] *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}}:root{--bg:#f7f8fa;--surface:#fff;--surface-2:#fbfbfd;--surface-3:#f3f4f7;--border:#e6e8ee;--border-strong:#d1d5de;--divider:#eef0f4;--text:#0e1116;--text-2:#2a2f3a;--text-3:#5b6270;--text-4:#8a8f9c;--text-placeholder:#a8adba;--muted:var(--surface-2);--muted-foreground:var(--text-3);--card:var(--surface);--card-foreground:var(--text);--popover:var(--surface);--popover-foreground:var(--text);--secondary:var(--surface-2);--secondary-foreground:var(--text-2);--input:var(--surface);--ring:var(--accent-ring);--primary:#1e2a4a;--primary-hover:#16213d;--primary-fg:#fff;--accent:#5b5bd6;--accent-2:#7b7be6;--accent-foreground:#fff;--accent-soft:#eeeefb;--accent-ring:#5b5bd647;--destructive:var(--danger);--destructive-foreground:#fff;--row-selected-bg:#eeeefb;--success:#118a5a;--success-soft:#e3f4ec;--warn:#b56b00;--warn-soft:#fbf1e0;--danger:#c2362c;--danger-soft:#fae8e6;--danger-hover:#a02a21;--info:#0b6fb0;--info-soft:#e4f1fa;--pill-indigo:#4f46e5;--pill-indigo-bg:#eef2ff;--pill-emerald:#047857;--pill-emerald-bg:#ecfdf5;--pill-amber:#b45309;--pill-amber-bg:#fef3c7;--pill-rose:#be123c;--pill-rose-bg:#fff1f2;--pill-sky:#0369a1;--pill-sky-bg:#e0f2fe;--pill-violet:#6d28d9;--pill-violet-bg:#f3e8ff;--pill-slate:#475569;--pill-slate-bg:#f1f5f9;--pill-teal:#0f766e;--pill-teal-bg:#ccfbf1;--rail:#0e1116;--rail-fg:#d6d9e0;--rail-muted:#6b707e;--rail-active:#1f232d;--rail-hover:#161a22;--sidebar:#fff;--sidebar-fg:#1e2a4a;--sidebar-muted:#6b7180;--sidebar-active:#f1f1fb;--sidebar-hover:#f4f5f8;--shadow-xs:0 1px 0 #0c0e140a;--shadow-sm:0 1px 2px #0c0e140f, 0 1px 2px #0c0e140a;--shadow-md:0 4px 12px #0c0e140f, 0 1px 3px #0c0e140a;--shadow-lg:0 16px 48px #0c0e1424, 0 4px 12px #0c0e1414;--shadow-panel:0 1px 0 #0c0e140a, 0 0 0 1px var(--border);--scrim:#0c0e1459;--scrim-strong:#0c0e1473;--scrim-lite:#0c0e1433;--inverted-overlay:#ffffff1f;--radius-xs:3px;--radius-sm:5px;--radius-md:7px;--radius-lg:10px;--radius-xl:14px;--row-h:32px;--row-h-comf:40px;--row-h-cozy:48px;--topbar-h:44px;--tabbar-h:34px;--rail-w:52px;--sidebar-w:220px;--font-sans:"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono:"JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;--impersonation-accent:#f59e0b;--impersonation-accent-soft:#f59e0b29;--impersonation-accent-fg:#92400e}body[data-impersonation-destructive=true]{--impersonation-accent:#ef4444;--impersonation-accent-soft:#ef444429;--impersonation-accent-fg:#7f1d1d}[data-theme=dark]{--bg:#0a0c10;--surface:#181c26;--surface-2:#111318;--surface-3:#20253a;--border:#262c3c;--border-strong:#353c52;--divider:#1a1e2c;--text:#e8eaf0;--text-2:#c4c8d2;--text-3:#8a90a0;--text-4:#5f6578;--text-placeholder:#4d5263;--primary:#e8eaf0;--primary-hover:#fff;--primary-fg:#0a0c10;--accent:#8b8bf0;--accent-2:#a5a5f5;--accent-foreground:#0a0c10;--accent-soft:#8b8bf024;--accent-ring:#8b8bf059;--destructive-foreground:#0a0c10;--success:#3fbf8f;--success-soft:#3fbf8f29;--warn:#e0a44a;--warn-soft:#e0a44a29;--danger:#ef6a60;--danger-soft:#ef6a6029;--danger-hover:#f48a82;--info:#5ab3ea;--info-soft:#5ab3ea29;--pill-indigo:#a5b4fc;--pill-indigo-bg:#4f46e538;--pill-emerald:#6ee7b7;--pill-emerald-bg:#04785738;--pill-amber:#fcd34d;--pill-amber-bg:#b4530942;--pill-rose:#fda4af;--pill-rose-bg:#be123c3d;--pill-sky:#7dd3fc;--pill-sky-bg:#0369a142;--pill-violet:#c4b5fd;--pill-violet-bg:#6d28d942;--pill-slate:#cbd5e1;--pill-slate-bg:#47556952;--pill-teal:#5eead4;--pill-teal-bg:#0f766e42;--rail:#06080c;--rail-fg:#c4c8d2;--rail-muted:#5f6578;--rail-active:#1c2030;--rail-hover:#14171e;--sidebar:#0e1018;--sidebar-fg:#e8eaf0;--sidebar-muted:#8a90a0;--sidebar-active:#8b8bf02e;--sidebar-hover:#161a24;--shadow-xs:inset 0 1px 0 #ffffff0f;--shadow-sm:0 2px 8px #00000073, inset 0 1px 0 #ffffff0d;--shadow-md:0 4px 16px #00000080, inset 0 1px 0 #ffffff0d;--shadow-lg:0 16px 48px #000000a6, 0 2px 8px #0006;--shadow-panel:0 0 0 1px var(--border), inset 0 1px 0 #ffffff0a;--scrim:#0000008c;--scrim-strong:#000000a6;--scrim-lite:#0006;--inverted-overlay:#0000001a;--row-selected-bg:var(--accent)}@supports (color:color-mix(in lab, red, red)){[data-theme=dark]{--row-selected-bg:color-mix(in srgb, var(--accent) 22%, var(--surface))}}[data-accent=violet]{--accent:#5b5bd6;--accent-2:#7b7be6;--accent-soft:#eeeefb;--accent-ring:#5b5bd647}[data-accent=blue]{--accent:#2563eb;--accent-2:#4f83f0;--accent-soft:#e7effd;--accent-ring:#2563eb47}[data-accent=teal]{--accent:#0d9488;--accent-2:#14b8a6;--accent-soft:#d8f2ef;--accent-ring:#0d948847}[data-accent=amber]{--accent:#b45309;--accent-2:#d97706;--accent-soft:#fbf1e0;--accent-ring:#b4530947}[data-accent=rose]{--accent:#be123c;--accent-2:#e11d48;--accent-soft:#fce7ec;--accent-ring:#be123c47}[data-theme=dark][data-accent=violet]{--accent:#8b8bf0;--accent-2:#a5a5f5;--accent-soft:#8b8bf024;--accent-ring:#8b8bf059}[data-theme=dark][data-accent=blue]{--accent:#60a5fa;--accent-2:#93c5fd;--accent-soft:#2563eb29;--accent-ring:#3b82f659}[data-theme=dark][data-accent=teal]{--accent:#2dd4bf;--accent-2:#5eead4;--accent-soft:#0d948829;--accent-ring:#14b8a659}[data-theme=dark][data-accent=amber]{--accent:#fcd34d;--accent-2:#fde68a;--accent-soft:#b453092e;--accent-ring:#d9770659}[data-theme=dark][data-accent=rose]{--accent:#fda4af;--accent-2:#fecdd3;--accent-soft:#be123c2e;--accent-ring:#e11d4859}[data-density=comfortable]{--row-h:var(--row-h-comf)}[data-density=cozy]{--row-h:var(--row-h-cozy)}html[data-zebra=on] table tbody tr:nth-child(2n)>td{background:var(--surface-2)}*{box-sizing:border-box}html,body{height:100%;margin:0}body{font-family:var(--font-sans);color:var(--text);background:var(--bg);-webkit-font-smoothing:antialiased;font-feature-settings:"cv11", "ss01", "ss03";letter-spacing:-.005em;font-size:13px}::selection{background:var(--accent-soft);color:var(--text)}button{font-family:inherit;font-size:inherit;letter-spacing:inherit}input,textarea,select{font-family:inherit;font-size:inherit;color:inherit;letter-spacing:inherit}.mono{font-family:var(--font-mono);font-feature-settings:"zero","ss01"}.num{font-variant-numeric:tabular-nums}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--border-strong);background-clip:padding-box;border:2px solid #0000;border-radius:8px}::-webkit-scrollbar-thumb:hover{background:var(--text-4);background-clip:padding-box;border:2px solid #0000}#app{grid-template-rows:var(--topbar-h) 1fr;grid-template-columns:var(--rail-w) var(--sidebar-w) 1fr;grid-template-areas:"topbar topbar topbar""rail sidebar main";height:100vh;display:grid;overflow:hidden}#app[data-sidebar=collapsed],#app[data-sidebar=icon-only]{grid-template-columns:var(--rail-w) 56px 1fr}#app[data-sidebar=hidden]{grid-template-columns:var(--rail-w) 0 1fr}.prose pre{background-color:var(--surface-3)!important;color:var(--text)!important}.prose code{color:var(--text)!important}.json-editor-readonly .jse-main{border:1px solid var(--border);border-radius:var(--radius-md);min-height:80px;max-height:300px}.json-editor-editable{resize:vertical;min-height:150px;max-height:500px;overflow:hidden}.json-editor-editable .jse-main{border:1px solid var(--border);border-radius:var(--radius-md);height:100%}.sl-row-actions{opacity:0;transition:opacity .1s}tr:hover .sl-row-actions,.sl-row-actions[data-open=true]{opacity:1}.peek-pencil{opacity:0;pointer-events:none;transition:opacity .12s}.peek-field-cell:hover .peek-pencil,.peek-field-cell:focus-within .peek-pencil,.peek-field-cell[data-editing=true] .peek-pencil{opacity:1;pointer-events:auto}@media (hover:none){.peek-pencil{opacity:1;pointer-events:auto}}.json-editor-readonly *,.json-editor-editable *{border-color:initial}.agent-highlight{animation:4s ease-out forwards agent-highlight-glow}@keyframes agent-highlight-glow{0%{box-shadow:0 0 0 2px rgb(var(--primary));background:rgb(var(--primary) / .08)}to{background:0 0;box-shadow:0 0 #0000}}.agent-attention{animation:2s ease-out forwards agent-attention-pulse}@keyframes agent-attention-pulse{0%,to{outline:2px solid #0000}50%{outline:2px solid rgb(var(--primary))}}@keyframes agent-blink{0%,50%{opacity:1}51%,to{opacity:0}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--color-black:#000;--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-medium:500;--font-weight-semibold:600;--radius-xs:var(--radius-xs);--radius-sm:var(--radius-sm);--radius-md:var(--radius-md);--radius-lg:var(--radius-lg);--radius-xl:var(--radius-xl);--shadow-xs:0 1px 2px 0 #0000000d;--shadow-md:0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;--shadow-lg:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.top-1{top:calc(var(--spacing) * 1)}.top-4{top:calc(var(--spacing) * 4)}.right-1{right:calc(var(--spacing) * 1)}.right-4{right:calc(var(--spacing) * 4)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-1{bottom:calc(var(--spacing) * 1)}.bottom-4{bottom:calc(var(--spacing) * 4)}.left-0{left:calc(var(--spacing) * 0)}.left-1{left:calc(var(--spacing) * 1)}.left-4{left:calc(var(--spacing) * 4)}.z-40{z-index:40}.z-50{z-index:50}.order-1{order:1}.col-span-full{grid-column:1/-1}.row-0{grid-row:0}.row-1{grid-row:1}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);margin-top:1.2em;margin-bottom:1.2em;font-size:1.25em;line-height:1.6}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em;list-style-type:decimal}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em;list-style-type:disc}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.25em;font-weight:600}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"“""”""‘""’";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em;font-style:italic;font-weight:500}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:0;margin-bottom:.888889em;font-size:2.25em;font-weight:800;line-height:1.11111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:2em;margin-bottom:1em;font-size:1.5em;font-weight:700;line-height:1.33333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.6em;margin-bottom:.6em;font-size:1.25em;font-weight:600;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.5em;margin-bottom:.5em;font-weight:600;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em;display:block}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-kbd);box-shadow:0 0 0 1px var(--tw-prose-kbd-shadows), 0 3px 0 var(--tw-prose-kbd-shadows);padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;border-radius:.3125rem;padding-inline-start:.375em;font-family:inherit;font-size:.875em;font-weight:500}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before,.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);padding-top:.857143em;padding-inline-end:1.14286em;padding-bottom:.857143em;border-radius:.375rem;margin-top:1.71429em;margin-bottom:1.71429em;padding-inline-start:1.14286em;font-size:.875em;font-weight:400;line-height:1.71429;overflow-x:auto}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit;background-color:#0000;border-width:0;border-radius:0;padding:0}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before,.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){table-layout:auto;width:100%;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.71429}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);vertical-align:bottom;padding-inline-end:.571429em;padding-bottom:.571429em;padding-inline-start:.571429em;font-weight:600}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);margin-top:.857143em;font-size:.875em;line-height:1.42857}.prose{--tw-prose-body:oklch(37.3% .034 259.733);--tw-prose-headings:oklch(21% .034 264.665);--tw-prose-lead:oklch(44.6% .03 256.802);--tw-prose-links:oklch(21% .034 264.665);--tw-prose-bold:oklch(21% .034 264.665);--tw-prose-counters:oklch(55.1% .027 264.364);--tw-prose-bullets:oklch(87.2% .01 258.338);--tw-prose-hr:oklch(92.8% .006 264.531);--tw-prose-quotes:oklch(21% .034 264.665);--tw-prose-quote-borders:oklch(92.8% .006 264.531);--tw-prose-captions:oklch(55.1% .027 264.364);--tw-prose-kbd:oklch(21% .034 264.665);--tw-prose-kbd-shadows:oklab(21% -.00316127 -.0338527/.1);--tw-prose-code:oklch(21% .034 264.665);--tw-prose-pre-code:oklch(92.8% .006 264.531);--tw-prose-pre-bg:oklch(27.8% .033 256.848);--tw-prose-th-borders:oklch(87.2% .01 258.338);--tw-prose-td-borders:oklch(92.8% .006 264.531);--tw-prose-invert-body:oklch(87.2% .01 258.338);--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:oklch(70.7% .022 261.325);--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:oklch(70.7% .022 261.325);--tw-prose-invert-bullets:oklch(44.6% .03 256.802);--tw-prose-invert-hr:oklch(37.3% .034 259.733);--tw-prose-invert-quotes:oklch(96.7% .003 264.542);--tw-prose-invert-quote-borders:oklch(37.3% .034 259.733);--tw-prose-invert-captions:oklch(70.7% .022 261.325);--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:#ffffff1a;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:oklch(87.2% .01 258.338);--tw-prose-invert-pre-bg:#00000080;--tw-prose-invert-th-borders:oklch(44.6% .03 256.802);--tw-prose-invert-td-borders:oklch(37.3% .034 259.733);font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.571429em;padding-inline-end:.571429em;padding-bottom:.571429em;padding-inline-start:.571429em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.71429}.prose-sm :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em;margin-bottom:1.14286em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.888889em;margin-bottom:.888889em;font-size:1.28571em;line-height:1.55556}.prose-sm :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.33333em;margin-bottom:1.33333em;padding-inline-start:1.11111em}.prose-sm :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:.8em;font-size:2.14286em;line-height:1.2}.prose-sm :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.6em;margin-bottom:.8em;font-size:1.42857em;line-height:1.4}.prose-sm :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.55556em;margin-bottom:.444444em;font-size:1.28571em;line-height:1.55556}.prose-sm :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.42857em;margin-bottom:.571429em;line-height:1.42857}.prose-sm :where(img):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.71429em;margin-bottom:1.71429em}.prose-sm :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.71429em;margin-bottom:1.71429em}.prose-sm :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.142857em;padding-inline-end:.357143em;padding-bottom:.142857em;border-radius:.3125rem;padding-inline-start:.357143em;font-size:.857143em}.prose-sm :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.857143em}.prose-sm :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.888889em}.prose-sm :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.666667em;padding-inline-end:1em;padding-bottom:.666667em;border-radius:.25rem;margin-top:1.66667em;margin-bottom:1.66667em;padding-inline-start:1em;font-size:.857143em;line-height:1.66667}.prose-sm :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em;margin-bottom:1.14286em;padding-inline-start:1.57143em}.prose-sm :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.285714em;margin-bottom:.285714em}.prose-sm :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.428571em}.prose-sm :where(.prose-sm>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.571429em;margin-bottom:.571429em}.prose-sm :where(.prose-sm>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em}.prose-sm :where(.prose-sm>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em}.prose-sm :where(.prose-sm>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em}.prose-sm :where(.prose-sm>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.571429em;margin-bottom:.571429em}.prose-sm :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em;margin-bottom:1.14286em}.prose-sm :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em}.prose-sm :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.285714em;padding-inline-start:1.57143em}.prose-sm :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2.85714em;margin-bottom:2.85714em}.prose-sm :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose-sm :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.857143em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.666667em;padding-inline-start:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.666667em;padding-inline-end:1em;padding-bottom:.666667em;padding-inline-start:1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.71429em;margin-bottom:1.71429em}.prose-sm :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.666667em;font-size:.857143em;line-height:1.33333}.prose-sm :where(.prose-sm>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose-sm>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.aspect-square{aspect-ratio:1}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-16{height:calc(var(--spacing) * 16)}.h-20{height:calc(var(--spacing) * 20)}.h-24{height:calc(var(--spacing) * 24)}.h-full{height:100%}.max-h-\[90vh\]{max-height:90vh}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-screen{min-height:100vh}.w-1{width:calc(var(--spacing) * 1)}.w-2{width:calc(var(--spacing) * 2)}.w-2\/3{width:66.6667%}.w-3{width:calc(var(--spacing) * 3)}.w-4{width:calc(var(--spacing) * 4)}.w-16{width:calc(var(--spacing) * 16)}.w-\[320px\]{width:320px}.w-full{width:100%}.max-w-\[90vw\]{max-width:90vw}.max-w-none{max-width:none}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.flex-none{flex:none}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-col-resize{cursor:col-resize}.cursor-grab{cursor:grab}.cursor-pointer{cursor:pointer}.resize{resize:both}.columns-3{columns:3}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-\[repeat\(auto-fill\,minmax\(140px\,1fr\)\)\]{grid-template-columns:repeat(auto-fill,minmax(140px,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-y-3{row-gap:calc(var(--spacing) * 3)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-divider>:not(:last-child)){border-color:var(--divider)}.self-start{align-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent{border-color:var(--accent)}.border-border{border-color:var(--border)}.border-destructive{border-color:var(--danger)}.border-divider{border-color:var(--divider)}.border-transparent{border-color:#0000}.border-white{border-color:var(--color-white)}.bg-black\/30{background-color:#0000004d}@supports (color:color-mix(in lab, red, red)){.bg-black\/30{background-color:color-mix(in oklab, var(--color-black) 30%, transparent)}}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab, red, red)){.bg-black\/40{background-color:color-mix(in oklab, var(--color-black) 40%, transparent)}}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab, red, red)){.bg-black\/50{background-color:color-mix(in oklab, var(--color-black) 50%, transparent)}}.bg-black\/70{background-color:#000000b3}@supports (color:color-mix(in lab, red, red)){.bg-black\/70{background-color:color-mix(in oklab, var(--color-black) 70%, transparent)}}.bg-black\/80{background-color:#000c}@supports (color:color-mix(in lab, red, red)){.bg-black\/80{background-color:color-mix(in oklab, var(--color-black) 80%, transparent)}}.bg-card{background-color:var(--surface)}.bg-destructive-soft{background-color:var(--danger-soft)}.bg-muted{background-color:var(--surface-2)}.bg-success-soft{background-color:var(--success-soft)}.bg-surface{background-color:var(--surface)}.bg-surface-2{background-color:var(--surface-2)}.bg-surface-3{background-color:var(--surface-3)}.bg-warning{background-color:var(--warn)}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.text-accent{color:var(--accent)}.text-destructive{color:var(--danger)}.text-foreground{color:var(--text)}.text-muted-foreground{color:var(--text-3)}.text-success{color:var(--success)}.text-text-3{color:var(--text-3)}.text-text-4{color:var(--text-4)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.inline-fit{inline-size:fit-content}.group-focus-within\:opacity-100:is(:where(.group):focus-within *){opacity:1}@media (hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.focus-within\:opacity-100:focus-within{opacity:1}@media (hover:hover){.hover\:border-border:hover{border-color:var(--border)}.hover\:bg-border:hover{background-color:var(--border)}.hover\:bg-surface:hover{background-color:var(--surface)}.hover\:bg-surface-2:hover{background-color:var(--surface-2)}.hover\:text-text-3:hover{color:var(--text-3)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}}.focus-visible\:outline:focus-visible{outline-style:var(--tw-outline-style);outline-width:1px}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-accent:focus-visible{outline-color:var(--accent)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media (width>=48rem){.md\:w-40{width:calc(var(--spacing) * 40)}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:pt-0\.5{padding-top:calc(var(--spacing) * .5)}}.dark\:prose-invert:where([data-theme=dark],[data-theme=dark] *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}}:root{--bg:#f7f8fa;--surface:#fff;--surface-2:#fbfbfd;--surface-3:#f3f4f7;--border:#e6e8ee;--border-strong:#d1d5de;--divider:#eef0f4;--text:#0e1116;--text-2:#2a2f3a;--text-3:#5b6270;--text-4:#8a8f9c;--text-placeholder:#a8adba;--muted:var(--surface-2);--muted-foreground:var(--text-3);--card:var(--surface);--card-foreground:var(--text);--popover:var(--surface);--popover-foreground:var(--text);--secondary:var(--surface-2);--secondary-foreground:var(--text-2);--input:var(--surface);--ring:var(--accent-ring);--primary:#1e2a4a;--primary-hover:#16213d;--primary-fg:#fff;--accent:#5b5bd6;--accent-2:#7b7be6;--accent-foreground:#fff;--accent-soft:#eeeefb;--accent-ring:#5b5bd647;--destructive:var(--danger);--destructive-foreground:#fff;--row-selected-bg:#eeeefb;--success:#118a5a;--success-soft:#e3f4ec;--warn:#b56b00;--warn-soft:#fbf1e0;--danger:#c2362c;--danger-soft:#fae8e6;--danger-hover:#a02a21;--info:#0b6fb0;--info-soft:#e4f1fa;--pill-indigo:#4f46e5;--pill-indigo-bg:#eef2ff;--pill-emerald:#047857;--pill-emerald-bg:#ecfdf5;--pill-amber:#b45309;--pill-amber-bg:#fef3c7;--pill-rose:#be123c;--pill-rose-bg:#fff1f2;--pill-sky:#0369a1;--pill-sky-bg:#e0f2fe;--pill-violet:#6d28d9;--pill-violet-bg:#f3e8ff;--pill-slate:#475569;--pill-slate-bg:#f1f5f9;--pill-teal:#0f766e;--pill-teal-bg:#ccfbf1;--rail:#0e1116;--rail-fg:#d6d9e0;--rail-muted:#6b707e;--rail-active:#1f232d;--rail-hover:#161a22;--sidebar:#fff;--sidebar-fg:#1e2a4a;--sidebar-muted:#6b7180;--sidebar-active:#f1f1fb;--sidebar-hover:#f4f5f8;--shadow-xs:0 1px 0 #0c0e140a;--shadow-sm:0 1px 2px #0c0e140f, 0 1px 2px #0c0e140a;--shadow-md:0 4px 12px #0c0e140f, 0 1px 3px #0c0e140a;--shadow-lg:0 16px 48px #0c0e1424, 0 4px 12px #0c0e1414;--shadow-panel:0 1px 0 #0c0e140a, 0 0 0 1px var(--border);--scrim:#0c0e1459;--scrim-strong:#0c0e1473;--scrim-lite:#0c0e1433;--inverted-overlay:#ffffff1f;--radius-xs:3px;--radius-sm:5px;--radius-md:7px;--radius-lg:10px;--radius-xl:14px;--row-h:32px;--row-h-comf:40px;--row-h-cozy:48px;--topbar-h:44px;--tabbar-h:34px;--rail-w:52px;--sidebar-w:220px;--font-sans:"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono:"JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;--impersonation-accent:#f59e0b;--impersonation-accent-soft:#f59e0b29;--impersonation-accent-fg:#92400e}body[data-impersonation-destructive=true]{--impersonation-accent:#ef4444;--impersonation-accent-soft:#ef444429;--impersonation-accent-fg:#7f1d1d}[data-theme=dark]{--bg:#0a0c10;--surface:#181c26;--surface-2:#111318;--surface-3:#20253a;--border:#262c3c;--border-strong:#353c52;--divider:#1a1e2c;--text:#e8eaf0;--text-2:#c4c8d2;--text-3:#8a90a0;--text-4:#5f6578;--text-placeholder:#4d5263;--primary:#e8eaf0;--primary-hover:#fff;--primary-fg:#0a0c10;--accent:#8b8bf0;--accent-2:#a5a5f5;--accent-foreground:#0a0c10;--accent-soft:#8b8bf024;--accent-ring:#8b8bf059;--destructive-foreground:#0a0c10;--success:#3fbf8f;--success-soft:#3fbf8f29;--warn:#e0a44a;--warn-soft:#e0a44a29;--danger:#ef6a60;--danger-soft:#ef6a6029;--danger-hover:#f48a82;--info:#5ab3ea;--info-soft:#5ab3ea29;--pill-indigo:#a5b4fc;--pill-indigo-bg:#4f46e538;--pill-emerald:#6ee7b7;--pill-emerald-bg:#04785738;--pill-amber:#fcd34d;--pill-amber-bg:#b4530942;--pill-rose:#fda4af;--pill-rose-bg:#be123c3d;--pill-sky:#7dd3fc;--pill-sky-bg:#0369a142;--pill-violet:#c4b5fd;--pill-violet-bg:#6d28d942;--pill-slate:#cbd5e1;--pill-slate-bg:#47556952;--pill-teal:#5eead4;--pill-teal-bg:#0f766e42;--rail:#06080c;--rail-fg:#c4c8d2;--rail-muted:#5f6578;--rail-active:#1c2030;--rail-hover:#14171e;--sidebar:#0e1018;--sidebar-fg:#e8eaf0;--sidebar-muted:#8a90a0;--sidebar-active:#8b8bf02e;--sidebar-hover:#161a24;--shadow-xs:inset 0 1px 0 #ffffff0f;--shadow-sm:0 2px 8px #00000073, inset 0 1px 0 #ffffff0d;--shadow-md:0 4px 16px #00000080, inset 0 1px 0 #ffffff0d;--shadow-lg:0 16px 48px #000000a6, 0 2px 8px #0006;--shadow-panel:0 0 0 1px var(--border), inset 0 1px 0 #ffffff0a;--scrim:#0000008c;--scrim-strong:#000000a6;--scrim-lite:#0006;--inverted-overlay:#0000001a;--row-selected-bg:var(--accent)}@supports (color:color-mix(in lab, red, red)){[data-theme=dark]{--row-selected-bg:color-mix(in srgb, var(--accent) 22%, var(--surface))}}[data-accent=violet]{--accent:#5b5bd6;--accent-2:#7b7be6;--accent-soft:#eeeefb;--accent-ring:#5b5bd647}[data-accent=blue]{--accent:#2563eb;--accent-2:#4f83f0;--accent-soft:#e7effd;--accent-ring:#2563eb47}[data-accent=teal]{--accent:#0d9488;--accent-2:#14b8a6;--accent-soft:#d8f2ef;--accent-ring:#0d948847}[data-accent=amber]{--accent:#b45309;--accent-2:#d97706;--accent-soft:#fbf1e0;--accent-ring:#b4530947}[data-accent=rose]{--accent:#be123c;--accent-2:#e11d48;--accent-soft:#fce7ec;--accent-ring:#be123c47}[data-theme=dark][data-accent=violet]{--accent:#8b8bf0;--accent-2:#a5a5f5;--accent-soft:#8b8bf024;--accent-ring:#8b8bf059}[data-theme=dark][data-accent=blue]{--accent:#60a5fa;--accent-2:#93c5fd;--accent-soft:#2563eb29;--accent-ring:#3b82f659}[data-theme=dark][data-accent=teal]{--accent:#2dd4bf;--accent-2:#5eead4;--accent-soft:#0d948829;--accent-ring:#14b8a659}[data-theme=dark][data-accent=amber]{--accent:#fcd34d;--accent-2:#fde68a;--accent-soft:#b453092e;--accent-ring:#d9770659}[data-theme=dark][data-accent=rose]{--accent:#fda4af;--accent-2:#fecdd3;--accent-soft:#be123c2e;--accent-ring:#e11d4859}[data-density=comfortable]{--row-h:var(--row-h-comf)}[data-density=cozy]{--row-h:var(--row-h-cozy)}html[data-zebra=on] table tbody tr:nth-child(2n)>td{background:var(--surface-2)}*{box-sizing:border-box}html,body{height:100%;margin:0}body{font-family:var(--font-sans);color:var(--text);background:var(--bg);-webkit-font-smoothing:antialiased;font-feature-settings:"cv11", "ss01", "ss03";letter-spacing:-.005em;font-size:13px}::selection{background:var(--accent-soft);color:var(--text)}button{font-family:inherit;font-size:inherit;letter-spacing:inherit}input,textarea,select{font-family:inherit;font-size:inherit;color:inherit;letter-spacing:inherit}.mono{font-family:var(--font-mono);font-feature-settings:"zero","ss01"}.num{font-variant-numeric:tabular-nums}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--border-strong);background-clip:padding-box;border:2px solid #0000;border-radius:8px}::-webkit-scrollbar-thumb:hover{background:var(--text-4);background-clip:padding-box;border:2px solid #0000}#app{grid-template-rows:var(--topbar-h) 1fr;grid-template-columns:var(--rail-w) var(--sidebar-w) 1fr;grid-template-areas:"topbar topbar topbar""rail sidebar main";height:100vh;display:grid;overflow:hidden}#app[data-sidebar=collapsed],#app[data-sidebar=icon-only]{grid-template-columns:var(--rail-w) 56px 1fr}#app[data-sidebar=hidden]{grid-template-columns:var(--rail-w) 0 1fr}.prose pre{background-color:var(--surface-3)!important;color:var(--text)!important}.prose code{color:var(--text)!important}.json-editor-readonly .jse-main{border:1px solid var(--border);border-radius:var(--radius-md);min-height:80px;max-height:300px}.json-editor-editable{resize:vertical;min-height:150px;max-height:500px;overflow:hidden}.json-editor-editable .jse-main{border:1px solid var(--border);border-radius:var(--radius-md);height:100%}.sl-row-actions{opacity:0;transition:opacity .1s}tr:hover .sl-row-actions,.sl-row-actions[data-open=true]{opacity:1}.peek-pencil{opacity:0;pointer-events:none;transition:opacity .12s}.peek-field-cell:hover .peek-pencil,.peek-field-cell:focus-within .peek-pencil,.peek-field-cell[data-editing=true] .peek-pencil{opacity:1;pointer-events:auto}@media (hover:none){.peek-pencil{opacity:1;pointer-events:auto}}.json-editor-readonly *,.json-editor-editable *{border-color:initial}.agent-highlight{animation:4s ease-out forwards agent-highlight-glow}@keyframes agent-highlight-glow{0%{box-shadow:0 0 0 2px rgb(var(--primary));background:rgb(var(--primary) / .08)}to{background:0 0;box-shadow:0 0 #0000}}.agent-attention{animation:2s ease-out forwards agent-attention-pulse}@keyframes agent-attention-pulse{0%,to{outline:2px solid #0000}50%{outline:2px solid rgb(var(--primary))}}@keyframes agent-blink{0%,50%{opacity:1}51%,to{opacity:0}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}
3
3
  /*$vite$:1*/