@tangle-network/agent-app 0.45.46 → 0.45.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DesignCanvas-P2ZVK6FM.js → DesignCanvas-QY2CA5GI.js} +2 -2
- package/dist/{DesignCanvasEditor-DGNCA54P.js → DesignCanvasEditor-CJ7PLX7A.js} +3 -3
- package/dist/{IntakeInterview-3ZIQMZS6.js → IntakeInterview-NJXKH35Q.js} +2 -2
- package/dist/InvitationsPanel-F2VY4TSL.js +9 -0
- package/dist/InviteAcceptPage-UT4452KT.js +7 -0
- package/dist/MembersPanel-N5CBOUXC.js +9 -0
- package/dist/{TimelineEditor-OTNPJ3SN.js → TimelineEditor-IYNKBSUX.js} +2 -2
- package/dist/assistant/index.d.ts +35 -10
- package/dist/assistant/index.js +234 -89
- package/dist/assistant/index.js.map +1 -1
- package/dist/chat-react/index.js +2 -1
- package/dist/chat-react/index.js.map +1 -1
- package/dist/{chunk-IUSO2XRE.js → chunk-5BACNOVR.js} +13 -14
- package/dist/chunk-5BACNOVR.js.map +1 -0
- package/dist/chunk-AULM4X7U.js +77 -0
- package/dist/chunk-AULM4X7U.js.map +1 -0
- package/dist/{chunk-UM6ODCLN.js → chunk-C7AQW6US.js} +346 -249
- package/dist/chunk-C7AQW6US.js.map +1 -0
- package/dist/{chunk-VCPZ3HTN.js → chunk-DB2D2JBQ.js} +51 -27
- package/dist/chunk-DB2D2JBQ.js.map +1 -0
- package/dist/{chunk-TL37E5YY.js → chunk-DS2WE62K.js} +3 -3
- package/dist/{chunk-TL37E5YY.js.map → chunk-DS2WE62K.js.map} +1 -1
- package/dist/{chunk-PE67O2LH.js → chunk-GT4GTRGQ.js} +18 -13
- package/dist/chunk-GT4GTRGQ.js.map +1 -0
- package/dist/{chunk-BT4QFCTB.js → chunk-HSBJB46C.js} +13 -1
- package/dist/chunk-HSBJB46C.js.map +1 -0
- package/dist/{chunk-54FYYXAX.js → chunk-J6OJTFNE.js} +13 -10
- package/dist/chunk-J6OJTFNE.js.map +1 -0
- package/dist/chunk-MLG6XKPV.js +44 -0
- package/dist/chunk-MLG6XKPV.js.map +1 -0
- package/dist/{chunk-F4XLTVQ3.js → chunk-R6KGLGEJ.js} +18 -17
- package/dist/chunk-R6KGLGEJ.js.map +1 -0
- package/dist/{chunk-B62EZF52.js → chunk-RILGAFEL.js} +3 -3
- package/dist/{chunk-65OZT566.js → chunk-T7XPIBCX.js} +16 -14
- package/dist/chunk-T7XPIBCX.js.map +1 -0
- package/dist/{chunk-VOJB7MVG.js → chunk-XPFNEKHS.js} +70 -28
- package/dist/chunk-XPFNEKHS.js.map +1 -0
- package/dist/{chunk-GNPN6ED4.js → chunk-XVRHISF3.js} +127 -165
- package/dist/chunk-XVRHISF3.js.map +1 -0
- package/dist/design-canvas-react/index.js +14 -12
- package/dist/design-canvas-react/index.js.map +1 -1
- package/dist/design-canvas-react/lazy.js +1 -1
- package/dist/intakes-react/index.js +1 -1
- package/dist/intakes-react/lazy.js +1 -1
- package/dist/sequences-react/index.js +2 -2
- package/dist/studio/index.d.ts +13 -1
- package/dist/studio/index.js +13 -1
- package/dist/studio-react/index.js +100 -63
- package/dist/studio-react/index.js.map +1 -1
- package/dist/studio-react/studio.css +0 -56
- package/dist/teams-react/index.js +4 -3
- package/dist/teams-react/lazy.js +3 -3
- package/dist/theme/tokens.css +173 -0
- package/dist/web-react/index.d.ts +15 -11
- package/dist/web-react/index.js +6 -4
- package/dist/work-product-react/index.js +3 -21
- package/dist/work-product-react/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/InvitationsPanel-F56UOQXA.js +0 -8
- package/dist/InviteAcceptPage-P3QJC3C6.js +0 -7
- package/dist/MembersPanel-XNLF3SA4.js +0 -8
- package/dist/chunk-54FYYXAX.js.map +0 -1
- package/dist/chunk-65OZT566.js.map +0 -1
- package/dist/chunk-BT4QFCTB.js.map +0 -1
- package/dist/chunk-F4XLTVQ3.js.map +0 -1
- package/dist/chunk-GNPN6ED4.js.map +0 -1
- package/dist/chunk-IUSO2XRE.js.map +0 -1
- package/dist/chunk-PE67O2LH.js.map +0 -1
- package/dist/chunk-UM6ODCLN.js.map +0 -1
- package/dist/chunk-VCPZ3HTN.js.map +0 -1
- package/dist/chunk-VOJB7MVG.js.map +0 -1
- /package/dist/{DesignCanvas-P2ZVK6FM.js.map → DesignCanvas-QY2CA5GI.js.map} +0 -0
- /package/dist/{DesignCanvasEditor-DGNCA54P.js.map → DesignCanvasEditor-CJ7PLX7A.js.map} +0 -0
- /package/dist/{IntakeInterview-3ZIQMZS6.js.map → IntakeInterview-NJXKH35Q.js.map} +0 -0
- /package/dist/{InvitationsPanel-F56UOQXA.js.map → InvitationsPanel-F2VY4TSL.js.map} +0 -0
- /package/dist/{InviteAcceptPage-P3QJC3C6.js.map → InviteAcceptPage-UT4452KT.js.map} +0 -0
- /package/dist/{MembersPanel-XNLF3SA4.js.map → MembersPanel-N5CBOUXC.js.map} +0 -0
- /package/dist/{TimelineEditor-OTNPJ3SN.js.map → TimelineEditor-IYNKBSUX.js.map} +0 -0
- /package/dist/{chunk-B62EZF52.js.map → chunk-RILGAFEL.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/web-react/index.tsx","../src/web-react/smooth-text.ts","../src/web-react/brand-mark.tsx","../src/web-react/durable-plan-card.tsx","../src/web-react/interaction-question-card.tsx","../src/web-react/interaction-card-support.ts","../src/web-react/interaction-plan-card.tsx","../src/web-react/durable-chat-cards.tsx","../src/web-react/message-attachments.tsx","../src/web-react/chat-stream.ts","../src/web-react/chat-composer.tsx","../src/web-react/durable-plan-flow.ts","../src/web-react/durable-interaction-submit.ts","../src/web-react/use-chat-interactions.ts","../src/web-react/use-file-mentions.ts","../src/web-react/chat-mentions.ts","../src/web-react/mission-activity.tsx","../src/web-react/provenance.tsx","../src/web-react/provenance-model.ts","../src/web-react/seat-paywall.tsx","../src/web-react/session-history.tsx","../src/web-react/record-grid.tsx","../src/web-react/record-grid-model.ts"],"sourcesContent":["/**\n * `@tangle-network/agent-app/web-react` — the shared chat-shell components\n * every agent app's web UI hand-rolls: a model picker over the runtime's\n * model catalogue, a reasoning-effort selector, and a message thread with\n * User/Agent identity, per-message model + cost + tokens/sec metrics,\n * canonical tool rows, and a collapsible thinking section.\n *\n * Works for BOTH chat shapes: router-backed copilots (LoopEvents from\n * `runtime/openai-stream`) and sandbox-backed chats — the thread renders\n * `ChatUiMessage`s; how they're produced is the app's business.\n *\n * Styling contract: Tailwind classes against the shared design tokens\n * (`bg-card`, `border-border`, `text-muted-foreground`, `bg-primary`, …) that\n * Tangle app shells define. No icon library of its own — the few local glyphs\n * are inline SVGs. Markdown and provider logos are injected (`renderMarkdown`,\n * `renderProviderBadge`).\n *\n * Tool rows compose the canonical run-row grammar from `@tangle-network/ui`\n * (`InlineToolItem` over `RunRowShell`): `chatToolCallPart` adapts each\n * `ChatToolCallInfo` to ui's `ToolPart` (the same adapter pattern ui's own\n * `ToolCallStep` uses), so the chat surface and every other Tangle run view\n * share one row implementation instead of drifting. That makes\n * `@tangle-network/ui` a peer of this subpath.\n */\n\nimport { useEffect, useMemo, useRef, useState, memo, type ReactNode } from 'react'\nimport { InlineToolItem } from '@tangle-network/ui/run'\nimport type { ToolPart } from '@tangle-network/ui/types'\nimport { useSmoothText } from './smooth-text'\nimport { ChevronDown, OVERLAY_SHADOW, POPOVER_OPTION_FOCUS, usePending } from './controls'\nimport { BrandMark } from './brand-mark'\nimport { DurableChatCards, type DurableChatCardsProps } from './durable-chat-cards'\nimport { attachmentPartsFromMessageParts, type ChatAttachmentPart } from './chat-attachments'\nimport { MessageAttachments } from './message-attachments'\nimport { WorkProductCard, workProductPartsFromMessageParts } from './work-product'\nimport type { WorkProductPersistedPart } from '../work-product/types'\n\nexport * from './chat-stream'\nexport * from './chat-interactions'\nexport * from './chat-composer'\nexport * from './interaction-card-support'\nexport * from './interaction-question-card'\nexport * from './interaction-plan-card'\nexport * from './durable-plan-flow'\nexport * from './durable-plan-card'\nexport * from './durable-chat-cards'\nexport * from './durable-interaction-submit'\nexport * from './use-chat-interactions'\nexport * from './use-file-mentions'\nexport * from './chat-mentions'\nexport * from './chat-attachments'\nexport * from './message-attachments'\nexport * from './use-composer-attachments'\nexport * from './provider-logo'\nexport * from './harness-glyphs'\nexport * from './smooth-text'\nexport * from './mission-activity'\nexport * from './work-product'\nexport * from './provenance'\nexport * from './sandbox-terminal'\nexport * from './seat-paywall'\nexport * from './session-history'\nexport * from './record-grid'\nexport {\n usePopover,\n usePending,\n PopoverSurface,\n POPOVER_SURFACE_ATTR,\n ModelPicker,\n EffortPicker,\n EffortMeter,\n effortMeterFill,\n effortLevelLabel,\n effortLevelsFromIds,\n reconcileEffortLevels,\n DEFAULT_EFFORT_LEVELS,\n EFFORT_METER_SEGMENTS,\n OVERLAY_SHADOW,\n type ModelPickerProps,\n type EffortPickerProps,\n type EffortLevel,\n type PopoverSurfaceProps,\n} from './controls'\nexport {\n AgentSessionControls,\n type AgentSessionControlsProps,\n} from './agent-session-controls'\nimport type { CatalogModel } from '../runtime/model-catalog'\n// Re-export the model type the chat components consume, so a web-react consumer\n// imports it from here rather than the package root.\nexport type { CatalogModel } from '../runtime/model-catalog'\n\n// ── metrics helpers ───────────────────────────────────────────────────────\n\n/** Describe metrics related to a chat message including model, token counts, and duration */\nexport interface ChatMessageMetrics {\n modelUsed?: string\n promptTokens?: number\n completionTokens?: number\n durationMs?: number\n}\n\n/** \"$0.0042\" from token counts × catalogue per-token pricing; null when unknown. */\nexport function formatModelCost(msg: ChatMessageMetrics, models: CatalogModel[]): string | null {\n if (msg.promptTokens == null && msg.completionTokens == null) return null\n const pricing = models.find((m) => m.id === msg.modelUsed)?.pricing\n if (!pricing) return null\n const cost =\n (msg.promptTokens ?? 0) * Number(pricing.prompt ?? 0) +\n (msg.completionTokens ?? 0) * Number(pricing.completion ?? 0)\n if (!isFinite(cost) || cost <= 0) return null\n return cost < 0.01 ? `$${cost.toFixed(4)}` : `$${cost.toFixed(2)}`\n}\n\n/** \"38 tok/s\" from completion tokens over first-token→end duration; null when unknown. */\nexport function formatTokensPerSecond(msg: ChatMessageMetrics): string | null {\n if (msg.completionTokens == null || !msg.durationMs) return null\n return `${Math.round(msg.completionTokens / (msg.durationMs / 1000))} tok/s`\n}\n\n// ── Tool run drill-in (retained runs) ─────────────────────────────────────\n\n/** One step of a retained tool run (e.g. a sandbox command + its output). */\nexport interface ToolRunStep {\n at: string\n label: string\n detail?: string\n status?: 'ok' | 'error'\n}\n\n/** A retained tool run keyed by the parent message's toolCallId. The product\n * persists these server-side (fail-closed: only ids its own loop created)\n * and serves them to the drill-in panel. */\nexport interface ToolRunRecord {\n toolCallId: string\n toolName: string\n title: string\n status: 'running' | 'complete' | 'error'\n steps: ToolRunStep[]\n}\n\n/** Define properties required to run a drill and handle its closure event */\nexport interface RunDrillInProps {\n run: ToolRunRecord\n onClose: () => void\n}\n\n/**\n * Readonly side panel showing a retained tool run's transcript — the\n * \"drill into what the sandbox actually did\" view. Follow-ups happen in the\n * main chat, never here.\n */\nexport function RunDrillIn({ run, onClose }: RunDrillInProps) {\n return (\n <div className={`fixed inset-y-0 right-0 z-50 flex w-[480px] max-w-full flex-col border-l border-card-edge bg-popover ${OVERLAY_SHADOW}`}>\n <div className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${\n run.status === 'running' ? 'bg-warning' : run.status === 'error' ? 'bg-destructive' : 'bg-success'\n }`}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-semibold\">{run.title}</p>\n <p className=\"truncate font-mono text-[11px] text-muted-foreground\">{run.toolName}</p>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"rounded-md p-1.5 text-muted-foreground transition hover:bg-accent hover:text-foreground\"\n >\n <svg className=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n <div className=\"flex-1 space-y-3 overflow-y-auto p-4\">\n {run.steps.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No steps recorded yet.</p>\n )}\n {run.steps.map((step, i) => (\n <div key={i} className=\"rounded-lg border border-card-edge bg-card\">\n <div className=\"flex items-baseline gap-2 border-b border-border px-3 py-1.5\">\n <span className={`font-mono text-[11px] ${step.status === 'error' ? 'text-destructive' : 'text-muted-foreground'}`}>\n {step.status === 'error' ? '✗' : '$'}\n </span>\n <code className=\"min-w-0 flex-1 truncate font-mono text-xs\">{step.label}</code>\n <span className=\"shrink-0 text-[10px] text-muted-foreground\">\n {new Date(step.at).toLocaleTimeString()}\n </span>\n </div>\n {step.detail && (\n <pre className=\"max-h-48 overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-[11px] leading-relaxed text-muted-foreground\">\n {step.detail}\n </pre>\n )}\n </div>\n ))}\n </div>\n <p className=\"border-t border-border px-4 py-2 text-[11px] text-muted-foreground\">\n Readonly drill-in. Follow up in the main chat.\n </p>\n </div>\n )\n}\n\n// ── ChatMessages ──────────────────────────────────────────────────────────\n\n/** Describe the structure and state of a tool call within a chat interaction */\nexport interface ChatToolCallInfo {\n id: string\n name: string\n status: 'running' | 'done' | 'error'\n /** The call arguments, captured from the tool_call event — shown in the\n * expanded card so users see exactly what the agent invoked. */\n args?: Record<string, unknown>\n /** The tool outcome (`{ok, result}` shape). When `result.status` is\n * 'queued_for_approval' the card renders the approval state. */\n result?: unknown\n}\n\n/** Extract `{proposalId, status}` from a tool outcome when it is a proposal\n * awaiting human approval; null otherwise. */\nexport function pendingApprovalOf(call: ChatToolCallInfo): { proposalId: string } | null {\n const outcome = call.result as { ok?: boolean; result?: { status?: string; proposalId?: string } } | undefined\n if (!outcome?.ok || outcome.result?.status !== 'queued_for_approval' || !outcome.result.proposalId) return null\n return { proposalId: outcome.result.proposalId }\n}\n\n/** One ordered piece of an assistant turn: a run of answer text, or a tool\n * call, in the sequence the agent emitted them. A message carrying `segments`\n * is rendered in order — interleaving text and tool rows — so the agent's\n * pre- and post-tool reasoning reads chronologically instead of as one text\n * blob with the tool rows collected after it. */\nexport type ChatMessageSegment =\n | { kind: 'text'; content: string }\n | { kind: 'tool'; call: ChatToolCallInfo }\n\n/** Describe the structure and properties of a chat message with roles, content, and optional metadata */\nexport interface ChatUiMessage extends ChatMessageMetrics {\n id: string\n role: 'user' | 'assistant' | 'system'\n content: string\n reasoning?: string\n toolCalls?: ChatToolCallInfo[]\n /** Ordered text/tool sequence for true chronological interleaving. When\n * present and non-empty it is rendered in place of `content` + `toolCalls`;\n * both remain the fallback for producers that don't segment a turn. */\n segments?: ChatMessageSegment[]\n /** Persisted assistant parts. When `ChatMessages.durableCards` is supplied,\n * shared plan/question cards render directly from these projections. */\n parts?: Array<Record<string, unknown>>\n}\n\n/** Define properties for rendering chat messages with optional models, markdown, extras, and durable cards */\nexport interface ChatMessagesProps {\n messages: ChatUiMessage[]\n /** Shared reading scale for both user and assistant prose. Defaults to 16px;\n * `large` uses 17px without enlarging labels, tool chrome, or metadata. */\n messageSize?: 'default' | 'large'\n /** Transcript chrome. `labeled` (default) keeps the always-on role label +\n * model/tok-s/cost meta line and the primary-tinted user bubble. `quiet`\n * drops the label row into a fixed-height meta lane at each row's bottom\n * (copy + the demoted meta, revealed on hover/focus, always visible on\n * touch) and renders user bubbles neutral with a symmetric radius.\n * Everything else — tool rows, reasoning, streaming — is identical. */\n chrome?: 'labeled' | 'quiet'\n /** Catalogue models, for per-message cost from pricing. Pass [] to skip cost. */\n models?: CatalogModel[]\n /** Markdown renderer for assistant content; default renders pre-wrapped text. */\n renderMarkdown?: (content: string) => ReactNode\n /** Extra per-message content (artifacts, custom panels) appended after the body. */\n renderExtras?: (message: ChatUiMessage) => ReactNode\n /** Canonical durable plan/question card wiring. Apps inject only transport,\n * access, and optional visual callbacks; card selection/dedupe stays shared. */\n durableCards?: Omit<DurableChatCardsProps, 'parts' | 'renderMarkdown'>\n userLabel?: string\n agentLabel?: string\n /** Render the trailing \"agent is thinking\" row. */\n loading?: boolean\n /** Approve/Reject handlers for proposals awaiting approval. When omitted the\n * card still shows \"awaiting approval\" but without action buttons. */\n approval?: ProposalApprovalHandlers\n /** Open a full-transcript view (e.g. {@link RunDrillIn}) from a tool row's\n * actions slot. */\n onToolCallClick?: (call: ChatToolCallInfo, message: ChatUiMessage) => void\n /** Per-tool custom detail renderers for the expanded tool row body. */\n toolRenderers?: ToolDetailRenderers\n /** Stream-error affordance: when the turn failed (a thrown transport error or\n * a loop-level `onErrorEvent`), pass the message here to render an error row.\n * A failed turn otherwise just stops with no UI signal. */\n error?: string | null\n /** Retry control shown on the error row; omit to render the error without a\n * retry button (e.g. when the product retries automatically). */\n onRetry?: () => void\n /** Zero-state renderer, shown when there are no messages and the turn is\n * neither loading nor errored. When omitted, a branded first-run state is\n * shown ({@link ChatEmptyState}); pass `() => null` to render nothing. */\n renderEmpty?: () => ReactNode\n /** First-run state config used when `renderEmpty` is not supplied. Lets a\n * product set the headline and the \"doors\" (e.g. start from a template, ask\n * the agent) without replacing the whole zero-state. */\n emptyState?: ChatEmptyStateProps\n /** Optional branded header slot rendered above the thread. Off by default to\n * preserve the current layout; pass `{ title }` (or your own node via\n * `header`) to show the Tangle mark + product title in the chat shell. */\n header?: ReactNode\n /** Resolve a raw-bytes download URL for one attachment part. When set, any\n * message carrying attachment parts (`file`/`image` parts with a `path`,\n * see `attachmentPartsFromMessageParts`) renders them as a `MessageAttachments`\n * row next to the bubble — thumbnails for images, download chips for files.\n * Absent → today's rendering, byte-identical (no attachment row). */\n resolveAttachmentUrl?: (part: ChatAttachmentPart) => string\n /** Render persisted `type:'work_product'` anchor parts as `WorkProductCard`\n * rows under the message body — the chat card that keeps chat the driver\n * surface for review. `onOpen` opens the product's queue/detail surface.\n * Absent → today's rendering, byte-identical (no card row). */\n workProductCards?: { onOpen?: (part: WorkProductPersistedPart) => void }\n}\n\n/** One starting \"door\" in the chat first-run state — a concrete, labeled action\n * (start from a template, do it by hand, ask the agent), not a placeholder. */\nexport interface ChatEmptyDoor {\n label: string\n description?: string\n onSelect: () => void\n}\n\n/** Define properties for rendering the chat empty state with customizable text and starting doors */\nexport interface ChatEmptyStateProps {\n /** Product name shown next to the Tangle mark. Default \"Agent\". */\n productName?: string\n /** Headline. Default frames delegation, not messaging. */\n headline?: string\n /** Subline under the headline. */\n subline?: string\n /** Up to three concrete starting doors. Omit for a mark-and-prompt-only state. */\n doors?: ChatEmptyDoor[]\n}\n\n/**\n * Branded chat first-run state: the Tangle mark, a delegation-framed prompt, and\n * up to three concrete doors. Replaces the blank thread that read as \"empty or\n * broken\". Concrete + actionable — never a \"coming soon\" placeholder.\n */\nexport function ChatEmptyState({\n productName = 'Agent',\n headline = 'Ask the agent to do something',\n subline = 'Describe the outcome you want. The agent works through it step by step, and pauses for your approval before anything irreversible.',\n doors,\n}: ChatEmptyStateProps) {\n return (\n <div className=\"mx-auto flex w-full max-w-2xl flex-col items-center px-6 py-12 text-center sm:py-20\">\n <span className=\"mb-5 inline-flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 ring-1 ring-primary/15\">\n <BrandMark size={32} className=\"shrink-0\" />\n </span>\n <p className=\"text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground\">{productName}</p>\n <h2 className=\"mt-1.5 text-balance text-2xl font-semibold leading-tight text-foreground sm:text-[28px]\">\n {headline}\n </h2>\n {subline && <p className=\"mt-3 max-w-md text-[15px] leading-relaxed text-muted-foreground\">{subline}</p>}\n {doors && doors.length > 0 && (\n <div className=\"mt-7 grid w-full gap-2.5 sm:grid-cols-3\">\n {doors.slice(0, 3).map((door, i) => (\n <button\n key={i}\n type=\"button\"\n onClick={door.onSelect}\n className=\"group flex min-h-[44px] flex-col items-start rounded-xl border border-border bg-card px-4 py-3 text-left transition hover:border-primary/40 hover:bg-accent\"\n >\n <span className=\"text-sm font-semibold text-foreground\">{door.label}</span>\n {door.description && (\n <span className=\"mt-0.5 text-[12px] leading-snug text-muted-foreground\">{door.description}</span>\n )}\n </button>\n ))}\n </div>\n )}\n </div>\n )\n}\n\n/** Handle approval and rejection actions for proposals with asynchronous support */\nexport interface ProposalApprovalHandlers {\n onApprove: (proposalId: string, toolCallId: string) => void | Promise<void>\n onReject: (proposalId: string, toolCallId: string) => void | Promise<void>\n}\n\n/** Per-tool custom detail renderers for the expanded card body — keyed by\n * tool name. Return null to fall back to the generic detail view. */\nexport type ToolDetailRenderers = Record<\n string,\n (call: ChatToolCallInfo, message: ChatUiMessage) => ReactNode\n>\n\nfunction ToolGlyph({ name, className }: { name: string; className?: string }) {\n if (name.startsWith('sandbox_')) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <polyline points=\"4 17 10 11 4 5\" />\n <line x1=\"12\" y1=\"19\" x2=\"20\" y2=\"19\" />\n </svg>\n )\n }\n if (name === 'submit_proposal') {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <path d=\"M14 2v6h6M9 15l2 2 4-4\" />\n </svg>\n )\n }\n if (name === 'schedule_followup') {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M12 7v5l3 3\" />\n </svg>\n )\n }\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M12 3v3m0 12v3M3 12h3m12 0h3\" />\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n </svg>\n )\n}\n\nfunction toolOutcomeOf(call: ChatToolCallInfo): { ok?: boolean; result?: Record<string, unknown>; message?: string } | undefined {\n return call.result as { ok?: boolean; result?: Record<string, unknown>; message?: string } | undefined\n}\n\n/** A call that failed — by status OR by an `ok:false` outcome envelope. Shared\n * by the row adapter, the collapse guard, and the card itself so the three can\n * never disagree about what \"failed\" means. */\nfunction toolCallFailed(call: ChatToolCallInfo): boolean {\n return call.status === 'error' || toolOutcomeOf(call)?.ok === false\n}\n\n/**\n * Adapt a chat tool call to the canonical `@tangle-network/ui` `ToolPart`, so\n * the row renders through ui's `InlineToolItem` — one run-row grammar shared\n * with every other Tangle run view (the same adapter pattern ui's own\n * `ToolCallStep` uses for its flat props). `sandbox_run_command` maps to ui's\n * canonical `bash` name so the row takes the command category (terminal icon);\n * every other tool keeps its real name. agent-app carries no per-call timings,\n * so `state.time` stays unset and the row shows no duration.\n */\nexport function chatToolCallPart(call: ChatToolCallInfo): ToolPart {\n const failed = toolCallFailed(call)\n return {\n type: 'tool',\n id: call.id,\n tool: call.name === 'sandbox_run_command' ? 'bash' : call.name,\n state: {\n status: call.status === 'running' ? 'running' : failed ? 'error' : 'completed',\n input: call.args,\n output: call.result,\n error: failed ? (toolOutcomeOf(call)?.message ?? 'Tool failed') : undefined,\n },\n }\n}\n\n/** The four visual kinds a tool call presents as. They are *different kinds of\n * thing* (audit chat finding #3/#4) and must read differently: a command is a\n * past-tense action, a proposal is a pending decision, a follow-up is a\n * scheduled intent, everything else is a generic tool step. Derived from the\n * tool name + outcome, never from baked domain values. */\ntype BlockKind = 'command' | 'proposal' | 'followup' | 'generic'\n\nfunction blockKindOf(call: ChatToolCallInfo): BlockKind {\n if (call.name === 'submit_proposal') return 'proposal'\n if (call.name === 'schedule_followup') return 'followup'\n if (call.name.startsWith('sandbox_')) return 'command'\n return 'generic'\n}\n\n/** Humanize an otherwise-unmapped tool name for display: `get_credit_balance`\n * → \"Get credit balance\". Splits on separators and camelCase, then sentence-\n * cases — domain-agnostic, so a host's tool reads as a label without this\n * shared renderer knowing that host's tool taxonomy. Falls back to the raw name\n * when there's nothing to humanize. */\nfunction humanizeToolName(name: string): string {\n const words = name\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/[_-]+/g, ' ')\n .trim()\n if (!words) return name\n return words.charAt(0).toUpperCase() + words.slice(1)\n}\n\n/** Human title for a call, derived from its real arguments. Proposals lead with\n * the decision verb (docs/product-surfaces.md) rather than the internal tool\n * taxonomy, so the user reads \"Approve: publish …?\" not \"submit_proposal\". An\n * unmapped tool falls back to its humanized name rather than the raw slug. */\nfunction friendlyToolTitle(call: ChatToolCallInfo): string {\n const a = call.args ?? {}\n switch (call.name) {\n case 'submit_proposal':\n return a.title ? `Approve: ${String(a.title)}?` : 'Approve this action?'\n case 'sandbox_create':\n return `Created sandbox (${String(a.environment ?? 'universal')})`\n case 'sandbox_run_command':\n return `Ran ${String(a.command ?? 'command')}`\n case 'sandbox_destroy':\n return `Destroyed sandbox ${String(a.sandbox_id ?? '')}`\n case 'schedule_followup':\n return `Scheduled: ${String(a.title ?? 'follow-up')}`\n case 'render_ui':\n return `Rendered view · ${String(a.title ?? '')}`\n case 'add_citation':\n return `Cited ${String(a.path ?? '')}`\n default:\n return humanizeToolName(call.name)\n }\n}\n\n/** A one-line, plain-English preview of WHAT a proposal will do, assembled from\n * the proposal's real arguments (audit chat finding #2 — \"approving a black box\n * is the fastest way to lose trust\"). Domain stays a parameter: we only read\n * conventional fields (destinations/targets/channels, cost, reach) when present\n * — nothing here is baked to a specific product's proposal type. Returns null\n * when there's nothing meaningful to preview. */\nfunction proposalPreview(call: ChatToolCallInfo): { summary: string | null; meta: string[] } {\n const a = (call.args ?? {}) as Record<string, unknown>\n const asString = (v: unknown): string | null =>\n typeof v === 'string' && v.trim() ? v.trim() : null\n const asList = (v: unknown): string[] =>\n Array.isArray(v)\n ? v.map((x) => (typeof x === 'string' ? x : null)).filter((x): x is string => !!x)\n : asString(v)\n ? [asString(v) as string]\n : []\n\n // The verb: a free-form summary the agent wrote, else derive from type.\n const verbPhrase =\n asString(a.summary) ??\n asString(a.description) ??\n (asString(a.type)\n ? `${String(a.type).replace(/_/g, ' ')}${asString(a.title) ? `: ${asString(a.title)}` : ''}`\n : null)\n\n const destinations = [\n ...asList(a.destinations),\n ...asList(a.channels),\n ...asList(a.targets),\n ...asList(a.platforms),\n ]\n const dest = destinations.length ? ` to ${destinations.join(' and ')}` : ''\n const summary = verbPhrase ? `${verbPhrase}${dest}` : destinations.length ? `Publish to ${destinations.join(' and ')}` : null\n\n // Cost / reach: surfaced when the data carries it, formatted lightly.\n const meta: string[] = []\n const cost = a.cost ?? a.price ?? a.estimatedCost\n if (typeof cost === 'number' && cost > 0) meta.push(`~$${cost < 0.01 ? cost.toFixed(4) : cost.toFixed(2)}`)\n else if (asString(cost)) meta.push(asString(cost) as string)\n const reach = a.reach ?? a.audience ?? a.estimatedReach\n if (typeof reach === 'number' && reach > 0) meta.push(`reaches ~${reach.toLocaleString()}`)\n else if (asString(reach)) meta.push(asString(reach) as string)\n\n return { summary, meta }\n}\n\nfunction truncate(v: unknown, max = 240): string {\n const s = typeof v === 'string' ? v : JSON.stringify(v)\n // JSON.stringify returns undefined (not a string) for undefined / functions /\n // symbols — a non-envelope tool output (a bare string, or a result with no\n // `.result`) lands here. Coerce to '' so we never read `.length` off undefined\n // and crash the whole chat surface.\n if (typeof s !== 'string') return ''\n return s.length > max ? `${s.slice(0, max)}…` : s\n}\n\nfunction KvRows({ data }: { data: Record<string, unknown> }) {\n const entries = Object.entries(data).filter(([, v]) => v !== undefined && v !== null && v !== '')\n if (!entries.length) return null\n return (\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-3 gap-y-1\">\n {entries.map(([k, v]) => (\n <div key={k} className=\"contents\">\n <dt className=\"font-mono text-[11px] text-muted-foreground\">{k}</dt>\n <dd className=\"min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground\">\n {truncate(v)}\n </dd>\n </div>\n ))}\n </dl>\n )\n}\n\n/** Terminal-styled rendering for shell executions. */\nfunction ShellDetail({ call }: { call: ChatToolCallInfo }) {\n const outcome = toolOutcomeOf(call)\n const r = (outcome?.result ?? {}) as { stdout?: string; stderr?: string; exitCode?: number }\n return (\n <div className=\"overflow-hidden rounded-md bg-zinc-900 font-mono text-[11px] leading-relaxed\">\n <div className=\"flex items-center gap-2 px-3 pt-2 text-zinc-400\">\n <span className=\"select-none text-zinc-500\">$</span>\n <span className=\"min-w-0 flex-1 truncate text-zinc-200\">{String(call.args?.command ?? '')}</span>\n {r.exitCode != null && (\n <span className={r.exitCode === 0 ? 'text-success' : 'text-destructive'}>exit {r.exitCode}</span>\n )}\n </div>\n <pre className=\"max-h-56 overflow-auto whitespace-pre-wrap px-3 pb-2.5 pt-1.5 text-zinc-300\">\n {outcome?.ok === false ? (outcome.message ?? 'failed') : [r.stdout, r.stderr].filter(Boolean).join('\\n') || '(no output)'}\n </pre>\n </div>\n )\n}\n\n/** Generic expanded detail: what was called, and what actually happened. */\nfunction DefaultToolDetail({ call }: { call: ChatToolCallInfo }) {\n // A tool result is the `{ ok, result }` proposal envelope ONLY when it is an\n // object. bash/skill/python outputs arrive as a bare string (or nothing at\n // all), so reading `.ok`/`.result` off them is meaningless — those render as\n // their raw value, not through the envelope branch.\n const result: unknown = call.result\n const envelope =\n typeof result === 'object' && result !== null\n ? (result as { ok?: boolean; result?: unknown; message?: string })\n : null\n return (\n <div className=\"space-y-2\">\n {call.args && Object.keys(call.args).length > 0 && (\n <div>\n <p className=\"mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground\">Called with</p>\n <KvRows data={call.args} />\n </div>\n )}\n {envelope ? (\n <div>\n <p className=\"mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground\">\n {envelope.ok === false ? 'Failed' : 'Result'}\n </p>\n {envelope.ok === false ? (\n <p className=\"text-xs text-destructive\">{envelope.message ?? 'Tool failed'}</p>\n ) : envelope.result && typeof envelope.result === 'object' ? (\n <KvRows data={envelope.result as Record<string, unknown>} />\n ) : envelope.result != null ? (\n <p className=\"font-mono text-[11px] text-muted-foreground\">{truncate(envelope.result)}</p>\n ) : null}\n </div>\n ) : result != null ? (\n <div>\n <p className=\"mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground\">Result</p>\n <p className=\"font-mono text-[11px] text-muted-foreground\">{truncate(result)}</p>\n </div>\n ) : null}\n </div>\n )\n}\n\n/** The pending-decision card. The single highest-leverage surface in the repo\n * (audit chat finding #1, critical): Approve is the affirmative path — filled,\n * brand-colored, primary — and Reject is quiet/outline, so a user never reads\n * both labels twice to know the safe action. Carries a plain-English preview of\n * WHAT it will do (#2). `onApprove`/`onReject` are unchanged. */\nfunction ProposalCard({\n call,\n message,\n pending,\n approval,\n renderers,\n}: {\n call: ChatToolCallInfo\n message: ChatUiMessage\n pending: { proposalId: string }\n approval?: ProposalApprovalHandlers\n renderers?: ToolDetailRenderers\n}) {\n const [expanded, setExpanded] = useState(false)\n const { summary, meta } = proposalPreview(call)\n const custom = renderers?.[call.name]?.(call, message)\n const { pending: deciding, run: decide } = usePending()\n\n return (\n <div className=\"w-full max-w-full rounded-xl border border-warning/50 bg-warning/[0.06] text-sm shadow-sm ring-1 ring-warning/10\">\n <div className=\"flex items-start gap-2.5 px-4 pt-3.5\">\n <span className=\"mt-0.5 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-warning/15 text-warning\">\n <ToolGlyph name={call.name} className=\"h-3.5 w-3.5\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-[10px] font-semibold uppercase tracking-wider text-warning-strong\">Needs your approval</p>\n <p className=\"mt-0.5 text-[15px] font-semibold leading-snug text-foreground\">{friendlyToolTitle(call)}</p>\n {summary && <p className=\"mt-1 text-[13px] leading-relaxed text-muted-foreground\">{summary}</p>}\n {meta.length > 0 && (\n <div className=\"mt-1.5 flex flex-wrap items-center gap-1.5\">\n {meta.map((m, i) => (\n <span key={i} className=\"rounded-full bg-secondary px-2 py-0.5 text-[11px] font-medium text-muted-foreground\">\n {m}\n </span>\n ))}\n </div>\n )}\n </div>\n </div>\n <div className=\"flex flex-wrap items-center gap-2 px-4 pb-3.5 pt-3\">\n {approval ? (\n <>\n <button\n type=\"button\"\n disabled={deciding}\n onClick={() => decide(() => approval.onApprove(pending.proposalId, call.id))}\n className=\"inline-flex min-h-[40px] flex-1 items-center justify-center rounded-lg bg-primary px-4 py-2 text-sm font-semibold text-primary-foreground shadow-sm transition hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-60 sm:flex-none sm:min-w-[160px]\"\n >\n Approve & run\n </button>\n <button\n type=\"button\"\n disabled={deciding}\n onClick={() => decide(() => approval.onReject(pending.proposalId, call.id))}\n className=\"inline-flex min-h-[40px] items-center justify-center rounded-lg border border-border bg-transparent px-4 py-2 text-sm font-medium text-muted-foreground transition hover:bg-accent hover:text-foreground disabled:cursor-not-allowed disabled:opacity-60\"\n >\n Reject\n </button>\n </>\n ) : (\n <span className=\"text-[12px] font-medium text-muted-foreground\">Awaiting approval…</span>\n )}\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n aria-expanded={expanded}\n className=\"ml-auto inline-flex items-center gap-1 rounded text-[12px] font-medium text-muted-foreground transition hover:text-foreground\"\n >\n {expanded ? 'Hide details' : 'View details'}\n <ChevronDown className={`h-3 w-3 transition-transform ${expanded ? 'rotate-180' : ''}`} />\n </button>\n </div>\n {expanded && (\n <div className=\"border-t border-warning/20 px-4 py-3 text-xs\">\n {custom ?? <DefaultToolDetail call={call} />}\n </div>\n )}\n </div>\n )\n}\n\n/** A scheduled follow-up — a pending, time-based intent, not a decision and not\n * a completed action (audit finding #5). Re-skinned onto the shared run-row\n * geometry (full width, 24px icon chip, xs title, mono `when` in the\n * description slot) so it reads as a sibling of the canonical tool rows; it\n * is not a tool invocation, so the row does not expand. */\nfunction FollowupCard({ call }: { call: ChatToolCallInfo }) {\n const a = (call.args ?? {}) as Record<string, unknown>\n const when = typeof a.when === 'string' ? a.when : typeof a.at === 'string' ? a.at : typeof a.schedule === 'string' ? a.schedule : null\n return (\n <div className=\"flex items-start gap-2\">\n <div className=\"min-w-0 flex-1 overflow-hidden rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--md3-surface-container)]\">\n <div className=\"flex w-full items-center gap-2.5 px-3 py-2\">\n <span className=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-border bg-muted text-muted-foreground\">\n <ToolGlyph name={call.name} className=\"h-3.5 w-3.5\" />\n </span>\n <span className=\"shrink-0 whitespace-nowrap text-xs font-medium text-foreground\">{friendlyToolTitle(call)}</span>\n {when && (\n <span className=\"hidden min-w-0 flex-1 truncate font-mono text-xs text-muted-foreground sm:inline\">{when}</span>\n )}\n </div>\n </div>\n </div>\n )\n}\n\n/** Row title: short and past-tense. A command's text moves to the canonical\n * mono description slot instead of filling the title. */\nfunction toolRowTitle(call: ChatToolCallInfo): string {\n if (call.name === 'sandbox_run_command') return 'Ran command'\n return friendlyToolTitle(call)\n}\n\n/** The collapsed row's inline description — the canonical row's mono slot. Only\n * a command has a natural one-liner; every other tool's title already carries\n * its identifying argument. */\nfunction toolRowDescription(call: ChatToolCallInfo): string | undefined {\n if (call.name !== 'sandbox_run_command') return undefined\n const command = call.args?.command\n return typeof command === 'string' && command ? command : undefined\n}\n\nfunction ToolCallCard({\n call,\n message,\n approval,\n onOpenRun,\n renderers,\n}: {\n call: ChatToolCallInfo\n message: ChatUiMessage\n approval?: ProposalApprovalHandlers\n onOpenRun?: (call: ChatToolCallInfo, message: ChatUiMessage) => void\n renderers?: ToolDetailRenderers\n}) {\n const pending = call.status === 'done' ? pendingApprovalOf(call) : null\n const kind = blockKindOf(call)\n const failed = toolCallFailed(call)\n\n // A proposal awaiting approval is a pending DECISION, not a tool row — it\n // keeps its own prominent card with primary Approve / quiet Reject.\n if (pending) {\n return (\n <ProposalCard\n call={call}\n message={message}\n pending={pending}\n approval={approval}\n renderers={renderers}\n />\n )\n }\n // A scheduled follow-up is a time-based intent — its own quiet row, distinct\n // from a tool invocation.\n if (kind === 'followup' && !failed) {\n return <FollowupCard call={call} />\n }\n\n // Command and generic tool calls render through the canonical InlineToolItem\n // row (category icon chip, title, mono description, status, hairline expand).\n // The expanded body stays agent-app's — the host's custom renderer, the\n // terminal ShellDetail for commands, or the generic args/result view — via\n // ui's `renderToolDetail` seam, and `onOpenRun` maps to the row's actions\n // slot, so no agent-app capability is lost to the shared chrome.\n const custom = renderers?.[call.name]?.(call, message)\n return (\n <InlineToolItem\n part={chatToolCallPart(call)}\n title={toolRowTitle(call)}\n description={toolRowDescription(call)}\n renderToolDetail={() =>\n custom ??\n (call.name === 'sandbox_run_command' ? <ShellDetail call={call} /> : <DefaultToolDetail call={call} />)\n }\n actions={\n onOpenRun && call.name.startsWith('sandbox_') ? (\n <button\n type=\"button\"\n onClick={() => onOpenRun(call, message)}\n className=\"rounded border border-border bg-card px-2 py-1 text-[11px] font-medium transition hover:bg-accent\"\n >\n Open full transcript →\n </button>\n ) : undefined\n }\n />\n )\n}\n\n/** The blinking insertion caret shown at the end of streaming answer text.\n * Shared by the segmented and legacy branches so their streaming cue can't\n * visually diverge. */\nfunction StreamingCaret() {\n return (\n <span\n className=\"ml-0.5 inline-block h-[1.1em] w-[3px] translate-y-[2px] animate-pulse rounded-sm bg-foreground/70\"\n aria-hidden\n />\n )\n}\n\n/** One text run inside a segmented turn. Smooths its own text so only the\n * actively-streaming trailing run types out; finalized runs render at once.\n * A child component (not an inline map) so its `useSmoothText` state is stable\n * across the parent's per-frame stream re-renders. */\nfunction SegmentText({\n content,\n streaming,\n showCaret,\n renderBody,\n messageClassName,\n}: {\n content: string\n streaming: boolean\n showCaret: boolean\n renderBody: (content: string) => ReactNode\n messageClassName: string\n}) {\n const text = useSmoothText(content, streaming)\n const body = useMemo(() => renderBody(text), [renderBody, text])\n // An empty / whitespace-only run paints a blank line-height gap — render\n // nothing, UNLESS it's the live trailing run (showCaret), where it still\n // carries the caret so the turn doesn't look frozen. (Hooks run first, so\n // this stays rules-of-hooks safe.)\n if (!content.trim() && !showCaret) return null\n return (\n <div className={messageClassName}>\n {body}\n {/* Gate on showCaret (not the smoothed `text`, which is '' on the first\n frame) so the caret is steady from the start instead of flickering. */}\n {showCaret && <StreamingCaret />}\n </div>\n )\n}\n\n/** A settled run of at least this many consecutive tool calls collapses into a\n * single \"Worked through N steps\" disclosure so a long multi-step turn does not\n * flood the transcript. Below it, tool rows render inline as before. */\nconst COLLAPSE_TOOL_RUN_AT = 3\n\n/** A tool call the user must not miss even in a settled run — a failure (by\n * status OR by an `ok:false` outcome, the shared `toolCallFailed` predicate),\n * a card awaiting their approval, or a tool still `running` after the turn has\n * settled (i.e. stuck / timed out). A run containing one is NEVER collapsed, so\n * a failed, blocked, or stuck turn can't hide behind a \"Worked through N steps\"\n * summary and read as successful. */\nfunction isImportantTool(call: ChatToolCallInfo): boolean {\n return (\n call.status === 'running' ||\n toolCallFailed(call) ||\n pendingApprovalOf(call) !== null\n )\n}\n\n/** Renders a turn's ordered text/tool segments interleaved. The trailing text\n * run carries the streaming caret; if the last segment is instead a tool, a\n * trailing caret keeps the gap before the next run from looking frozen. Any\n * `toolCalls` not represented in `segments` (a partially-migrated producer that\n * set both) still render, so a tool row is never silently dropped. A settled\n * run of many tool calls collapses into one disclosure — see below. */\nfunction SegmentedBody({\n segments,\n msg,\n streaming,\n renderBody,\n approval,\n onToolCallClick,\n toolRenderers,\n messageClassName,\n}: {\n segments: ChatMessageSegment[]\n msg: ChatUiMessage\n streaming: boolean\n renderBody: (content: string) => ReactNode\n approval?: ProposalApprovalHandlers\n onToolCallClick?: (call: ChatToolCallInfo, message: ChatUiMessage) => void\n toolRenderers?: ToolDetailRenderers\n messageClassName: string\n}) {\n const lastIndex = segments.length - 1\n const segmentToolIds = new Set(\n segments.flatMap((s) => (s.kind === 'tool' ? [s.call.id] : [])),\n )\n const leftoverToolCalls = (msg.toolCalls ?? []).filter(\n (tc) => !segmentToolIds.has(tc.id),\n )\n const renderToolCard = (call: ChatToolCallInfo) => (\n <ToolCallCard\n key={`tool-${call.id}`}\n call={call}\n message={msg}\n approval={approval}\n onOpenRun={onToolCallClick}\n renderers={toolRenderers}\n />\n )\n // Group consecutive tool segments so a SETTLED run of many tool calls (a\n // multi-step turn, e.g. workflow authoring) collapses into one disclosure\n // instead of flooding the transcript with a card per step. While the turn is\n // streaming nothing is grouped — live tool activity is exactly what the user\n // wants to watch; the run collapses once the turn settles. Text runs (the\n // actual answer) always render in full.\n const groups: Array<\n | { kind: 'text'; index: number; content: string }\n | { kind: 'tools'; index: number; calls: ChatToolCallInfo[] }\n > = []\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i]\n if (!seg) continue\n if (seg.kind === 'text') {\n groups.push({ kind: 'text', index: i, content: seg.content })\n } else {\n const last = groups[groups.length - 1]\n if (last && last.kind === 'tools') last.calls.push(seg.call)\n else groups.push({ kind: 'tools', index: i, calls: [seg.call] })\n }\n }\n\n return (\n <div className=\"flex flex-col gap-2\">\n {groups.map((g) =>\n g.kind === 'text' ? (\n <SegmentText\n // Segments only ever append within a turn, so the index is a stable\n // key — a finalized run keeps its slot as later runs/tools are added,\n // so its smooth-text state isn't reset.\n key={`text-${g.index}`}\n content={g.content}\n // Only the trailing run of the live turn types out + shows the caret.\n streaming={streaming && g.index === lastIndex}\n showCaret={streaming && g.index === lastIndex}\n renderBody={renderBody}\n messageClassName={messageClassName}\n />\n ) : !streaming &&\n g.calls.length >= COLLAPSE_TOOL_RUN_AT &&\n !g.calls.some(isImportantTool) ? (\n // The fold is a quiet disclosure line, not a filled box — the\n // canonical rows inside it carry the row chrome.\n <details key={`tools-${g.index}`}>\n <summary className=\"cursor-pointer select-none rounded-md px-1 py-0.5 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground\">\n Worked through {g.calls.length} steps\n </summary>\n <div className=\"mt-1.5 flex flex-col gap-1.5\">\n {g.calls.map(renderToolCard)}\n </div>\n </details>\n ) : (\n <div key={`tools-${g.index}`} className=\"flex flex-col gap-2\">\n {g.calls.map(renderToolCard)}\n </div>\n ),\n )}\n {leftoverToolCalls.map(renderToolCard)}\n {streaming && segments[lastIndex]?.kind === 'tool' && <StreamingCaret />}\n </div>\n )\n}\n\n// ── Quiet chrome ────────────────────────────────────────────────────────────\n\n/** The quiet chrome's per-row meta lane: a fixed ~18px strip that always\n * reserves its height (so the reveal is pure opacity — zero layout shift) and\n * fades in on row hover/focus-within, staying visible on touch via\n * `@media (hover: none)`. The fade is reduced-motion-guarded. */\nconst QUIET_META_LANE_CLASS =\n 'mt-1 flex h-[18px] items-center gap-2 text-[11px] tracking-wide text-muted-foreground opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100 motion-reduce:transition-none [@media(hover:none)]:opacity-100'\n\n/** The text a copy of the message should carry: the ordered text runs when the\n * turn is segmented (they render in place of `content`), else `content`. */\nfunction copyTextOf(msg: ChatUiMessage): string {\n const textRuns = msg.segments?.filter((s) => s.kind === 'text') ?? []\n if (textRuns.length > 0) return textRuns.map((s) => s.content).join('\\n\\n')\n return msg.content\n}\n\n/** Copies the message's plain text; swaps to a check for a beat on success.\n * Quiet chrome only — labeled mode's meta line is information, not action. */\nfunction CopyMessageButton({ text }: { text: string }) {\n const [copied, setCopied] = useState(false)\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n useEffect(\n () => () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current)\n },\n [],\n )\n const copy = () => {\n const clipboard = navigator.clipboard\n if (!clipboard) return\n void clipboard.writeText(text).then(\n () => {\n setCopied(true)\n if (timerRef.current !== null) clearTimeout(timerRef.current)\n timerRef.current = setTimeout(() => setCopied(false), 1200)\n },\n () => {},\n )\n }\n return (\n <button\n type=\"button\"\n onClick={copy}\n aria-label=\"Copy message\"\n title=\"Copy message\"\n className=\"rounded p-0.5 text-muted-foreground transition hover:bg-accent hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {copied ? (\n <svg className=\"h-3.5 w-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n ) : (\n <svg className=\"h-3.5 w-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n )}\n </button>\n )\n}\n\nfunction AssistantMessageImpl({\n msg,\n streaming,\n models,\n agentLabel,\n renderBody,\n approval,\n onToolCallClick,\n toolRenderers,\n renderExtras,\n durableCards,\n resolveAttachmentUrl,\n workProductCards,\n messageClassName,\n chrome,\n}: {\n msg: ChatUiMessage\n streaming: boolean\n models: CatalogModel[]\n agentLabel: string\n renderBody: (content: string) => ReactNode\n approval?: ProposalApprovalHandlers\n onToolCallClick?: (call: ChatToolCallInfo, message: ChatUiMessage) => void\n toolRenderers?: ToolDetailRenderers\n renderExtras?: (message: ChatUiMessage) => ReactNode\n durableCards?: Omit<DurableChatCardsProps, 'parts' | 'renderMarkdown'>\n resolveAttachmentUrl?: (part: ChatAttachmentPart) => string\n workProductCards?: { onOpen?: (part: WorkProductPersistedPart) => void }\n messageClassName: string\n chrome: 'labeled' | 'quiet'\n}) {\n // Smooth reveal: chunky network slabs (model bursts, flush windows, replay\n // polls) paint as a continuous typewriter. Reasoning often arrives as one\n // burst right before the answer — smoothing makes it visibly type out in\n // the open thinking box instead of popping in and collapsing.\n const content = useSmoothText(msg.content, streaming)\n const reasoning = useSmoothText(msg.reasoning ?? '', streaming)\n // The smooth reveal re-renders on every rAF frame while streaming, but the\n // FLOORED visible length only advances every few frames — re-parsing markdown\n // each frame is wasted work on the hot path. Memo on (renderBody, content) so\n // the parse runs only when the visible text actually changes.\n const body = useMemo(() => renderBody(content), [renderBody, content])\n // When a turn is segmented, render the ordered text/tool runs interleaved;\n // otherwise fall back to the single content body + trailing tool group.\n const segments = msg.segments\n // \"Has the answer started?\" — true once any answer text exists, whether the\n // producer puts it in `content` (legacy) or in a text `segment`. Drives the\n // reasoning box (open while still thinking, the thinking timer, the summary\n // label), so a segmented message with `content: ''` doesn't read as\n // perpetually \"Thinking…\" after its answer segments are visible.\n const hasAnswerText =\n content !== '' ||\n (segments?.some((s) => s.kind === 'text' && s.content.trim() !== '') ??\n false)\n const reasoningScrollRef = useRef<HTMLDivElement>(null)\n // Measure visible thinking time: first reasoning reveal → first answer text.\n const thinkStartRef = useRef<number | null>(null)\n const thinkMsRef = useRef<number | null>(null)\n if (streaming && reasoning && !hasAnswerText && thinkStartRef.current === null) {\n thinkStartRef.current = performance.now()\n }\n if (\n hasAnswerText &&\n thinkStartRef.current !== null &&\n thinkMsRef.current === null\n ) {\n thinkMsRef.current = performance.now() - thinkStartRef.current\n }\n useEffect(() => {\n const el = reasoningScrollRef.current\n if (el && streaming && !hasAnswerText) el.scrollTop = el.scrollHeight\n }, [reasoning, streaming, hasAnswerText])\n // Live seconds while the model is reasoning before its answer starts, so a\n // long thinking gap shows progress rather than a static \"Thinking…\".\n const thinkingSeconds = useThinkingSeconds(\n streaming && !!reasoning && !hasAnswerText,\n )\n\n const quiet = chrome === 'quiet'\n return (\n <div className={`mx-auto w-full max-w-3xl px-6 ${quiet ? 'group pb-1 pt-3' : 'py-3'}`}>\n {!quiet && (\n <div className=\"mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground\">\n <span className=\"font-semibold uppercase\">{agentLabel}</span>\n {msg.modelUsed && <span className=\"font-mono normal-case\">{msg.modelUsed}</span>}\n {formatTokensPerSecond(msg) && <span>{formatTokensPerSecond(msg)}</span>}\n {formatModelCost(msg, models) && <span>{formatModelCost(msg, models)}</span>}\n </div>\n )}\n {reasoning && (\n <details className=\"mb-2 rounded-lg border-l-2 border-border bg-secondary px-3 py-2\" open={!hasAnswerText}>\n <summary className=\"cursor-pointer select-none text-xs font-medium text-muted-foreground\">\n {!hasAnswerText ? (\n <span className=\"animate-pulse\">\n Thinking{thinkingSeconds >= 3 ? ` · ${thinkingSeconds}s` : '…'}\n </span>\n ) : thinkMsRef.current != null ? (\n `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1000))}s`\n ) : (\n 'Thought process'\n )}\n </summary>\n <div ref={reasoningScrollRef} className=\"mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-[13px] leading-relaxed text-muted-foreground\">\n {reasoning}\n </div>\n </details>\n )}\n {segments && segments.length > 0 ? (\n <SegmentedBody\n segments={segments}\n msg={msg}\n streaming={streaming}\n renderBody={renderBody}\n approval={approval}\n onToolCallClick={onToolCallClick}\n toolRenderers={toolRenderers}\n messageClassName={messageClassName}\n />\n ) : (\n <>\n <div className={messageClassName}>\n {body}\n {streaming && content && !msg.toolCalls?.length && <StreamingCaret />}\n </div>\n {msg.toolCalls && msg.toolCalls.length > 0 && (\n <div className=\"mt-2 flex flex-col gap-1.5\">\n {msg.toolCalls.map((tc) => (\n <ToolCallCard\n key={tc.id}\n call={tc}\n message={msg}\n approval={approval}\n onOpenRun={onToolCallClick}\n renderers={toolRenderers}\n />\n ))}\n </div>\n )}\n </>\n )}\n {durableCards && msg.parts && (\n <DurableChatCards\n {...durableCards}\n parts={msg.parts}\n renderMarkdown={renderBody}\n className=\"mt-3\"\n />\n )}\n {workProductCards &&\n workProductPartsFromMessageParts(msg.parts).map((part) => (\n <WorkProductCard\n key={`${part.ref.id}:${part.ref.version}`}\n part={part}\n onOpen={workProductCards.onOpen}\n className=\"mt-3\"\n />\n ))}\n {renderExtras?.(msg)}\n {resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && (\n <div className=\"mt-2\">\n <MessageAttachments\n parts={attachmentPartsFromMessageParts(msg.parts)}\n resolveFileUrl={resolveAttachmentUrl}\n justify=\"start\"\n />\n </div>\n )}\n {quiet && (\n <div data-testid=\"message-meta-lane\" className={QUIET_META_LANE_CLASS}>\n <CopyMessageButton text={copyTextOf(msg)} />\n {msg.modelUsed && <span className=\"font-mono\">{msg.modelUsed}</span>}\n {formatTokensPerSecond(msg) && <span>{formatTokensPerSecond(msg)}</span>}\n {formatModelCost(msg, models) && <span>{formatModelCost(msg, models)}</span>}\n </div>\n )}\n </div>\n )\n}\n\n/**\n * Only the actively-streaming message changes per frame; historical messages\n * are referentially stable. `memo` keeps a stable `AssistantMessage` from\n * re-rendering (and re-running its markdown parse) when a sibling streams —\n * default shallow-equal prop comparison is exactly right here since every prop\n * is referentially stable except the one being streamed.\n */\nconst AssistantMessage = memo(AssistantMessageImpl)\n\n/** Whole seconds elapsed while `active`, ticking once a second. Powers the live\n * \"thinking\" timers (the pre-first-token row and the reasoning box) so a long\n * thinking gap shows progress instead of a frozen label. Counts from when\n * `active` first turns true; freezes when it clears. */\nexport function useThinkingSeconds(active: boolean): number {\n const [seconds, setSeconds] = useState(0)\n useEffect(() => {\n if (!active) return\n // Reset on each (re)activation so a reused component resuming \"thinking\"\n // counts from 0 rather than showing the prior phase's stale elapsed time.\n setSeconds(0)\n const id = setInterval(() => setSeconds((s) => s + 1), 1000)\n return () => clearInterval(id)\n }, [active])\n return seconds\n}\n\nfunction ThinkingRow({ agentLabel, chrome = 'labeled' }: { agentLabel: string; chrome?: 'labeled' | 'quiet' }) {\n const seconds = useThinkingSeconds(true)\n return (\n <div className=\"mx-auto w-full max-w-3xl px-6 py-3\">\n {chrome !== 'quiet' && (\n <p className=\"mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground\">{agentLabel}</p>\n )}\n <div className=\"flex items-center gap-2 text-base text-muted-foreground\">\n <svg className=\"h-4 w-4 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" strokeLinecap=\"round\" />\n </svg>\n Thinking{seconds >= 3 ? ` · ${seconds}s` : '...'}\n </div>\n </div>\n )\n}\n\n/** Top-level turn-failure row with an optional Retry — the affordance a failed\n * stream otherwise lacks (the turn just stopped). */\nfunction StreamErrorRow({ message, onRetry }: { message: string; onRetry?: () => void }) {\n return (\n <div className=\"mx-auto w-full max-w-3xl px-6 py-3\">\n <div role=\"alert\" className=\"flex items-start gap-2.5 rounded-lg border border-destructive/40 bg-destructive/5 px-3 py-2.5 text-sm text-destructive\">\n <svg className=\"mt-0.5 h-4 w-4 shrink-0\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M12 8v4m0 4h.01\" />\n </svg>\n <span className=\"min-w-0 flex-1 break-words\">{message}</span>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className={`shrink-0 rounded border border-destructive/40 bg-card px-2 py-0.5 text-[11px] font-medium text-destructive transition hover:bg-destructive/10 ${POPOVER_OPTION_FOCUS}`}\n >\n Retry\n </button>\n )}\n </div>\n </div>\n )\n}\n\n/**\n * The message thread: one centered column; user messages are right-aligned\n * bubbles with a User label; agent messages carry an Agent meta line with\n * model id, tokens/sec, and cost, plus a collapsible thinking section and\n * tool rows. `chrome=\"quiet\"` opts into the label-free variant: the\n * label/meta row becomes a hover-revealed meta lane under each row.\n */\nexport function ChatMessages({\n messages,\n messageSize = 'default',\n chrome = 'labeled',\n models = [],\n renderMarkdown,\n renderExtras,\n durableCards,\n userLabel = 'User',\n agentLabel = 'Agent',\n loading,\n approval,\n onToolCallClick,\n toolRenderers,\n error,\n onRetry,\n renderEmpty,\n emptyState,\n header,\n resolveAttachmentUrl,\n workProductCards,\n}: ChatMessagesProps) {\n const messageClassName =\n messageSize === 'large'\n ? 'agent-app-message-copy text-[17px] leading-[1.75]'\n : 'agent-app-message-copy text-base leading-[1.75]'\n // Stabilize the fallback renderer's identity so it doesn't change every\n // render — otherwise the memoized `AssistantMessage` (and its per-frame body\n // memo) would invalidate on every parent render when no `renderMarkdown` is\n // supplied.\n const renderBody = useMemo(\n () => renderMarkdown ?? ((content: string) => <p className=\"whitespace-pre-wrap\">{content}</p>),\n [renderMarkdown],\n )\n const lastIsUser = messages[messages.length - 1]?.role === 'user'\n const quiet = chrome === 'quiet'\n if (messages.length === 0 && !loading && !error) {\n // Explicit renderEmpty wins (incl. `() => null` to opt out); otherwise show\n // the branded first-run state instead of a blank thread.\n const empty = renderEmpty ? renderEmpty() : <ChatEmptyState {...emptyState} />\n return (\n <>\n {header}\n {empty}\n </>\n )\n }\n return (\n <>\n {header}\n {messages.map((msg) =>\n msg.role === 'user' ? (\n <div key={msg.id} className={`mx-auto w-full max-w-3xl px-6 ${quiet ? 'group pb-1 pt-3' : 'py-3'}`}>\n <div className={`ml-auto w-fit ${quiet ? 'max-w-[72%]' : 'max-w-[85%]'}`}>\n {!quiet && (\n <p className=\"mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground\">\n {userLabel}\n </p>\n )}\n <div\n className={\n quiet\n ? `rounded-2xl bg-[color-mix(in_srgb,hsl(var(--secondary))_65%,hsl(var(--background)))] px-4 py-2.5 ${messageClassName}`\n : `rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 ${messageClassName}`\n }\n >\n <p className=\"whitespace-pre-wrap\">{msg.content}</p>\n </div>\n {resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && (\n <div className=\"mt-1.5\">\n <MessageAttachments\n parts={attachmentPartsFromMessageParts(msg.parts)}\n resolveFileUrl={resolveAttachmentUrl}\n justify=\"end\"\n />\n </div>\n )}\n </div>\n {quiet && (\n <div data-testid=\"message-meta-lane\" className={`${QUIET_META_LANE_CLASS} justify-end`}>\n <CopyMessageButton text={msg.content} />\n </div>\n )}\n </div>\n ) : (\n <AssistantMessage\n key={msg.id}\n msg={msg}\n streaming={!!loading && msg.id === messages[messages.length - 1]?.id}\n models={models}\n agentLabel={agentLabel}\n renderBody={renderBody}\n approval={approval}\n onToolCallClick={onToolCallClick}\n toolRenderers={toolRenderers}\n renderExtras={renderExtras}\n durableCards={durableCards}\n resolveAttachmentUrl={resolveAttachmentUrl}\n workProductCards={workProductCards}\n messageClassName={messageClassName}\n chrome={chrome}\n />\n ),\n )}\n {loading && lastIsUser && <ThinkingRow agentLabel={agentLabel} chrome={chrome} />}\n {error && !loading && <StreamErrorRow message={error} onRetry={onRetry} />}\n </>\n )\n}\n","/**\n * Smooth text reveal — turns chunky network deltas into a continuous\n * typewriter paint. Streamed turns arrive in 100-500ms slabs (model burst,\n * flush windows, replay polls); revealing characters at an adaptive rate\n * makes the same bytes read as top-tier streaming. The rate scales with the\n * backlog so the reveal never falls behind the stream — it crawls when caught\n * up and sprints when a burst lands (e.g. a reasoning summary arriving all at\n * once still *types out* instead of popping in).\n */\n\nimport { useEffect, useRef, useState } from 'react'\n\n/** Define configuration options for controlling smooth text reveal animation rates */\nexport interface SmoothRevealOptions {\n /** Baseline reveal rate when nearly caught up. Default 90 chars/s. */\n baseCharsPerSecond?: number\n /** Extra chars/s per backlog character — the catch-up pressure. Default 5. */\n catchUpPerChar?: number\n /** Hard ceiling so giant bursts still animate. Default 2400 chars/s. */\n maxCharsPerSecond?: number\n}\n\n/** Pure reveal step: how many characters should be visible after `dtMs`.\n * Exposed for tests; the hook is a thin rAF wrapper around it. */\nexport function nextRevealCount(\n shown: number,\n targetLength: number,\n dtMs: number,\n opts: SmoothRevealOptions = {},\n): number {\n if (shown >= targetLength) return targetLength\n const base = opts.baseCharsPerSecond ?? 90\n const catchUp = opts.catchUpPerChar ?? 5\n const max = opts.maxCharsPerSecond ?? 2400\n const backlog = targetLength - shown\n const rate = Math.min(max, base + backlog * catchUp)\n return Math.min(targetLength, shown + (rate * dtMs) / 1000)\n}\n\n/**\n * Animate `target` text into view. While `enabled`, the returned string grows\n * smoothly toward `target` (which may itself keep growing); when `enabled` is\n * false the full text returns immediately (history, completed turns). A\n * target that is not an extension of the revealed prefix (new message) resets\n * the reveal.\n */\nexport function useSmoothText(target: string, enabled: boolean, opts?: SmoothRevealOptions): string {\n const [, force] = useState(0)\n const shownRef = useRef(0)\n const lastTargetRef = useRef('')\n\n // New message / rewritten prefix → restart the reveal from zero.\n if (!target.startsWith(lastTargetRef.current.slice(0, Math.floor(shownRef.current)))) {\n shownRef.current = 0\n }\n lastTargetRef.current = target\n if (!enabled) shownRef.current = target.length\n\n useEffect(() => {\n if (!enabled) return\n let raf = 0\n let last: number | null = null\n const tick = (t: number) => {\n const dt = last == null ? 16 : Math.min(t - last, 100)\n last = t\n const targetLen = lastTargetRef.current.length\n if (shownRef.current < targetLen) {\n shownRef.current = nextRevealCount(shownRef.current, targetLen, dt, opts)\n force((n) => n + 1)\n // Keep painting while there is still backlog to reveal.\n raf = requestAnimationFrame(tick)\n }\n // Caught up: stop the loop. A later `target` growth re-renders this hook\n // (target is read fresh below), and the next render's effect — re-run\n // because `target` is a dep — restarts the loop. Idle messages spawn no\n // rAF, so a full thread of completed turns is dormant.\n }\n raf = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(raf)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, target])\n\n return target.slice(0, Math.floor(shownRef.current))\n}\n","/**\n * Load the canonical Tangle knot only when a web surface renders it.\n * `/brand` imports the optional `@tangle-network/brand` peer, so a failed load\n * renders a fixed-size spacer instead of crashing the chat shell.\n */\n\nimport { lazy, Suspense } from 'react'\nimport type { ComponentType } from 'react'\n\ninterface BrandMarkProps {\n size?: number\n className?: string\n}\n\n/** Preserve the mark's footprint while its optional package loads or is absent. */\nfunction MarkSpacer({ size = 24, className }: BrandMarkProps) {\n return <span aria-hidden style={{ display: 'inline-block', width: size, height: size }} className={className} />\n}\n\nconst LazyKnot = lazy(async () => {\n try {\n const mod = await import('../brand')\n return { default: mod.TangleKnot as ComponentType<BrandMarkProps> }\n } catch {\n return { default: MarkSpacer as ComponentType<BrandMarkProps> }\n }\n})\n\nexport function BrandMark({ size = 24, className }: BrandMarkProps) {\n return (\n <Suspense fallback={<MarkSpacer size={size} className={className} />}>\n <LazyKnot size={size} className={className} />\n </Suspense>\n )\n}\n","import { useEffect, useState, type ReactNode } from 'react'\nimport type { ChatPlan } from '../plans/index'\nimport type {\n DurablePlanDecision,\n DurablePlanDecisionResult,\n} from './durable-plan-flow'\nimport { InteractionActionButton, InteractionBadge } from './interaction-question-card'\n\nexport interface DurablePlanCardProps {\n plan: ChatPlan\n canWrite: boolean\n decide: (decision: DurablePlanDecision, feedback?: string) => Promise<DurablePlanDecisionResult | null>\n deciding?: DurablePlanDecision | null\n error?: string | null\n renderMarkdown?: (markdown: string) => ReactNode\n className?: string\n}\n\nfunction statusLabel(plan: ChatPlan): string {\n switch (plan.status) {\n case 'pending': return 'Waiting for your decision'\n case 'approved': return 'Approved'\n case 'rejected': return 'Changes requested'\n case 'superseded': return 'Superseded'\n case 'withdrawn': return 'Withdrawn'\n default: return 'Preparing'\n }\n}\n\nexport function DurablePlanCard({\n plan,\n canWrite,\n decide,\n deciding = null,\n error,\n renderMarkdown,\n className,\n}: DurablePlanCardProps) {\n const [feedback, setFeedback] = useState('')\n const [expanded, setExpanded] = useState(false)\n const [localError, setLocalError] = useState<string | null>(null)\n useEffect(() => setLocalError(null), [plan.planId, plan.revision, plan.status])\n\n const actionable = plan.status === 'pending'\n const disabled = !canWrite || !actionable || deciding !== null\n\n async function submit(decision: DurablePlanDecision) {\n const trimmed = feedback.trim()\n if (decision === 'rejected' && !trimmed) {\n setLocalError('Describe what you want changed before requesting a revision.')\n return\n }\n setLocalError(null)\n await decide(decision, decision === 'rejected' ? trimmed : undefined)\n }\n\n return (\n <div className={`rounded-xl border border-primary/40 bg-card p-4 ${className ?? ''}`}>\n <div className=\"mb-3 flex flex-wrap items-center justify-between gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <InteractionBadge variant=\"outline\">Plan decision</InteractionBadge>\n <InteractionBadge variant={plan.status === 'approved' ? 'default' : plan.status === 'rejected' || plan.status === 'withdrawn' ? 'destructive' : 'outline'}>\n {statusLabel(plan)}\n </InteractionBadge>\n </div>\n <span className=\"text-xs text-muted-foreground\">Revision {plan.revision}</span>\n </div>\n {plan.title && <p className=\"mb-3 text-sm font-medium leading-5 text-foreground\">{plan.title}</p>}\n <div className=\"relative\">\n <div className=\"overflow-hidden text-sm\" style={expanded ? undefined : { maxHeight: 320 }}>\n {renderMarkdown ? renderMarkdown(plan.body) : <p className=\"whitespace-pre-wrap leading-5\">{plan.body}</p>}\n </div>\n {!expanded && <div className=\"pointer-events-none absolute inset-x-0 bottom-0 h-12 bg-gradient-to-t from-card to-transparent\" />}\n <button\n type=\"button\"\n onClick={() => setExpanded((value) => !value)}\n className=\"mt-1 text-xs text-muted-foreground hover:text-foreground\"\n >\n {expanded ? 'Collapse plan' : 'Show full plan'}\n </button>\n </div>\n {actionable && (\n <div className=\"mt-3 space-y-2\">\n <label className=\"block text-sm font-medium leading-5 text-foreground\" htmlFor={`durable-plan-feedback-${plan.planId}-${plan.revision}`}>\n Feedback for requested changes\n </label>\n <textarea\n id={`durable-plan-feedback-${plan.planId}-${plan.revision}`}\n value={feedback}\n disabled={disabled}\n onChange={(event) => setFeedback(event.target.value)}\n rows={2}\n placeholder=\"Describe what you want changed in the plan\"\n className=\"w-full rounded-lg border border-border bg-background px-3 py-2 text-sm focus:border-primary disabled:opacity-50\"\n />\n </div>\n )}\n {(localError ?? error) && <p className=\"mt-3 text-xs text-destructive\">{localError ?? error}</p>}\n {actionable && (\n <div className=\"mt-4 flex items-center justify-end gap-2\">\n <InteractionActionButton variant=\"outline\" onClick={() => void submit('rejected')} disabled={disabled}>\n {deciding === 'rejected' ? 'Sending…' : 'Request changes'}\n </InteractionActionButton>\n <InteractionActionButton onClick={() => void submit('approved')} disabled={disabled}>\n {deciding === 'approved' ? 'Approving…' : 'Approve plan'}\n </InteractionActionButton>\n </div>\n )}\n </div>\n )\n}\n","/**\n * InteractionQuestionCard — the agent-ask card every sandbox-backed chat UI\n * forked (~1,000 lines each in gtm/legal/tax). Renders the answerSpec\n * verbatim: selects (radio/checkbox by `multi`, write-in row only when the\n * sidecar granted `allowCustom`), free text, and minimal number/boolean/secret\n * inputs for open kinds.\n *\n * Behavior lifted from the gtm-agent fork (the most fix-absorbed):\n * - a terminal stream status always wins over local optimistic state,\n * - a 410 from the answer route flips the card to the same dead state a\n * cancel event produces (never a raw error),\n * - expired/withdrawn asks stay answerable: the answer is delivered as a NEW\n * chat turn via `onLateAnswer` (secret-bearing asks are blocked from that\n * path),\n * - one submit in flight at a time; a failed/timed-out submit stays\n * retryable.\n *\n * Pure data + callbacks: no fetch inside the component. Products bind the wire\n * via `createInteractionAnswerSubmitter` (or any `SubmitInteractionAnswer`).\n */\n\nimport { type ReactNode, useEffect, useMemo, useRef, useState } from 'react'\nimport type {\n ChatInteraction,\n ChatInteractionField,\n ChatInteractionStatus,\n ChatSelectField,\n ChatFreeTextField,\n} from './chat-interactions'\nimport { isTerminalInteractionStatus } from './chat-interactions'\nimport {\n buildAnswerData,\n fieldValuesFromAnswers,\n hasSecretField,\n interactionStatusLabels,\n interactionTerminalNotes,\n isLateAnswerableStatus,\n lateAnswerMessage,\n settleInteractionSubmit,\n type FieldValues,\n type SubmitInteractionAnswer,\n} from './interaction-card-support'\n\n// ── glyphs + primitives (no icon-library / UI-kit dependency) ───────────────\n\nfunction CheckGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n )\n}\n\nexport type InteractionBadgeVariant = 'outline' | 'default' | 'destructive'\n\nconst BADGE_VARIANT_CLASSES: Record<InteractionBadgeVariant, string> = {\n outline: 'border-border text-foreground',\n default: 'border-transparent bg-primary text-primary-foreground',\n destructive: 'border-transparent bg-destructive/15 text-destructive',\n}\n\nexport function InteractionBadge({ variant, children }: { variant: InteractionBadgeVariant; children: string }) {\n return (\n <span className={`inline-flex items-center rounded-md border px-2 py-0.5 text-xs font-medium ${BADGE_VARIANT_CLASSES[variant]}`}>\n {children}\n </span>\n )\n}\n\nexport function InteractionActionButton({\n variant = 'primary',\n onClick,\n disabled,\n children,\n}: {\n variant?: 'primary' | 'outline'\n onClick: () => void\n disabled?: boolean\n children: string\n}) {\n const variantClasses = variant === 'primary'\n ? 'bg-primary text-primary-foreground shadow-sm hover:bg-primary/90'\n : 'border border-border bg-transparent text-foreground hover:bg-accent'\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n className={`inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium transition disabled:cursor-not-allowed disabled:opacity-40 ${variantClasses}`}\n >\n {children}\n </button>\n )\n}\n\nconst FIELD_INPUT_CLASSES =\n 'w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground focus:border-primary disabled:opacity-50'\n\n// ── option rows ─────────────────────────────────────────────────────────────\n\nexport interface QuestionOptionListProps {\n /** Radio/checkbox group name — unique per field so selection is isolated. */\n groupName: string\n /** Stable prefix for per-option input ids (label htmlFor pairing). */\n idPrefix: string\n options: ChatSelectField['options']\n /** Checkbox (multi-select) vs radio (single). */\n multi: boolean\n selectedValues: string[]\n disabled: boolean\n onToggle: (value: string) => void\n}\n\n/** The radio/checkbox option rows for a select field. Renders a fragment of\n * option `<label>` rows so a card keeps its own wrapping layout and appends\n * its own write-in input. */\nexport function QuestionOptionList({\n groupName,\n idPrefix,\n options,\n multi,\n selectedValues,\n disabled,\n onToggle,\n}: QuestionOptionListProps) {\n return (\n <>\n {options.map((option, optionIndex) => {\n const inputId = `${idPrefix}-${optionIndex}`\n const checked = selectedValues.includes(option.value)\n // The whole row is a wrapping <label> for click target, but the input's\n // accessible NAME must be the option label alone — the description is\n // linked as aria-describedby, not folded into the name.\n return (\n <label key={`${option.value}-${optionIndex}`} htmlFor={inputId} className=\"flex cursor-pointer gap-2 rounded-lg border border-strong p-3 transition-colors hover:bg-accent\">\n <input\n id={inputId}\n type={multi ? 'checkbox' : 'radio'}\n name={groupName}\n value={option.value}\n checked={checked}\n disabled={disabled}\n onChange={() => onToggle(option.value)}\n aria-labelledby={`${inputId}-label`}\n aria-describedby={option.description ? `${inputId}-description` : undefined}\n className=\"mt-0.5 h-4 w-4 shrink-0 accent-primary\"\n />\n <span className=\"min-w-0\">\n <span id={`${inputId}-label`} className=\"block text-sm font-medium leading-5 text-foreground\">{option.label}</span>\n {option.description && <span id={`${inputId}-description`} className=\"mt-0.5 block text-xs leading-5 text-muted-foreground\">{option.description}</span>}\n </span>\n </label>\n )\n })}\n </>\n )\n}\n\n// ── card ────────────────────────────────────────────────────────────────────\n\nexport interface InteractionQuestionCardProps {\n interaction: ChatInteraction\n /** Viewer-vs-editor gate: false renders everything read-only. */\n canWrite: boolean\n /** POST one resolution to the product's answer route (see\n * `createInteractionAnswerSubmitter`). Never called for late answers. */\n submitAnswer: SubmitInteractionAnswer\n /** Fired when this card resolves locally (answered, or discovered expired\n * via a 410) so the stream/route state stays in sync. */\n onResolved?: (\n id: string,\n status: Exclude<ChatInteractionStatus, 'pending'>,\n answers?: ChatInteraction['answers'],\n ) => void\n /** Delivers a late answer (the ask expired/was withdrawn) as a fresh chat\n * turn. Return/resolve `false` when the send was rejected so the card stays\n * retryable. Omit to hide the late-answer affordance entirely. */\n onLateAnswer?: (message: string) => boolean | void | Promise<boolean | void>\n /** Overrides the kind badge (\"Question\"). */\n kindLabel?: string\n /** Overrides the header note (\"The agent asked for input\"). Set it whenever an\n * agent is not the one asking — a host that parks on a human at the graph\n * level is not an agent's mid-run question, and a card that claims otherwise\n * misreports why the work stopped. */\n sourceNote?: string\n /** What happens if nobody answers, rendered beside the submit action.\n *\n * The caller owns both the clock and the copy: this card holds no timer, so a\n * deadline that counts down re-renders on the caller's cadence rather than\n * driving one of its own — and the consequence of silence (\"the default is\n * taken\", \"the run fails\") is the host's policy to state, not this card's to\n * infer. */\n timeoutNote?: ReactNode\n /** Renders `body` as markdown. Omitted, `body` renders as plain text — so a\n * host that passes authored markdown without this shows its syntax raw.\n *\n * `body` ONLY. `title` and every `field.label` stay plain strings: a label is\n * also the input's accessible name (`aria-label`), which has to be text, and\n * rendering one as nodes would either break that or silently disagree with\n * what a screen reader announces. Put prose in `body`.\n *\n * `interaction.body` is untrusted: it arrives off the wire, written by an\n * agent or whoever authored the ask. This card never injects HTML, but a\n * renderer that does is an XSS sink — so return React elements, and sanitize\n * (DOMPurify or equivalent) if you must produce HTML. */\n renderMarkdown?: (markdown: string) => ReactNode\n className?: string\n}\n\nfunction selectField(field: ChatInteractionField): ChatSelectField | null {\n return field.type === 'select' ? (field as ChatSelectField) : null\n}\n\n/** The free-text fields, which are the only ones that can carry a length cap. */\nfunction freeTextField(field: ChatInteractionField): ChatFreeTextField | null {\n return field.type === 'text' || field.type === 'secret' ? (field as ChatFreeTextField) : null\n}\n\n/** The cap to stop typing at, or `undefined` for an uncapped field. A\n * non-positive or fractional cap is treated as absent rather than clamping the\n * field to zero characters — an unanswerable field is worse than an uncapped\n * one, and the answer route still enforces the real bound. */\nfunction textFieldMaxLength(field: ChatFreeTextField): number | undefined {\n const max = field.maxLength\n return typeof max === 'number' && Number.isInteger(max) && max > 0 ? max : undefined\n}\n\nfunction valuesWithSelected(values: FieldValues, field: ChatSelectField, optionValue: string): FieldValues {\n const current = values[field.name]?.selected ?? []\n let selected = [optionValue]\n if (field.multi === true) {\n selected = current.includes(optionValue)\n ? current.filter((item) => item !== optionValue)\n : [...current, optionValue]\n }\n return { ...values, [field.name]: { ...values[field.name], selected } }\n}\n\nconst STATUS_LABELS = interactionStatusLabels({\n pending: 'Waiting for your answer',\n answered: 'Answered',\n declined: 'Declined',\n})\n\nconst TERMINAL_NOTES = interactionTerminalNotes('question', {\n expired: 'The original run ended. Answer now to send a new message with this context.',\n cancelled: 'The agent withdrew this question. Answer now to send a new message with this context.',\n})\n\nexport function InteractionQuestionCard({\n interaction,\n canWrite,\n submitAnswer,\n onResolved,\n onLateAnswer,\n kindLabel,\n sourceNote,\n timeoutNote,\n renderMarkdown,\n className,\n}: InteractionQuestionCardProps) {\n const [values, setValues] = useState<FieldValues>(() =>\n fieldValuesFromAnswers(interaction.fields, interaction.answers))\n const [submitting, setSubmitting] = useState(false)\n // Terminal state this card learned locally (submit success / 410) before the\n // stream part catches up. A terminal stream status always wins.\n const [localStatus, setLocalStatus] = useState<Exclude<ChatInteractionStatus, 'pending'> | null>(null)\n const [lateAnswerSent, setLateAnswerSent] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const submitInFlightRef = useRef(false)\n // The ask this card's state currently belongs to. State, never a ref: it is\n // compared and written during render, and a ref would not be transactional\n // with the resets below. React may abandon a render — the discarded pass's\n // `setValues` would be thrown away while a ref mutation survived it, leaving\n // this guard claiming the reset had happened over the previous ask's answers.\n const [askId, setAskId] = useState(interaction.id)\n\n // Every answer-bearing piece of state belongs to ONE ask, so being handed the\n // NEXT one starts over. A host can resolve one question and be handed another\n // on the same card instance (a run that re-parks, a queue that advances); left\n // alone, the new question would render with the previous answer already\n // filled in and its terminal chrome still showing — one click from submitting\n // an answer to a question the user never read.\n //\n // Keyed on `id` because `id` IS the ask's identity: a different id is a\n // different question. Re-issuing the same id with different fields is\n // therefore NOT a new ask and deliberately does not reset — an answer already\n // typed against those fields survives. A host that changes what it is asking\n // must change the id; what it may re-send under one id is the answer, which\n // arrives as `answers` and resyncs through the effect below.\n //\n // During render, not in an effect — React's documented \"adjusting state when\n // a prop changes\" pattern: it re-runs this component immediately with the new\n // state, before committing and before rendering children, so nothing escapes\n // the render phase. An effect would instead commit one frame of the previous\n // answer under the new question before clearing it. `submitting` and\n // `submitInFlightRef` are deliberately NOT reset — they are owned by the\n // in-flight request's `finally`, and clearing them here would let a second\n // submit start while the first is still outstanding.\n //\n // The visible cost: an id that changes WHILE a submit is outstanding leaves\n // the new question reading \"Submitting…\" and disabled until that request\n // settles. Bounded, because `settleInteractionSubmit` holds the submitter to\n // this card's own deadline rather than trusting it to have one. Preferred to\n // the alternative, since the only way to free the button early is to drop the\n // in-flight guard, and a second submit racing the first is a real bug where a\n // stale label is only a confusing one.\n if (askId !== interaction.id) {\n setAskId(interaction.id)\n setValues(fieldValuesFromAnswers(interaction.fields, interaction.answers))\n setLocalStatus(null)\n setLateAnswerSent(false)\n setError(null)\n }\n\n useEffect(() => {\n if (!interaction.answers) return\n setValues(fieldValuesFromAnswers(interaction.fields, interaction.answers))\n }, [interaction.answers, interaction.fields])\n\n const status: ChatInteractionStatus = isTerminalInteractionStatus(interaction.status)\n ? interaction.status\n : localStatus ?? interaction.status\n const answered = status === 'answered'\n const lateAnswerable = isLateAnswerableStatus(status) && onLateAnswer !== undefined\n const secretLateAnswerBlocked = lateAnswerable && hasSecretField(interaction.fields)\n const canLateAnswer = canWrite && lateAnswerable && !lateAnswerSent && !secretLateAnswerBlocked\n const disabled = !canWrite || (status !== 'pending' && !canLateAnswer) || submitting\n const answerData = useMemo(() => buildAnswerData(interaction.fields, values), [interaction.fields, values])\n\n const setFieldValue = (name: string, patch: FieldValues[string]) => {\n setValues((prev) => ({ ...prev, [name]: { ...prev[name], ...patch } }))\n }\n\n const toggleSelected = (field: ChatSelectField, optionValue: string) => {\n setValues((prev) => valuesWithSelected(prev, field, optionValue))\n }\n\n async function submitLateAnswer() {\n if (submitInFlightRef.current || !canLateAnswer || !onLateAnswer) return\n const data = buildAnswerData(interaction.fields, values)\n if (!data) return\n submitInFlightRef.current = true\n setSubmitting(true)\n setError(null)\n let accepted: boolean | void\n try {\n accepted = await onLateAnswer(lateAnswerMessage(interaction, data))\n } catch {\n accepted = false\n } finally {\n submitInFlightRef.current = false\n setSubmitting(false)\n }\n if (accepted === false) {\n setError('The new message was not sent. Try again from this card.')\n return\n }\n setLateAnswerSent(true)\n }\n\n async function submit() {\n if (lateAnswerable) {\n await submitLateAnswer()\n return\n }\n if (submitInFlightRef.current || disabled || !answerData) return\n submitInFlightRef.current = true\n setSubmitting(true)\n setError(null)\n try {\n const result = await settleInteractionSubmit(() =>\n submitAnswer({ id: interaction.id, outcome: 'accepted', data: answerData }),\n )\n if (result.ok) {\n setLocalStatus('answered')\n onResolved?.(interaction.id, 'answered', answerData)\n return\n }\n if (result.expired) {\n // The ask is gone (answered elsewhere, timed out, or the session moved\n // on) — flip to the same dead state a cancel event produces.\n setLocalStatus('expired')\n onResolved?.(interaction.id, 'expired')\n return\n }\n setError(result.message)\n } finally {\n submitInFlightRef.current = false\n setSubmitting(false)\n }\n }\n\n const terminalNote = secretLateAnswerBlocked\n ? 'This question asked for a secret, so it cannot be sent as a new chat message. Ask the agent to request it again.'\n : TERMINAL_NOTES[status]\n const showSubmitButton = status === 'pending' || (canWrite && lateAnswerable && !lateAnswerSent)\n // Only while the ask is still open. The note says what happens if nobody\n // answers, which stops being true the moment somebody has — and a resolved\n // card still offering a countdown reads as though the answer did not land.\n // Shown to read-only viewers too: an ask about to settle itself is worth\n // knowing whether or not you are the one who can answer it.\n const showTimeoutNote = timeoutNote != null && status === 'pending'\n let submitLabel = 'Submit answer'\n if (lateAnswerable) {\n submitLabel = submitting ? 'Sending…' : 'Send as new message'\n } else if (submitting) {\n submitLabel = 'Submitting…'\n }\n\n return (\n <div className={`rounded-xl border border-card-edge bg-card p-4 ${className ?? ''}`}>\n <div className=\"mb-3 flex flex-wrap items-center justify-between gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <InteractionBadge variant=\"outline\">{kindLabel ?? 'Question'}</InteractionBadge>\n <InteractionBadge variant={answered ? 'default' : status === 'expired' || status === 'declined' ? 'destructive' : 'outline'}>\n {STATUS_LABELS[status]}\n </InteractionBadge>\n </div>\n <span className=\"text-xs text-muted-foreground\">{sourceNote ?? 'The agent asked for input'}</span>\n </div>\n\n {interaction.title.trim() && interaction.fields.every((field) => field.label !== interaction.title) && (\n <p className=\"mb-3 text-sm font-medium leading-5 text-foreground\">{interaction.title}</p>\n )}\n {interaction.body && (renderMarkdown\n ? <div className=\"mb-3 text-sm leading-5 text-muted-foreground\">{renderMarkdown(interaction.body)}</div>\n : <p className=\"mb-3 text-sm leading-5 text-muted-foreground\">{interaction.body}</p>)}\n\n <div className=\"space-y-4\">\n {interaction.fields.map((field) => {\n const value = values[field.name] ?? {}\n const select = selectField(field)\n const freeText = freeTextField(field)\n return (\n <fieldset key={field.name} className=\"space-y-2\">\n <p className=\"text-sm font-medium leading-5 text-foreground\">{field.label}</p>\n {select ? (\n <div className=\"space-y-2\">\n <QuestionOptionList\n groupName={`${interaction.id}-${field.name}`}\n idPrefix={`${interaction.id}-${field.name}`}\n options={select.options}\n multi={select.multi === true}\n selectedValues={value.selected ?? []}\n disabled={disabled}\n onToggle={(optionValue) => toggleSelected(select, optionValue)}\n />\n {select.allowCustom === true && (\n <input\n type=\"text\"\n value={value.custom ?? ''}\n disabled={disabled}\n onChange={(event) => setFieldValue(field.name, { custom: event.target.value })}\n placeholder=\"Other — type your own answer\"\n aria-label={`Custom answer for ${field.label}`}\n className={FIELD_INPUT_CLASSES}\n />\n )}\n </div>\n ) : field.type === 'boolean' ? (\n <div className=\"flex gap-4\">\n {(['true', 'false'] as const).map((boolValue) => (\n <label key={boolValue} className=\"flex cursor-pointer items-center gap-2 text-sm text-foreground\">\n <input\n type=\"radio\"\n name={`${interaction.id}-${field.name}`}\n value={boolValue}\n checked={(value.selected ?? [])[0] === boolValue}\n disabled={disabled}\n onChange={() => setFieldValue(field.name, { selected: [boolValue] })}\n className=\"h-4 w-4 accent-primary\"\n />\n {boolValue === 'true' ? 'Yes' : 'No'}\n </label>\n ))}\n </div>\n ) : field.type === 'number' ? (\n <input\n type=\"number\"\n value={value.text ?? ''}\n disabled={disabled}\n aria-label={field.label}\n onChange={(event) => setFieldValue(field.name, { text: event.target.value })}\n className={FIELD_INPUT_CLASSES}\n />\n ) : field.type === 'secret' ? (\n <input\n type=\"password\"\n value={value.text ?? ''}\n disabled={disabled}\n aria-label={field.label}\n onChange={(event) => setFieldValue(field.name, { text: event.target.value })}\n placeholder={field.placeholder}\n maxLength={freeText ? textFieldMaxLength(freeText) : undefined}\n className={FIELD_INPUT_CLASSES}\n />\n ) : (\n <textarea\n value={value.text ?? ''}\n disabled={disabled}\n aria-label={field.label}\n onChange={(event) => setFieldValue(field.name, { text: event.target.value })}\n rows={3}\n maxLength={freeText ? textFieldMaxLength(freeText) : undefined}\n placeholder={field.type === 'text' ? field.placeholder : undefined}\n className={FIELD_INPUT_CLASSES}\n />\n )}\n </fieldset>\n )\n })}\n </div>\n\n {/* Announced, not just shown: a submit that failed is the one thing on this\n card that changes without the reader having moved focus. */}\n {error && <p role=\"alert\" className=\"mt-3 text-xs text-destructive\">{error}</p>}\n {terminalNote && <p className=\"mt-3 text-xs text-muted-foreground\">{terminalNote}</p>}\n\n {(showSubmitButton || showTimeoutNote) && (\n <div className=\"mt-4 flex flex-wrap items-center justify-end gap-2\">\n {showTimeoutNote && (\n <div className=\"mr-auto text-xs text-muted-foreground\">{timeoutNote}</div>\n )}\n {showSubmitButton && (\n <InteractionActionButton onClick={() => void submit()} disabled={disabled || !answerData}>\n {submitLabel}\n </InteractionActionButton>\n )}\n </div>\n )}\n {answered && (\n <div className=\"mt-4 flex items-center justify-end\">\n <span className=\"inline-flex items-center gap-1 text-xs text-muted-foreground\"><CheckGlyph className=\"h-3 w-3\" />Answered</span>\n </div>\n )}\n {lateAnswerSent && (\n <div className=\"mt-4 flex items-center justify-end\">\n <span className=\"inline-flex items-center gap-1 text-xs text-muted-foreground\"><CheckGlyph className=\"h-3 w-3\" />Sent as new message</span>\n </div>\n )}\n </div>\n )\n}\n","/**\n * Shared answer-building + submit plumbing for the interaction cards\n * (question, plan). Client-safe, no React: cards own their state, this owns\n * the wire. Lifted from the gtm-agent fork (the most fix-absorbed of the three\n * product copies), including the 30s submit timeout that keeps a dead route\n * from wedging a card in \"Submitting…\".\n */\n\nimport type {\n ChatInteraction,\n ChatInteractionField,\n ChatInteractionStatus,\n ChatSelectField,\n InteractionAnswers,\n InteractionData,\n} from './chat-interactions'\n\n// ---------------------------------------------------------------------------\n// Card copy helpers\n\n/** Status-badge labels for an interaction card. `cancelled`/`expired` read the\n * same across cards; each card supplies its own verbs for the other states\n * (a question is answered/declined; a plan is approved/rejected). */\nexport function interactionStatusLabels(\n labels: { pending: string; answered: string; declined: string },\n): Record<ChatInteractionStatus, string> {\n return { cancelled: 'Withdrawn', expired: 'Expired', ...labels }\n}\n\n/** Terminal-state notes for an interaction card. The expiry/withdrawal lines\n * share one shape around the card's noun (\"question\"/\"plan\"); any extra notes\n * (e.g. a plan's `declined` revision line) merge on top. */\nexport function interactionTerminalNotes(\n noun: string,\n extra?: Partial<Record<ChatInteractionStatus, string>>,\n): Partial<Record<ChatInteractionStatus, string>> {\n return {\n expired: `This ${noun} expired — send a new message to continue.`,\n cancelled: `The agent withdrew this ${noun}.`,\n ...extra,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Answer building\n\n/** Define a record mapping field names to objects with optional selected, text, and custom string arrays or values */\nexport type FieldValues = Record<string, { selected?: string[]; text?: string; custom?: string }>\n\n/** Converts acknowledged, persisted answers back into the local field state\n * consumed by the shared cards. Persisted values are authoritative: this is\n * intentionally used only when an interaction carries `answers`, never to\n * guess an answer from the absence of an outstanding sidecar ask. */\nexport function fieldValuesFromAnswers(\n fields: ChatInteractionField[],\n answers: InteractionAnswers | undefined,\n): FieldValues {\n if (!answers) return {}\n const values: FieldValues = {}\n for (const field of fields) {\n const answer = answers[field.name]\n if (answer === undefined) continue\n if (field.type === 'select') {\n values[field.name] = { selected: Array.isArray(answer) ? [...answer] : [String(answer)] }\n } else if (field.type === 'boolean') {\n values[field.name] = { selected: [String(answer)] }\n } else {\n values[field.name] = { text: String(answer) }\n }\n }\n return values\n}\n\n/** The submitted value for one field, or null when it has no answer yet. */\nexport function fieldAnswer(field: ChatInteractionField, values: FieldValues): InteractionData[string] | null {\n const value = values[field.name] ?? {}\n if (field.type === 'select') {\n const custom = (field as ChatSelectField).allowCustom === true ? value.custom?.trim() : undefined\n const chosen = [...(value.selected ?? []), ...(custom ? [custom] : [])]\n if (field.multi !== true && custom) return [custom]\n return chosen.length > 0 ? chosen : null\n }\n if (field.type === 'number') {\n const parsed = Number(value.text)\n return value.text?.trim() && Number.isFinite(parsed) ? parsed : null\n }\n if (field.type === 'boolean') return value.selected ? value.selected[0] === 'true' : null\n const text = value.text?.trim()\n return text ? text : null\n}\n\n/** All required fields answered → the respond payload; else null (not\n * submittable yet). Optional unanswered fields are omitted. */\nexport function buildAnswerData(fields: ChatInteractionField[], values: FieldValues): InteractionData | null {\n const data: InteractionData = {}\n for (const field of fields) {\n const answer = fieldAnswer(field, values)\n if (answer === null) {\n if (field.required === false) continue\n return null\n }\n data[field.name] = answer\n }\n return data\n}\n\n// ---------------------------------------------------------------------------\n// Late answers (question card): an expired/withdrawn ask can still be sent as\n// a NEW chat turn carrying the question context, so the user's typed answer is\n// never dropped on the floor.\n\n/** Determine if a status is late answerable by checking if it is expired or cancelled */\nexport function isLateAnswerableStatus(status: ChatInteractionStatus): boolean {\n return status === 'expired' || status === 'cancelled'\n}\n\n/** Secrets must never leave the sidecar answer channel for the visible chat\n * transcript, so a secret-bearing ask cannot be late-answered. */\nexport function hasSecretField(fields: ChatInteractionField[]): boolean {\n return fields.some((field) => field.type === 'secret')\n}\n\nfunction optionLabel(field: ChatSelectField, value: string): string {\n return field.options.find((option) => option.value === value)?.label ?? value\n}\n\nfunction answerText(field: ChatInteractionField, answer: InteractionData[string]): string {\n if (field.type === 'select' && Array.isArray(answer)) {\n return answer.map((value) => optionLabel(field as ChatSelectField, value)).join(', ')\n }\n if (field.type === 'boolean') return answer === true ? 'Yes' : 'No'\n if (field.type === 'secret') return '[secret omitted]'\n return String(answer)\n}\n\n/** Renders the late answer as a self-contained chat message: the original\n * question, its context, and the user's answer(s). */\nexport function lateAnswerMessage(interaction: ChatInteraction, data: InteractionData): string {\n const title = interaction.title.trim() || 'the earlier question'\n const body = interaction.body?.trim()\n const answers = interaction.fields\n .map((field) => {\n const answer = data[field.name]\n if (answer === undefined) return null\n return { label: field.label.trim(), text: answerText(field, answer).trim() }\n })\n .filter((item): item is { label: string; text: string } => !!item && item.text.length > 0)\n\n const only = answers.length === 1 ? answers[0] : undefined\n const answerSummary = only\n ? only.text\n : answers.map((item) => `${item.label || 'Answer'}: ${item.text}`).join('\\n')\n\n return [\n `Regarding your earlier question: \"${title}\"`,\n body ? `Context: ${body}` : null,\n `My answer: ${answerSummary}`,\n ].filter((line): line is string => !!line).join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Submit plumbing\n\n/** Define the timeout duration in milliseconds for submitting an interaction */\nexport const INTERACTION_SUBMIT_TIMEOUT_MS = 30_000\n/** Provide the timeout message displayed when the agent cannot be reached during interaction submission */\nexport const INTERACTION_SUBMIT_TIMEOUT_MESSAGE = 'Could not reach the agent. Try again.'\n\n/** One card submission: which ask, resolved how, with what answers. */\nexport interface InteractionAnswerSubmission {\n id: string\n outcome: 'accepted' | 'declined'\n data?: InteractionData\n}\n\n/** Resolve the result of an interaction submission indicating success or failure with details */\nexport type InteractionSubmitResult =\n | { ok: true }\n | { ok: false; expired: boolean; message: string }\n\n/** The cards' only side-effect seam: POST one resolution, report the normalized\n * outcome. Products bind their route URL + routing fields (workspaceId,\n * threadId, session path param) via `createInteractionAnswerSubmitter` or a\n * hand-rolled implementation. */\nexport type SubmitInteractionAnswer = (submission: InteractionAnswerSubmission) => Promise<InteractionSubmitResult>\n\n/** Extracts the most specific error message a route returned. */\nexport async function responseErrorMessage(res: Response): Promise<{ code?: string; message: string }> {\n const text = await res.text().catch(() => '')\n if (text) {\n try {\n const parsed = JSON.parse(text) as { code?: unknown; error?: unknown; message?: unknown }\n const message = typeof parsed.error === 'string' && parsed.error.trim() ? parsed.error\n : typeof parsed.message === 'string' && parsed.message.trim() ? parsed.message\n : null\n if (message) return { ...(typeof parsed.code === 'string' ? { code: parsed.code } : {}), message }\n } catch { /* non-JSON body falls through */ }\n }\n return { message: `Answer failed (${res.status})` }\n}\n\n/** Define options for submitting interaction answers including URL, body, timeout, and fetch implementation */\nexport interface InteractionAnswerSubmitterOptions {\n /** The product's answer route (the POST half of `createInteractionAnswerRoute`).\n * A function when the URL carries the session (e.g. `/api/sessions/${id}/interactions`). */\n url: string | ((submission: InteractionAnswerSubmission) => string)\n /** Extra routing fields merged into the POST body (e.g. workspaceId, threadId). */\n body?: Record<string, unknown> | ((submission: InteractionAnswerSubmission) => Record<string, unknown>)\n timeoutMs?: number\n fetchImpl?: typeof fetch\n}\n\n/**\n * Runs a host-supplied submitter under the CARD's own deadline, and always\n * resolves.\n *\n * `createInteractionAnswerSubmitter` aborts its own fetch, but a product may\n * pass any `SubmitInteractionAnswer` — commonly one wrapping an untimed\n * `fetch`. The deadline cannot live only in the submitter, because what gets\n * stuck is the card: its in-flight guard is cleared by the awaited promise\n * settling, so a submitter that never settles leaves that guard set for the\n * life of the instance — \"Submitting…\" forever, and no answer can be sent\n * again. A submitter with its own shorter timeout simply wins the race.\n *\n * Rejection is normalized too: a submitter that throws would otherwise escape\n * the click handler as an unhandled rejection, leaving the user with a card\n * that silently did nothing. It becomes a visible, retryable message instead.\n */\nexport function settleInteractionSubmit(\n run: () => Promise<InteractionSubmitResult>,\n timeoutMs: number = INTERACTION_SUBMIT_TIMEOUT_MS,\n): Promise<InteractionSubmitResult> {\n return new Promise((resolve) => {\n const timer = setTimeout(\n () => resolve({ ok: false, expired: false, message: INTERACTION_SUBMIT_TIMEOUT_MESSAGE }),\n timeoutMs,\n )\n const settle = (result: InteractionSubmitResult) => {\n clearTimeout(timer)\n // A late result after the deadline resolves nothing — this promise is\n // already settled — so the card keeps the timeout it already reported.\n resolve(result)\n }\n // `Promise.resolve().then(run)` so a submitter that throws SYNCHRONOUSLY is\n // caught here rather than at the call site, where it would bypass this\n // whole guard.\n Promise.resolve()\n .then(run)\n .then(settle, (err: unknown) =>\n settle({\n ok: false,\n expired: false,\n message: err instanceof Error ? err.message : 'Failed to submit the answer',\n }),\n )\n })\n}\n\n/**\n * Builds the `SubmitInteractionAnswer` the cards consume: POSTs\n * `{ ...routingFields, id, outcome, data? }` with an abortable timeout and\n * normalizes the outcome. `expired` is the 410 path — the ask is gone\n * (answered elsewhere, timed out, or the session moved on) and the card must\n * flip to the same dead state a cancel event produces.\n */\nexport function createInteractionAnswerSubmitter(options: InteractionAnswerSubmitterOptions): SubmitInteractionAnswer {\n const timeoutMs = options.timeoutMs ?? INTERACTION_SUBMIT_TIMEOUT_MS\n return async (submission) => {\n const doFetch = options.fetchImpl ?? fetch\n const url = typeof options.url === 'function' ? options.url(submission) : options.url\n const extra = typeof options.body === 'function' ? options.body(submission) : options.body ?? {}\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(INTERACTION_SUBMIT_TIMEOUT_MESSAGE), timeoutMs)\n try {\n const res = await doFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n signal: controller.signal,\n body: JSON.stringify({\n ...extra,\n id: submission.id,\n outcome: submission.outcome,\n ...(submission.data ? { data: submission.data } : {}),\n }),\n })\n if (res.ok) return { ok: true }\n const failure = await responseErrorMessage(res)\n return { ok: false, expired: res.status === 410, message: failure.message }\n } catch (err) {\n if (controller.signal.aborted) {\n return { ok: false, expired: false, message: INTERACTION_SUBMIT_TIMEOUT_MESSAGE }\n }\n return { ok: false, expired: false, message: err instanceof Error ? err.message : 'Failed to submit the answer' }\n } finally {\n clearTimeout(timer)\n }\n }\n}\n","/**\n * InteractionPlanCard — the plan-approval round-trip card (kind:\"plan\",\n * claude-code plan mode). The plan itself arrives as markdown in\n * `interaction.body`; the answerSpec is producer-defined, so fields render\n * generically — a free-text field doubles as the rejection-feedback input.\n * Approve POSTs outcome:\"accepted\", Request changes POSTs outcome:\"declined\"\n * with any typed feedback.\n *\n * Markdown is injected (`renderMarkdown`, matching the rest of `web-react`);\n * without it the plan body falls back to pre-wrapped plain text. Pure data +\n * callbacks: no fetch inside the component.\n */\n\nimport { useMemo, useRef, useState, type ReactNode } from 'react'\nimport type { ChatInteraction, ChatInteractionStatus, InteractionData } from './chat-interactions'\nimport { fieldAcceptsFreeText, isTerminalInteractionStatus } from './chat-interactions'\nimport {\n buildAnswerData,\n fieldAnswer,\n interactionStatusLabels,\n interactionTerminalNotes,\n isLateAnswerableStatus,\n type FieldValues,\n type SubmitInteractionAnswer,\n} from './interaction-card-support'\nimport { InteractionActionButton, InteractionBadge } from './interaction-question-card'\n\nfunction CheckGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n )\n}\n\nfunction ChevronDownGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\nexport interface InteractionPlanCardProps {\n interaction: ChatInteraction\n /** Viewer-vs-editor gate: false renders everything read-only. */\n canWrite: boolean\n /** POST one resolution to the product's answer route (see\n * `createInteractionAnswerSubmitter`). */\n submitAnswer: SubmitInteractionAnswer\n /** Fired when this card resolves locally (approved/rejected, or discovered\n * expired via a 410) so the stream/route state stays in sync. */\n onResolved?: (id: string, status: Exclude<ChatInteractionStatus, 'pending'>) => void\n /** Fired when the user asks the agent to re-submit an expired/withdrawn plan\n * as a new chat turn. Receives the interaction so a callback shared across\n * cards (e.g. via DurableChatCards) knows which plan fired. Return/resolve\n * `false` (or throw) to report the send failed and keep the affordance\n * retryable. Omit to hide it entirely. */\n onReRequest?: (interaction: ChatInteraction) => boolean | void | Promise<boolean | void>\n /** Overrides the default re-request button label\n * (\"Ask agent to re-submit the plan\" — gtm's exact current copy). */\n reRequestLabel?: string\n /** Renders the plan body (markdown). Falls back to pre-wrapped plain text. */\n renderMarkdown?: (markdown: string) => ReactNode\n className?: string\n}\n\nconst STATUS_LABELS = interactionStatusLabels({\n pending: 'Waiting for your approval',\n answered: 'Approved',\n declined: 'Rejected',\n})\n\nconst TERMINAL_NOTES = interactionTerminalNotes('plan', {\n declined: 'The agent was asked to revise the plan.',\n})\n\nconst DEFAULT_RE_REQUEST_LABEL = 'Ask agent to re-submit the plan'\n\n/** Body height (px) beyond which the plan collapses behind a \"Show full plan\"\n * control so a long plan doesn't dominate the transcript. */\nconst COLLAPSED_MAX_HEIGHT = 320\n\nexport function InteractionPlanCard({\n interaction,\n canWrite,\n submitAnswer,\n onResolved,\n onReRequest,\n reRequestLabel,\n renderMarkdown,\n className,\n}: InteractionPlanCardProps) {\n const [values, setValues] = useState<FieldValues>({})\n const [expanded, setExpanded] = useState(false)\n const [submitting, setSubmitting] = useState<'approve' | 'reject' | 'requesting' | null>(null)\n // Terminal state this card learned locally (resolved / 410) before the\n // stream part catches up. A terminal stream status always wins.\n const [localStatus, setLocalStatus] = useState<Exclude<ChatInteractionStatus, 'pending'> | null>(null)\n const [reRequested, setReRequested] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const submitInFlightRef = useRef(false)\n\n const status: ChatInteractionStatus = isTerminalInteractionStatus(interaction.status)\n ? interaction.status\n : localStatus ?? interaction.status\n const reRequestable = isLateAnswerableStatus(status) && onReRequest !== undefined\n const canReRequest = canWrite && reRequestable && !reRequested\n const disabled = !canWrite || status !== 'pending' || submitting !== null\n\n // Approve sends whatever the producer's answerSpec requires; an empty or\n // all-optional spec still approves with `data: {}` (the sidecar validates\n // fail-closed either way).\n const approveData = useMemo(() => buildAnswerData(interaction.fields, values), [interaction.fields, values])\n // Reject carries only the values actually typed/picked — feedback is\n // optional, so unanswered fields are simply omitted.\n const rejectData = useMemo(() => {\n const data: InteractionData = {}\n for (const field of interaction.fields) {\n const answer = fieldAnswer(field, values)\n if (answer !== null) data[field.name] = answer\n }\n return data\n }, [interaction.fields, values])\n\n async function submit(outcome: 'accepted' | 'declined') {\n const data = outcome === 'accepted' ? approveData : rejectData\n if (submitInFlightRef.current || disabled || data === null) return\n submitInFlightRef.current = true\n setSubmitting(outcome === 'accepted' ? 'approve' : 'reject')\n setError(null)\n try {\n const result = await submitAnswer({ id: interaction.id, outcome, data })\n if (result.ok) {\n const resolved = outcome === 'accepted' ? 'answered' : 'declined'\n setLocalStatus(resolved)\n onResolved?.(interaction.id, resolved)\n return\n }\n if (result.expired) {\n setLocalStatus('expired')\n onResolved?.(interaction.id, 'expired')\n return\n }\n setError(result.message)\n } finally {\n submitInFlightRef.current = false\n setSubmitting(null)\n }\n }\n\n async function requestReSubmission() {\n if (submitInFlightRef.current || !canReRequest || !onReRequest) return\n submitInFlightRef.current = true\n setSubmitting('requesting')\n setError(null)\n let accepted: boolean | void\n try {\n accepted = await onReRequest(interaction)\n } catch {\n accepted = false\n } finally {\n submitInFlightRef.current = false\n setSubmitting(null)\n }\n if (accepted === false) {\n setError('The re-request was not sent. Try again.')\n return\n }\n setReRequested(true)\n }\n\n const terminalNote = TERMINAL_NOTES[status]\n const approved = status === 'answered'\n\n return (\n <div className={`rounded-xl border border-card-edge bg-card p-4 ${className ?? ''}`}>\n <div className=\"mb-3 flex flex-wrap items-center justify-between gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <InteractionBadge variant=\"outline\">Plan</InteractionBadge>\n <InteractionBadge variant={approved ? 'default' : status === 'expired' || status === 'declined' ? 'destructive' : 'outline'}>\n {STATUS_LABELS[status]}\n </InteractionBadge>\n </div>\n <span className=\"text-xs text-muted-foreground\">The agent proposed a plan</span>\n </div>\n\n {interaction.title.trim() && (\n <p className=\"mb-3 text-sm font-medium leading-5 text-foreground\">{interaction.title}</p>\n )}\n\n {interaction.body && (\n <div className=\"relative\">\n <div\n className=\"overflow-hidden text-sm text-foreground\"\n style={expanded ? undefined : { maxHeight: COLLAPSED_MAX_HEIGHT }}\n >\n {renderMarkdown\n ? renderMarkdown(interaction.body)\n : <p className=\"whitespace-pre-wrap leading-5\">{interaction.body}</p>}\n </div>\n {!expanded && (\n <div className=\"pointer-events-none absolute inset-x-0 bottom-0 h-12 bg-gradient-to-t from-card to-transparent\" />\n )}\n <button\n type=\"button\"\n onClick={() => setExpanded((prev) => !prev)}\n className=\"mt-1 inline-flex items-center gap-1 text-xs text-muted-foreground transition hover:text-foreground\"\n >\n <ChevronDownGlyph className={`h-3 w-3 transition-transform ${expanded ? 'rotate-180' : ''}`} />\n {expanded ? 'Collapse plan' : 'Show full plan'}\n </button>\n </div>\n )}\n\n {interaction.fields.length > 0 && (\n <div className=\"mt-3 space-y-4\">\n {interaction.fields.map((field) => (\n <fieldset key={field.name} className=\"space-y-2\">\n <p className=\"text-sm font-medium leading-5 text-foreground\">{field.label}</p>\n {fieldAcceptsFreeText(field) ? (\n <textarea\n value={values[field.name]?.text ?? ''}\n disabled={disabled}\n aria-label={field.label}\n onChange={(event) =>\n setValues((prev) => ({ ...prev, [field.name]: { ...prev[field.name], text: event.target.value } }))}\n rows={2}\n placeholder={field.type === 'text' ? field.placeholder ?? 'Optional feedback for the agent' : undefined}\n className=\"w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground focus:border-primary disabled:opacity-50\"\n />\n ) : (\n <input\n type=\"text\"\n value={values[field.name]?.text ?? ''}\n disabled={disabled}\n aria-label={field.label}\n onChange={(event) =>\n setValues((prev) => ({ ...prev, [field.name]: { ...prev[field.name], text: event.target.value } }))}\n className=\"w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground focus:border-primary disabled:opacity-50\"\n />\n )}\n </fieldset>\n ))}\n </div>\n )}\n\n {error && <p className=\"mt-3 text-xs text-destructive\">{error}</p>}\n {terminalNote && <p className=\"mt-3 text-xs text-muted-foreground\">{terminalNote}</p>}\n\n {canReRequest && (\n <div className=\"mt-4 flex items-center justify-end\">\n <InteractionActionButton variant=\"outline\" onClick={() => void requestReSubmission()} disabled={submitting !== null}>\n {submitting === 'requesting' ? 'Asking…' : reRequestLabel ?? DEFAULT_RE_REQUEST_LABEL}\n </InteractionActionButton>\n </div>\n )}\n {reRequested && (\n <div className=\"mt-4 flex items-center justify-end\">\n <span className=\"inline-flex items-center gap-1 text-xs text-muted-foreground\"><CheckGlyph className=\"h-3 w-3\" />Re-submission requested</span>\n </div>\n )}\n\n {status === 'pending' && (\n <div className=\"mt-4 flex items-center justify-end gap-2\">\n <InteractionActionButton variant=\"outline\" onClick={() => void submit('declined')} disabled={disabled}>\n {submitting === 'reject' ? 'Sending…' : 'Request changes'}\n </InteractionActionButton>\n <InteractionActionButton onClick={() => void submit('accepted')} disabled={disabled || approveData === null}>\n {submitting === 'approve' ? 'Approving…' : 'Approve plan'}\n </InteractionActionButton>\n </div>\n )}\n {approved && (\n <div className=\"mt-4 flex items-center justify-end\">\n <span className=\"inline-flex items-center gap-1 text-xs text-muted-foreground\"><CheckGlyph className=\"h-3 w-3\" />Approved</span>\n </div>\n )}\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport { persistedPartToInteraction, type ChatInteraction, type InteractionAnswers } from './chat-interactions'\nimport { persistedPartToPlan, type ChatPlan } from '../plans/index'\nimport type { DurablePlanDecision, DurablePlanDecisionResult } from './durable-plan-flow'\nimport { DurablePlanCard } from './durable-plan-card'\nimport { InteractionPlanCard } from './interaction-plan-card'\nimport { InteractionQuestionCard } from './interaction-question-card'\nimport type { SubmitInteractionAnswer } from './interaction-card-support'\n\nexport type DurableChatCard =\n | { kind: 'plan'; key: string; plan: ChatPlan }\n | { kind: 'interaction'; key: string; interaction: ChatInteraction }\n\nfunction planIdentity(planId: string, revision: number): string {\n return `${planId}:${revision}`\n}\n\n/** Converts persisted/live parts to canonical cards. Legacy interaction-plan\n * cards are suppressed only when their raw part carries an explicit planId and\n * revision matching a durable plan. Identical markdown alone is never proof. */\nexport function durableChatCardsFromParts(parts: Array<Record<string, unknown>>): DurableChatCard[] {\n const durablePlans = new Set<string>()\n for (const part of parts) {\n const plan = persistedPartToPlan(part)\n if (plan) durablePlans.add(planIdentity(plan.planId, plan.revision))\n }\n const cards: DurableChatCard[] = []\n for (const part of parts) {\n const plan = persistedPartToPlan(part)\n if (plan) {\n cards.push({ kind: 'plan', key: `plan:${planIdentity(plan.planId, plan.revision)}`, plan })\n continue\n }\n const interaction = persistedPartToInteraction(part)\n if (!interaction) continue\n const correlatedPlan = interaction.kind === 'plan' && typeof part.planId === 'string' &&\n typeof part.revision === 'number' && durablePlans.has(planIdentity(part.planId, part.revision))\n if (correlatedPlan) continue\n cards.push({ kind: 'interaction', key: `interaction:${interaction.id}`, interaction })\n }\n return cards\n}\n\nexport interface DurableChatCardsProps {\n parts: Array<Record<string, unknown>>\n canWrite: boolean\n submitInteraction: SubmitInteractionAnswer\n decidePlan: (plan: ChatPlan, decision: DurablePlanDecision, feedback?: string) => Promise<DurablePlanDecisionResult | null>\n decidingPlan?: (plan: ChatPlan) => DurablePlanDecision | null\n planError?: (plan: ChatPlan) => string | null\n onInteractionResolved?: (id: string, status: Exclude<ChatInteraction['status'], 'pending'>, answers?: InteractionAnswers) => void\n onLateAnswer?: (message: string) => boolean | void | Promise<boolean | void>\n /** Fired when the user asks the agent to re-submit an expired/withdrawn\n * plan card as a new chat turn; receives that card's interaction. Omit to\n * hide the affordance entirely. */\n onReRequest?: (interaction: ChatInteraction) => boolean | void | Promise<boolean | void>\n /** Overrides the default re-request button label. */\n reRequestLabel?: string\n renderMarkdown?: (markdown: string) => ReactNode\n className?: string\n}\n\n/** Ready-to-embed canonical question/plan card lane for persisted assistant\n * parts. Apps inject transport and styling callbacks instead of rebuilding the\n * lifecycle/render switch. */\nexport function DurableChatCards({\n parts,\n canWrite,\n submitInteraction,\n decidePlan,\n decidingPlan,\n planError,\n onInteractionResolved,\n onLateAnswer,\n onReRequest,\n reRequestLabel,\n renderMarkdown,\n className,\n}: DurableChatCardsProps) {\n const cards = durableChatCardsFromParts(parts)\n if (cards.length === 0) return null\n return (\n <div className={`space-y-3 ${className ?? ''}`}>\n {cards.map((card) => {\n if (card.kind === 'plan') {\n return (\n <DurablePlanCard\n key={card.key}\n plan={card.plan}\n canWrite={canWrite}\n decide={(decision, feedback) => decidePlan(card.plan, decision, feedback)}\n deciding={decidingPlan?.(card.plan)}\n error={planError?.(card.plan)}\n renderMarkdown={renderMarkdown}\n />\n )\n }\n if (card.interaction.kind === 'plan') {\n return (\n <InteractionPlanCard\n key={card.key}\n interaction={card.interaction}\n canWrite={canWrite}\n submitAnswer={submitInteraction}\n onResolved={onInteractionResolved}\n onReRequest={onReRequest}\n reRequestLabel={reRequestLabel}\n renderMarkdown={renderMarkdown}\n />\n )\n }\n return (\n <InteractionQuestionCard\n key={card.key}\n interaction={card.interaction}\n canWrite={canWrite}\n submitAnswer={submitInteraction}\n onResolved={onInteractionResolved}\n onLateAnswer={onLateAnswer}\n />\n )\n })}\n </div>\n )\n}\n","/**\n * Renders a message's attachment parts (images + files) as thumbnails and\n * download chips — the transcript-side counterpart to `ChatComposer`'s\n * staged-upload chips. Ported from gtm-agent's `chat-attachment-parts.tsx`\n * onto agent-app's RAW-BYTES download contract: the host supplies\n * `resolveFileUrl(part)`, a URL that serves the attachment's raw bytes\n * directly, so this module never parses a JSON `{file:{blobUrl,body}}`\n * envelope or decodes a `[base64]` marker the way gtm's vault route did.\n *\n * No icon-library or primitives dependency (`ChatComposer`'s house style):\n * the loading skeleton is an inline `animate-pulse` span and the few glyphs\n * are inline SVGs.\n */\n\nimport { useCallback, useEffect, useState, type ReactNode } from 'react'\nimport type { ChatAttachmentPart } from './chat-attachments'\nimport { formatBytes } from '../chat-routes/wire'\n\n// ── glyphs (no icon-library dependency) ───────────────────────────────────\n\nfunction FileGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <path d=\"M14 2v6h6\" />\n </svg>\n )\n}\n\nfunction ImageGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" />\n <circle cx=\"9\" cy=\"9\" r=\"2\" />\n <path d=\"m21 15-5-5L5 21\" />\n </svg>\n )\n}\n\nfunction WarningGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M12 9v4m0 4h.01M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z\" />\n </svg>\n )\n}\n\nfunction iconForMediaType(mediaType: string | undefined): (props: { className?: string }) => ReactNode {\n return mediaType?.startsWith('image/') ? ImageGlyph : FileGlyph\n}\n\n// ── display name ────────────────────────────────────────────────────────\n\n/** Resolve a display name for an attachment part. `isChatAttachmentPart`\n * only checks `type`/`path` (by design — a structural guard, not a\n * provenance proof), so a stored part can carry `path` with no `name` if it\n * was written before a normalization fix landed. Rather than rendering a\n * blank label or downloading a file named `undefined`, fall back to the\n * storage path's own basename; only when even that is unusable (e.g. a\n * path ending in `/`) does a caller need the explicit unavailable state. */\nfunction attachmentDisplayName(part: ChatAttachmentPart): string | null {\n if (typeof part.name === 'string' && part.name.trim().length > 0) return part.name\n const base = part.path.split('/').pop() ?? ''\n const trimmed = base.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\n// ── file loading + cache ───────────────────────────────────────────────────\n\n/** Typed outcome of fetching one attachment's raw bytes. Callers must check\n * `ok` before touching `blob` — a failed fetch never produces a blank\n * render, it produces a visible error state. */\nexport type AttachmentFileResult = { ok: true; blob: Blob } | { ok: false; message: string }\n\n/** Module-level cache so mounting several rows that reference the same URL\n * (e.g. a thumbnail re-rendered across reloads within one session) issues\n * exactly one fetch. Keyed on the RESOLVED url — `resolveFileUrl`'s output —\n * since that is what actually identifies the byte stream to the host. */\nconst attachmentFileCache = new Map<string, Promise<AttachmentFileResult>>()\n\nexport function __resetAttachmentFileCacheForTests(): void {\n attachmentFileCache.clear()\n}\n\nasync function defaultFetchFile(url: string): Promise<Response> {\n return fetch(url, { credentials: 'same-origin' })\n}\n\nasync function fetchAttachmentFile(\n url: string,\n fetchFile: (url: string) => Promise<Response>,\n): Promise<AttachmentFileResult> {\n try {\n const res = await fetchFile(url)\n if (!res.ok) return { ok: false, message: `Failed to load attachment (${res.status})` }\n return { ok: true, blob: await res.blob() }\n } catch (err) {\n return { ok: false, message: err instanceof Error && err.message ? err.message : 'Network error loading attachment' }\n }\n}\n\n/** Fetches (and caches) the raw bytes behind one attachment url. Concurrent\n * callers for the SAME url dedupe to one in-flight fetch. Only a successful\n * settlement stays cached — evicting failures means a remount or click-retry\n * after a transient error issues a fresh fetch. */\nexport function loadAttachmentFile(\n url: string,\n fetchFile: (url: string) => Promise<Response> = defaultFetchFile,\n): Promise<AttachmentFileResult> {\n const cached = attachmentFileCache.get(url)\n if (cached) return cached\n const promise = fetchAttachmentFile(url, fetchFile)\n attachmentFileCache.set(url, promise)\n void promise.then((result) => {\n if (!result.ok && attachmentFileCache.get(url) === promise) attachmentFileCache.delete(url)\n })\n return promise\n}\n\n/** Drives an anchor-click download from an already-resolved blob. Returns a\n * typed outcome rather than throwing — a chip that fails to synthesize the\n * download must show the failure, not silently no-op. */\nexport function triggerAttachmentDownload(name: string, blob: Blob): { ok: true } | { ok: false; message: string } {\n try {\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = name\n document.body.appendChild(link)\n link.click()\n link.remove()\n URL.revokeObjectURL(url)\n return { ok: true }\n } catch (err) {\n return { ok: false, message: err instanceof Error && err.message ? err.message : 'Failed to download attachment' }\n }\n}\n\n/** Object URL for a resolved blob, created once per blob and revoked on\n * unmount (or when the blob it was built from changes). */\nfunction useAttachmentObjectUrl(blob: Blob | undefined): string | null {\n const [url, setUrl] = useState<string | null>(null)\n useEffect(() => {\n if (!blob) {\n setUrl(null)\n return\n }\n const objectUrl = URL.createObjectURL(blob)\n setUrl(objectUrl)\n return () => URL.revokeObjectURL(objectUrl)\n }, [blob])\n return url\n}\n\n// ── thumbnail (images) ──────────────────────────────────────────────────────\n\nfunction AttachmentThumbnailError({ name }: { name: string }) {\n return (\n <span className=\"inline-flex h-16 w-16 shrink-0 flex-col items-center justify-center gap-1 rounded-md border border-destructive/40 bg-destructive/10 px-1 text-center text-destructive\">\n <WarningGlyph className=\"h-4 w-4 shrink-0\" />\n <span className=\"line-clamp-2 text-[10px] leading-tight\">{name}</span>\n </span>\n )\n}\n\n/** Non-clickable placeholder for a stored part with no usable name at all\n * (no `name`, and no basename could be derived from `path`) — never a blank\n * clickable control, and never a download named `undefined`. */\nfunction AttachmentUnavailable({ shape }: { shape: 'thumbnail' | 'chip' }) {\n if (shape === 'thumbnail') {\n return (\n <span\n aria-disabled=\"true\"\n className=\"inline-flex h-16 w-16 shrink-0 flex-col items-center justify-center gap-1 rounded-md border border-border bg-muted px-1 text-center text-muted-foreground\"\n >\n <WarningGlyph className=\"h-4 w-4 shrink-0\" />\n <span className=\"line-clamp-2 text-[10px] leading-tight\">Attachment unavailable</span>\n </span>\n )\n }\n return (\n <span\n aria-disabled=\"true\"\n className=\"inline-flex items-center gap-1 rounded-md border border-border bg-muted px-2 py-0.5 text-[11px] text-muted-foreground\"\n >\n <WarningGlyph className=\"h-3 w-3 shrink-0\" />\n Attachment unavailable\n </span>\n )\n}\n\ninterface AttachmentPartProps {\n part: ChatAttachmentPart\n resolveFileUrl: (part: ChatAttachmentPart) => string\n fetchFile?: (url: string) => Promise<Response>\n}\n\nfunction AttachmentThumbnail({ part, resolveFileUrl, fetchFile }: AttachmentPartProps) {\n const url = resolveFileUrl(part)\n const displayName = attachmentDisplayName(part)\n const [result, setResult] = useState<AttachmentFileResult | null>(null)\n\n // Images fetch eagerly on mount — unlike the chip, which fetches only on\n // click — so the transcript shows a real thumbnail rather than a\n // placeholder icon. Skipped entirely for a part with no usable display\n // name — there is nothing meaningful to label the fetched bytes with.\n useEffect(() => {\n if (!displayName) return\n let cancelled = false\n setResult(null)\n loadAttachmentFile(url, fetchFile).then((next) => {\n if (!cancelled) setResult(next)\n })\n return () => {\n cancelled = true\n }\n }, [url, fetchFile, displayName])\n\n const objectUrl = useAttachmentObjectUrl(result?.ok ? result.blob : undefined)\n\n const handleClick = useCallback(() => {\n if (!objectUrl) return\n window.open(objectUrl, '_blank', 'noopener')\n }, [objectUrl])\n\n if (!displayName) {\n return <AttachmentUnavailable shape=\"thumbnail\" />\n }\n if (!result) {\n // The shimmer stays hidden and UNROLED. Giving each placeholder a role\n // would put a dozen of them in the accessibility tree of one transcript\n // message and, worse, make a not-yet-loaded attachment answer to the same\n // role as a loaded one — the announcement belongs to the group instead.\n return <span aria-hidden=\"true\" className=\"inline-block h-16 w-16 shrink-0 animate-pulse rounded-md bg-muted\" />\n }\n if (!result.ok || !objectUrl) {\n return <AttachmentThumbnailError name={displayName} />\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n aria-label={`Open ${displayName}`}\n className=\"h-16 w-16 shrink-0 overflow-hidden rounded-md border border-border\"\n >\n <img src={objectUrl} alt={displayName} className=\"h-16 w-16 object-cover\" />\n </button>\n )\n}\n\n// ── chip (files) ─────────────────────────────────────────────────────────\n\nfunction AttachmentChip({ part, resolveFileUrl, fetchFile }: AttachmentPartProps) {\n const displayName = attachmentDisplayName(part)\n const [status, setStatus] = useState<'idle' | 'loading' | 'error'>('idle')\n const [errorMessage, setErrorMessage] = useState<string | null>(null)\n\n // Files fetch ONLY on click — an unopened chip never issues a network\n // request, unlike an eagerly-fetched thumbnail.\n const handleClick = useCallback(() => {\n if (!displayName || status === 'loading') return\n setStatus('loading')\n setErrorMessage(null)\n const url = resolveFileUrl(part)\n void loadAttachmentFile(url, fetchFile).then((result) => {\n if (!result.ok) {\n setStatus('error')\n setErrorMessage(result.message)\n return\n }\n const download = triggerAttachmentDownload(displayName, result.blob)\n if (!download.ok) {\n setStatus('error')\n setErrorMessage(download.message)\n return\n }\n setStatus('idle')\n })\n }, [displayName, status, resolveFileUrl, part, fetchFile])\n\n if (!displayName) {\n return <AttachmentUnavailable shape=\"chip\" />\n }\n\n const Icon = status === 'error' ? WarningGlyph : iconForMediaType(part.mediaType)\n const className = [\n 'inline-flex items-center gap-1 rounded-md border px-2 py-0.5 text-[11px]',\n status === 'error'\n ? 'border-destructive/40 bg-destructive/10 text-destructive'\n : 'border-border bg-secondary text-muted-foreground',\n ].join(' ')\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n title={status === 'error' ? errorMessage ?? undefined : undefined}\n className={className}\n >\n <Icon className=\"h-3 w-3 shrink-0\" />\n {displayName}\n {typeof part.size === 'number' && <span className=\"text-muted-foreground/70\">· {formatBytes(part.size)}</span>}\n </button>\n )\n}\n\n// ── row ──────────────────────────────────────────────────────────────────\n\nexport interface MessageAttachmentsProps {\n parts: ChatAttachmentPart[]\n /** URL serving the attachment's RAW bytes. */\n resolveFileUrl: (part: ChatAttachmentPart) => string\n /** Row alignment — a user-bubble attachment row is right-aligned by\n * default; pass `\"start\"` for an assistant-turn attachment, which sits\n * inline with the rest of the transcript. */\n justify?: 'start' | 'end'\n /** Override the fetch used to load an attachment's bytes. Default:\n * `fetch(url, { credentials: 'same-origin' })`. */\n fetchFile?: (url: string) => Promise<Response>\n}\n\n/** Renders a message's attachment parts as a row of image thumbnails and file\n * chips. `null` when there are none, so callers can render unconditionally\n * without an extra length check. */\nexport function MessageAttachments({ parts, resolveFileUrl, justify = 'end', fetchFile }: MessageAttachmentsProps): ReactNode {\n if (parts.length === 0) return null\n return (\n <div className={`flex flex-wrap gap-1.5 ${justify === 'start' ? 'justify-start' : 'justify-end'}`}>\n {parts.map((part) =>\n part.type === 'image' ? (\n <AttachmentThumbnail key={`${part.path}:${part.name}`} part={part} resolveFileUrl={resolveFileUrl} fetchFile={fetchFile} />\n ) : (\n <AttachmentChip key={`${part.path}:${part.name}`} part={part} resolveFileUrl={resolveFileUrl} fetchFile={fetchFile} />\n ),\n )}\n </div>\n )\n}\n","/**\n * Client-side chat-stream consumption — the NDJSON parse loop every agent\n * app's chat UI hand-rolls (and breaks). Normalizes the three line shapes the\n * agent-app chat routes emit:\n *\n * {kind:'event', event:{type:'text'|'reasoning'|'tool_call'|'usage'|'notice'|'error', ...}}\n * {kind:'tool_result', toolCallId, toolName, label, outcome}\n * {type:'turn'|'metadata'|'error'|'turn_status', ...} (route-level)\n * {type:'interaction', data:{request}} (sidecar ask)\n *\n * Replayed lines carry an extra `seq` — transparently ignored. Works for\n * router-backed and sandbox-backed chats alike: anything producing these\n * lines (live pump, queued follow, resume replay) feeds the same callbacks.\n */\n\nimport {\n interactionFromWireRequest,\n parseInteractionCancel,\n parseInteractionRequest,\n type ChatInteraction,\n type InteractionCancelData,\n} from './chat-interactions'\nimport {\n parsePlanSubmittedEvent,\n persistedPartToPlan,\n type ChatPlan,\n} from '../plans/index'\n\n// The `/chat-routes` wire contract, re-exported for turn-body construction —\n// `./chat-routes/wire` and `./chat-routes/file-index`'s response types are\n// import-free and browser-safe by design.\nexport {\n chatTurnRequestInit,\n type ChatTurnFilePartInput,\n type ChatTurnPartInput,\n type ChatTurnRequestPayload,\n type ProducerTextEvent,\n type ProducerReasoningEvent,\n type ProducerToolCallEvent,\n type ProducerToolResultEvent,\n type ProducerUsageEvent,\n type ProducerNoticeEvent,\n type ProducerErrorEvent,\n type ProducerPassthroughEventType,\n type ProducerPassthroughEvent,\n type ProducerWireEvent,\n type FileMention,\n fileMentionsToParts,\n buildMentionPromptBlock,\n mediaTypeForMentionPath,\n mentionKindForPath,\n type ChatAttachmentKind,\n type ChatAttachmentInput,\n DISPATCH_REQUEST_MAX_BYTES,\n DISPATCH_STRUCTURAL_RESERVE_BYTES,\n DISPATCH_MAX_PARTS,\n DISPATCH_MAX_MEDIA_PARTS,\n base64WireLen,\n} from '../chat-routes/wire'\nexport {\n type FileIndexResponse,\n type FileIndexReadyResponse,\n type FileIndexWarmingResponse,\n} from '../chat-routes/file-index'\n\n/** Define the structure for a chat tool call including optional ID, name, and arguments object */\nexport interface ChatStreamToolCall {\n toolCallId?: string\n toolName: string\n args: Record<string, unknown>\n}\n\n/** Describe the result of a chat stream tool including its outcome and optional metadata fields */\nexport interface ChatStreamToolResult {\n toolCallId?: string\n toolName?: string\n label?: string\n outcome: { ok: boolean; result?: unknown; code?: string; message?: string }\n}\n\n/** Define callbacks to handle events and data during a chat streaming session */\nexport interface ChatStreamCallbacks {\n onTurnId?: (turnId: string) => void\n onText?: (delta: string) => void\n onReasoning?: (delta: string) => void\n onToolCall?: (call: ChatStreamToolCall) => void\n onToolResult?: (result: ChatStreamToolResult) => void\n onUsage?: (usage: { promptTokens: number; completionTokens: number }) => void\n onNotice?: (notice: { id: string; noticeKind: 'warning' | 'auto-declined'; text: string }) => void\n onMetadata?: (data: Record<string, unknown>) => void\n /** Structured detail from a loop-level error event. Fired alongside the\n * legacy string-only `onErrorEvent` callback. */\n onErrorEventDetail?: (detail: {\n message: string\n code?: string\n details?: Record<string, unknown>\n }) => void\n /** A loop-level error event (the turn failed server-side). Optional, but the\n * error never vanishes: when omitted, the message is synthesized into the\n * transcript via `onText` (rendered by ChatMessages as a text segment) and\n * logged with `console.error`. */\n onErrorEvent?: (message: string) => void\n /** A sidecar interaction ask (kind: \"question\"/\"plan\"/…). The run is BLOCKED\n * in the broker until the user answers; a pending ask is \"waiting on the\n * user\", not \"model working\". Optional — a consumer that doesn't wire it\n * parses the same stream unchanged. */\n onInteraction?: (interaction: ChatInteraction) => void\n /** A terminal withdrawal/timeout for a previously emitted interaction. */\n onInteractionCancel?: (cancel: InteractionCancelData) => void\n /** A durable-plan snapshot from any plan lifecycle event. */\n onPlan?: (plan: ChatPlan) => void\n}\n\n/** Represent the result of consuming a chat stream including turn ID and content reception status */\nexport interface ConsumeChatStreamResult {\n turnId: string | null\n /** True when any text/reasoning/tool activity was received. */\n receivedContent: boolean\n}\n\n/** Parse one NDJSON line into the callbacks. Exposed for tests. */\nexport function dispatchChatStreamLine(line: string, cb: ChatStreamCallbacks): {\n turnId?: string\n receivedContent: boolean\n} {\n let receivedContent = false\n let turnId: string | undefined\n if (!line.trim()) return { receivedContent }\n let parsed: Record<string, unknown>\n try {\n parsed = JSON.parse(line) as Record<string, unknown>\n } catch {\n return { receivedContent } // tolerate a torn line\n }\n\n if (parsed.kind === 'tool_result') {\n cb.onToolResult?.({\n toolCallId: parsed.toolCallId as string | undefined,\n toolName: parsed.toolName as string | undefined,\n label: parsed.label as string | undefined,\n outcome: (parsed.outcome ?? parsed.result) as ChatStreamToolResult['outcome'],\n })\n return { receivedContent: true }\n }\n\n const evt = (parsed.kind === 'event' ? parsed.event : parsed) as Record<string, unknown>\n if (!evt || typeof evt !== 'object') return { receivedContent }\n\n switch (evt.type) {\n case 'turn':\n if (typeof evt.turnId === 'string') turnId = evt.turnId\n break\n case 'text':\n if (typeof evt.text === 'string') {\n cb.onText?.(evt.text)\n receivedContent = true\n }\n break\n case 'reasoning':\n if (typeof evt.text === 'string') {\n cb.onReasoning?.(evt.text)\n receivedContent = true\n }\n break\n case 'tool_call': {\n const call = (evt.call ?? evt) as Record<string, unknown>\n cb.onToolCall?.({\n toolCallId: (call.toolCallId ?? call.id) as string | undefined,\n toolName: String(call.toolName ?? call.name ?? 'unknown'),\n args: (call.args ?? {}) as Record<string, unknown>,\n })\n receivedContent = true\n break\n }\n case 'tool_result':\n cb.onToolResult?.({\n toolCallId: evt.toolCallId as string | undefined,\n toolName: evt.toolName as string | undefined,\n label: evt.label as string | undefined,\n outcome: (evt.outcome ?? evt.result) as ChatStreamToolResult['outcome'],\n })\n receivedContent = true\n break\n case 'usage': {\n const u = evt.usage as { promptTokens?: number; completionTokens?: number } | undefined\n if (u) cb.onUsage?.({ promptTokens: u.promptTokens ?? 0, completionTokens: u.completionTokens ?? 0 })\n break\n }\n case 'notice': {\n if (\n typeof evt.id === 'string' &&\n (evt.noticeKind === 'warning' || evt.noticeKind === 'auto-declined') &&\n typeof evt.text === 'string'\n ) {\n cb.onNotice?.({ id: evt.id, noticeKind: evt.noticeKind, text: evt.text })\n receivedContent = true\n }\n break\n }\n case 'metadata':\n cb.onMetadata?.((evt.data ?? {}) as Record<string, unknown>)\n break\n case 'interaction': {\n // The run is now BLOCKED in the sidecar broker until this ask is\n // answered, withdrawn, or times out. Validate the shape and surface the\n // parsed ChatInteraction; a malformed ask is logged and skipped rather\n // than half-surfaced.\n const parsed = parseInteractionRequest(evt.data as Record<string, unknown> | undefined)\n if (parsed.succeeded) {\n cb.onInteraction?.(interactionFromWireRequest(parsed.value))\n receivedContent = true\n } else {\n console.error('[chat-stream] dropping malformed interaction line:', parsed.error)\n }\n break\n }\n case 'interaction.cancel': {\n const cancelled = parseInteractionCancel(evt.data as Record<string, unknown> | undefined)\n if (cancelled.succeeded) {\n cb.onInteractionCancel?.(cancelled.value)\n receivedContent = true\n } else {\n console.error('[chat-stream] dropping malformed interaction.cancel line:', cancelled.error)\n }\n break\n }\n case 'error': {\n // The sandbox lane sends the reason as `{ type: 'error', data: { message } }`\n // (mirrored by `session.run.failed`); older/edge lanes use a top-level\n // `details`/`error`. Read `data.message` FIRST so a real failure surfaces\n // to the operator instead of the useless \"Unknown stream error\".\n const data = evt.data as {\n message?: string\n code?: string\n details?: Record<string, unknown>\n } | undefined\n const message = String(data?.message ?? evt.details ?? evt.error ?? 'Unknown stream error')\n cb.onErrorEventDetail?.({\n message,\n ...(typeof data?.code === 'string' ? { code: data.code } : {}),\n ...(data?.details && typeof data.details === 'object' ? { details: data.details } : {}),\n })\n if (cb.onErrorEvent) {\n cb.onErrorEvent(message)\n } else {\n // Fail loud when the consumer wired no onErrorEvent: a turn that fails\n // server-side must not end as a silent empty answer. Synthesize the\n // error into the transcript through the text channel (it lands as a\n // text segment ChatMessages renders) and log it — the app that forgot\n // the callback still shows the user an error row.\n console.error('[chat-stream] unhandled stream error event:', message)\n cb.onText?.(`\\n\\nThe agent hit an error and this turn stopped: ${message}`)\n receivedContent = true\n }\n break\n }\n default: {\n if (typeof evt.type === 'string' && evt.type.startsWith('plan.')) {\n const submitted = parsePlanSubmittedEvent(evt)\n const planRecord = (\n (evt.data as Record<string, unknown> | undefined)?.plan ??\n (evt.properties as Record<string, unknown> | undefined)?.plan\n ) as Record<string, unknown> | undefined\n const plan = submitted.succeeded\n ? submitted.value\n : planRecord ? persistedPartToPlan({ type: 'plan', ...planRecord }) : null\n if (plan) {\n cb.onPlan?.(plan)\n receivedContent = true\n } else {\n console.error('[chat-stream] dropping malformed durable plan line:', evt.type)\n }\n }\n break // turn_status and unknown line types are non-content\n }\n }\n return { turnId, receivedContent }\n}\n\n/** Drain one NDJSON body into the callbacks. Throws on transport failure\n * (caller decides whether to resume). */\nexport async function consumeChatStream(\n body: ReadableStream<Uint8Array>,\n cb: ChatStreamCallbacks,\n): Promise<ConsumeChatStreamResult> {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let turnId: string | null = null\n let receivedContent = false\n\n const handle = (line: string) => {\n const r = dispatchChatStreamLine(line, cb)\n if (r.turnId) {\n turnId = r.turnId\n cb.onTurnId?.(r.turnId)\n }\n if (r.receivedContent) receivedContent = true\n }\n\n for (;;) {\n const { done, value } = await reader.read()\n if (done) {\n if (buffer.trim()) handle(buffer)\n break\n }\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) handle(line)\n }\n return { turnId, receivedContent }\n}\n\n/** Define options for managing and resuming streaming chat interactions with callbacks */\nexport interface StreamChatOptions {\n /** Start the turn (POST the chat request); must return a streaming Response. */\n start: () => Promise<Response>\n /** Re-attach to a turn after a transport drop (GET the resume route). */\n resume?: (turnId: string, fromSeq: number) => Promise<Response>\n callbacks: ChatStreamCallbacks\n /** Called before a resume replays from 0 so the UI can reset accumulated\n * turn state (text, reasoning, tool chips). */\n onResetForResume?: () => void\n}\n\n/**\n * Run one chat turn with automatic single-shot resume: if the transport drops\n * mid-turn and the server announced a turnId, reset and replay the buffered\n * turn. Server-side the turn keeps running either way (queued runner).\n */\nexport async function streamChatTurn(opts: StreamChatOptions): Promise<ConsumeChatStreamResult> {\n const res = await opts.start()\n if (!res.ok || !res.body) {\n const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` })) as { error?: string }\n throw new Error(err.error ?? `HTTP ${res.status}`)\n }\n let turnId: string | null = null\n const cb: ChatStreamCallbacks = {\n ...opts.callbacks,\n onTurnId: (id) => {\n turnId = id\n opts.callbacks.onTurnId?.(id)\n },\n }\n try {\n return await consumeChatStream(res.body, cb)\n } catch (transportErr) {\n if (!turnId || !opts.resume) throw transportErr\n opts.onResetForResume?.()\n const resumed = await opts.resume(turnId, 0)\n if (!resumed.ok || !resumed.body) throw transportErr\n return await consumeChatStream(resumed.body, cb)\n }\n}\n","/**\n * ChatComposer — the shared message input every agent app used to hand-roll:\n * an auto-resizing textarea (Enter sends, Shift+Enter inserts a newline), an\n * opt-in attach + drag-and-drop surface with pending-file chips, a streaming\n * Stop/Send toggle, a slot for inline controls (model picker, reasoning\n * effort), and a Cmd/Ctrl+L focus shortcut.\n *\n * A REJECTED send never destroys the draft. The input clears optimistically —\n * the composer stays editable while a turn streams precisely so the next\n * message can be typed against a live answer, and holding the sent text in the\n * box until the server confirms would put the clear on a collision course with\n * that typing. So the clear happens immediately and the draft is held until the\n * send is known to have landed: a handler that throws, rejects, or returns\n * `{ ok: false }` puts the exact bytes back with the caret where it was, names\n * the reason, and reports `onSendFailed` so the host can restore the\n * attachments it consumed. If the user has already typed a replacement, the\n * unsent text is shown in the notice with its own Retry instead of overwriting\n * what they typed — neither draft is ever destroyed.\n *\n * Styling contract matches the rest of `web-react`: Tailwind over the shared\n * design tokens (`bg-card`, `border-border`, `text-foreground`, `bg-primary`, …)\n * and inline-SVG glyphs. It defines NO `--chat-*` / `--brand-*` custom\n * properties, so it themes correctly in any shell that provides the standard\n * tokens — the input renders on-palette instead of collapsing to unstyled\n * fallbacks when a host hasn't defined a private chat-token set.\n */\n\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n type ChangeEvent,\n type DragEvent,\n type KeyboardEvent,\n type ReactNode,\n} from 'react'\n\n// ── glyphs (no icon-library dependency) ───────────────────────────────────\n\nfunction SendGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M22 2 11 13M22 2l-7 20-4-9-9-4 20-7z\" />\n </svg>\n )\n}\n\nfunction StopGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden>\n <rect x=\"6\" y=\"6\" width=\"12\" height=\"12\" rx=\"2\" />\n </svg>\n )\n}\n\nfunction PaperclipGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48\" />\n </svg>\n )\n}\n\nfunction FolderGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z\" />\n <path d=\"M12 10v6m-3-3h6\" />\n </svg>\n )\n}\n\nfunction CloseGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n )\n}\n\nfunction UploadGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M17 8l-5-5-5 5M12 3v12\" />\n </svg>\n )\n}\n\n// ── component ──────────────────────────────────────────────────────────────\n\n/** Prompt-part descriptor an uploaded file carries (the upload route's\n * `UploadedChatFile.part`), echoed back in the turn body on send. Mirrors\n * `/chat-routes`' wire shape structurally — no server import here. */\nexport interface ComposerFilePart {\n type: 'image' | 'file'\n filename?: string\n mediaType?: string\n url?: string\n path?: string\n content?: string\n}\n\nexport interface ComposerFile {\n id: string\n name: string\n size?: number\n kind: 'file' | 'folder'\n /** Number of files inside, for a folder chip. */\n fileCount?: number\n status: 'pending' | 'uploading' | 'ready' | 'error'\n /** Uploaded part descriptor; set once the upload route returns. Only\n * `status: 'ready'` files with a part travel on a parts-aware send. */\n part?: ComposerFilePart\n}\n\n/** A send the host refused. `error` is shown verbatim in the composer's notice;\n * omit it for the generic copy. */\nexport interface ComposerSendRejected {\n ok: false\n error?: string\n}\n\n/**\n * What a send handler reports back. `void` — what every handler returned before\n * this existed — reads as accepted, so wiring stays unchanged; a thrown error, a\n * rejected promise, or `{ ok: false }` is the rejection that restores the draft.\n * A handler that resolves only when the whole turn finishes still reports\n * correctly: the input already cleared on dispatch, so the answer only decides\n * whether the draft comes back.\n */\nexport type ComposerSendOutcome = void | { ok: true } | ComposerSendRejected\nexport type ComposerSendResult = ComposerSendOutcome | Promise<ComposerSendOutcome>\n\n/**\n * A send handler, typed as a UNION with the legacy `=> void` signature rather\n * than as `(…) => ComposerSendResult` alone.\n *\n * TypeScript's return-type-`void` rule accepts a function returning ANYTHING\n * where a `=> void` is expected, and that rule fires only when the target's\n * return type is exactly `void` — not when it is a union that contains `void`.\n * So narrowing this prop to `ComposerSendResult` would reject handler shapes\n * that compiled against the shipped `onSend?: (message: string) => void`:\n * `onSend={(m) => rows.push(m)}` (returns `number`) and\n * `onSend={(m) => append({ role: 'user', content: m })}` (an ai-sdk append\n * returns `Promise<string | null | undefined>`) both stop compiling, on a\n * package whose pinned consumers must never need a source edit to take a minor.\n *\n * The union keeps both: a legacy handler lands on the first member, and a\n * handler that reports an outcome lands on the second. A call through it\n * resolves to `void | ComposerSendResult`, which IS `ComposerSendResult`, so\n * the composer reads the outcome exactly as before.\n */\nexport type ComposerSendHandler =\n | ((message: string) => void)\n | ((message: string) => ComposerSendResult)\n\n/** @see ComposerSendHandler — the parts-aware arity, same union for the same reason. */\nexport type ComposerSendPartsHandler =\n | ((message: string, parts: ComposerFilePart[]) => void)\n | ((message: string, parts: ComposerFilePart[]) => ComposerSendResult)\n\n/** The rejected send, handed to `onSendFailed` so the host can undo whatever it\n * cleared optimistically — most importantly the staged attachments, which the\n * composer does not own (`pendingFiles` is a prop). */\nexport interface ComposerSendFailure {\n /** The reason as the composer renders it. */\n message: string\n /** The user's exact draft, untrimmed. */\n text: string\n /** The parts the rejected send carried. */\n parts: ComposerFilePart[]\n /** Whatever the handler threw / rejected with, or the `{ ok: false }` value. */\n error: unknown\n /** True when the draft was put back in the textarea (the box was empty).\n * False means the user had typed a replacement, so the unsent text is held in\n * the notice instead. */\n restored: boolean\n}\n\nexport interface ChatComposerProps {\n /** Send the trimmed, non-empty message. Attached files travel separately via\n * `onAttach` + `pendingFiles` (the host consumes and clears them on send).\n * Optional when `onSendParts` is wired.\n *\n * Report a refused send by throwing, rejecting, or returning `{ ok: false }`\n * — the composer restores the draft rather than losing it. */\n onSend?: ComposerSendHandler\n /** Parts-aware send: receives the trimmed message plus the `part`\n * descriptors of every `ready` pending file. Takes precedence over\n * `onSend`; enables file-only sends (empty text, ≥1 ready part).\n *\n * Same rejection contract as `onSend`. */\n onSendParts?: ComposerSendPartsHandler\n /** Notified when a send is rejected, after the composer has restored what it\n * owns. The host uses it to put back the `pendingFiles` it consumed. */\n onSendFailed?: (failure: ComposerSendFailure) => void\n /** Notice copy when the handler names no reason of its own. */\n sendFailureMessage?: string\n /** Stop the in-flight turn; shown in place of Send while `isStreaming`. */\n onCancel?: () => void\n isStreaming?: boolean\n /** Block input + send (e.g. while restoring). Distinct from `isStreaming`,\n * which keeps the textarea editable so the next turn can be composed. */\n disabled?: boolean\n placeholder?: string\n\n /** Controlled value. Omit for self-managed internal state (cleared on send). */\n value?: string\n onValueChange?: (value: string) => void\n /** Initial text in uncontrolled mode; ignored when `value` is provided. */\n initialValue?: string\n\n /** One-shot external prefill: when this becomes a non-null string the\n * composer adopts it as the draft (replacing any current draft), focuses the\n * input with the caret at the end, and reports consumption via\n * `onSeedApplied` so the host can clear its seed state. */\n seed?: string | null\n onSeedApplied?: () => void\n\n /** Inline controls (e.g. `<ModelPicker/>` + `<EffortPicker/>` or\n * `<AgentSessionControls/>`). */\n controls?: ReactNode\n /**\n * Where {@link controls} sit. `inline` (default) puts them on the card's own\n * action row, beside attach and Send — the model a turn will use reads as\n * part of the input rather than as a separate widget floating above it.\n * `above` keeps them outside the card, for a host that wants the input to be\n * nothing but the input.\n */\n controlsPlacement?: 'above' | 'inline'\n\n /** Attachments are opt-in: pass `onAttach` to show the attach button, accept\n * drag-and-drop onto the input, and render `pendingFiles` chips. */\n onAttach?: (files: FileList) => void\n onAttachFolder?: (files: FileList) => void\n pendingFiles?: ComposerFile[]\n onRemoveFile?: (id: string) => void\n accept?: string\n dropTitle?: string\n dropDescription?: string\n\n /** Cmd/Ctrl+L focuses the input and shows the hint. Default true. */\n focusShortcut?: boolean\n /** Float the card on a soft two-layer foreground-tinted shadow (opt-in).\n * Elevation only — radius, ring, and control layout are unchanged. */\n floating?: boolean\n /** Send button label. Default \"Send\". */\n sendLabel?: string\n className?: string\n}\n\nconst MAX_HEIGHT = 168\n\nconst DEFAULT_SEND_FAILURE = \"Message not sent. Your draft is still here — try again.\"\n\n/** A rejection the handler reported by value rather than by throwing. */\nfunction isRejectedOutcome(outcome: ComposerSendOutcome): outcome is ComposerSendRejected {\n return typeof outcome === 'object' && outcome !== null && outcome.ok === false\n}\n\nfunction isPromise(value: ComposerSendResult): value is Promise<ComposerSendOutcome> {\n return typeof (value as Promise<ComposerSendOutcome> | undefined)?.then === 'function'\n}\n\n/** The reason to show. A rejection's own `error` string wins; then an Error's\n * message; else the caller's copy — never an empty notice. */\nfunction sendFailureText(error: unknown, fallback: string): string {\n if (typeof error === 'object' && error !== null && 'ok' in error) {\n const named = (error as ComposerSendRejected).error\n if (typeof named === 'string' && named.trim() !== '') return named\n return fallback\n }\n if (typeof error === 'string' && error.trim() !== '') return error\n if (error instanceof Error && error.message.trim() !== '') return error.message\n return fallback\n}\n\ninterface FailedSend {\n message: string\n /** The user's exact draft, untrimmed — what a restore puts back. */\n text: string\n /** The trimmed form the handler was called with, so Retry sends the same\n * bytes the rejected attempt did. */\n trimmed: string\n parts: ComposerFilePart[]\n restored: boolean\n}\n\nexport function ChatComposer({\n onSend,\n onSendParts,\n onSendFailed,\n sendFailureMessage = DEFAULT_SEND_FAILURE,\n onCancel,\n isStreaming = false,\n disabled = false,\n placeholder = 'Message the agent…',\n value,\n onValueChange,\n initialValue,\n seed,\n onSeedApplied,\n controls,\n controlsPlacement = 'inline',\n onAttach,\n onAttachFolder,\n pendingFiles = [],\n onRemoveFile,\n accept,\n dropTitle = 'Drop files to add context',\n dropDescription = 'They attach to your next message.',\n focusShortcut = true,\n floating = false,\n sendLabel = 'Send',\n className,\n}: ChatComposerProps) {\n const isControlled = value !== undefined\n const [internal, setInternal] = useState(initialValue ?? '')\n const text = isControlled ? value : internal\n // A send outcome arrives after the render that dispatched it, so the restore\n // decision must read the LIVE draft, not the one captured in that closure.\n const textRef = useRef(text)\n textRef.current = text\n\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n const fileInputRef = useRef<HTMLInputElement>(null)\n const folderInputRef = useRef<HTMLInputElement>(null)\n const [dragOver, setDragOver] = useState(false)\n const dragDepth = useRef(0)\n\n const setText = useCallback(\n (next: string) => {\n if (!isControlled) setInternal(next)\n onValueChange?.(next)\n },\n [isControlled, onValueChange],\n )\n\n // Keep the textarea height in sync with the content for BOTH typed and\n // external (controlled) value changes — one effect covers both paths.\n useEffect(() => {\n const el = textareaRef.current\n if (!el) return\n el.style.height = 'auto'\n el.style.height = `${Math.min(el.scrollHeight, MAX_HEIGHT)}px`\n }, [text])\n\n // Adopt a one-shot seed. Applies only when the `seed` PROP transitions to a\n // new string (host sets it → consumed here → host clears it via\n // onSeedApplied), so an unstable callback identity re-running this effect\n // can never re-apply a still-set seed over the user's typing. Like\n // `initialValue`, the seed is honored ONLY in uncontrolled mode — a\n // controlled host drives its own `value` (which would shadow `setText`), so\n // it seeds by updating that state itself.\n const prevSeedRef = useRef<string | null>(null)\n const pendingCaretRef = useRef<string | null>(null)\n useEffect(() => {\n const prev = prevSeedRef.current\n prevSeedRef.current = seed ?? null\n if (seed == null || seed === prev || isControlled) return\n setText(seed)\n onSeedApplied?.()\n const el = textareaRef.current\n if (el && el.value === seed) {\n // The DOM already shows the seed — setText was a no-op (the user had\n // typed the exact string), so no re-render is coming and the [text]\n // effect below won't fire. Position the caret now instead of leaving a\n // stranded pendingCaretRef.\n el.focus()\n el.setSelectionRange(seed.length, seed.length)\n } else {\n // Defer caret positioning until the seeded value renders (see below).\n pendingCaretRef.current = seed\n }\n }, [seed, setText, onSeedApplied, isControlled])\n\n // Focus + caret-to-end AFTER the seeded value has rendered into the DOM —\n // setSelectionRange in the applying effect would run against the pre-render\n // value and clamp the caret to the old text's length.\n useEffect(() => {\n if (pendingCaretRef.current == null || pendingCaretRef.current !== text)\n return\n pendingCaretRef.current = null\n const el = textareaRef.current\n if (!el) return\n el.focus()\n el.setSelectionRange(text.length, text.length)\n }, [text])\n\n // A restored draft gets the caret back where the user left it — same\n // post-render rule as the seed above, but to the recorded offsets rather than\n // to the end, so a failed send returns the user to the word they were on.\n const restoreCaretRef = useRef<{ text: string; start: number; end: number } | null>(null)\n useEffect(() => {\n const pending = restoreCaretRef.current\n if (!pending || pending.text !== text) return\n restoreCaretRef.current = null\n const el = textareaRef.current\n if (!el) return\n el.focus()\n const start = Math.min(pending.start, text.length)\n const end = Math.min(pending.end, text.length)\n el.setSelectionRange(start, end)\n }, [text])\n\n // Cmd/Ctrl+L focuses the composer from anywhere — the shortcut the hint\n // advertises. Scoped to when the shortcut is enabled and not disabled.\n useEffect(() => {\n if (!focusShortcut || disabled) return\n function onKeyDown(e: globalThis.KeyboardEvent) {\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'l') {\n e.preventDefault()\n textareaRef.current?.focus()\n }\n }\n document.addEventListener('keydown', onKeyDown)\n return () => document.removeEventListener('keydown', onKeyDown)\n }, [focusShortcut, disabled])\n\n // A ready file counts as sendable content even without a `part`: store-backed\n // attachments (`useComposerAttachments`) carry no prompt part — their\n // references ride the turn body's `attachments` field — but a file-only\n // message must still be sendable.\n const readyFileCount = pendingFiles.filter((f) => f.status === 'ready').length\n const hasSendable = text.trim().length > 0 || readyFileCount > 0\n const canSend = hasSendable && !isStreaming && !disabled\n\n const [failedSend, setFailedSend] = useState<FailedSend | null>(null)\n\n // The draft comes back only when the box is still empty. If the user typed a\n // replacement while the send was in flight, overwriting it would trade one\n // lost message for another — the unsent text is held in the notice instead,\n // where Retry can send it without touching what they typed.\n const failSend = useCallback(\n (error: unknown, draft: string, trimmed: string, parts: ComposerFilePart[], caret: { start: number; end: number }) => {\n const message = sendFailureText(error, sendFailureMessage)\n const restored = textRef.current === ''\n if (restored) {\n const el = textareaRef.current\n setText(draft)\n if (el && el.value === draft) {\n // A handler that rejected SYNCHRONOUSLY did so inside the same event\n // as the clear, so React collapses clear+restore into no state change\n // at all — no re-render is coming and the effect below will never\n // fire. Place the caret now rather than stranding the pending ref.\n el.focus()\n el.setSelectionRange(Math.min(caret.start, draft.length), Math.min(caret.end, draft.length))\n } else {\n restoreCaretRef.current = { text: draft, start: caret.start, end: caret.end }\n }\n }\n setFailedSend({ message, text: draft, trimmed, parts, restored })\n onSendFailed?.({ message, text: draft, parts, error, restored })\n },\n [onSendFailed, sendFailureMessage, setText],\n )\n\n // Hand the message to the host and watch the outcome. The input has already\n // been cleared by the caller — this only decides whether it comes back.\n const dispatchSend = useCallback(\n (draft: string, trimmed: string, parts: ComposerFilePart[], caret: { start: number; end: number }) => {\n let outcome: ComposerSendResult\n try {\n outcome = onSendParts ? onSendParts(trimmed, parts) : onSend?.(trimmed)\n } catch (error) {\n failSend(error, draft, trimmed, parts, caret)\n return\n }\n if (isPromise(outcome)) {\n void outcome.then(\n (settled) => {\n if (isRejectedOutcome(settled)) failSend(settled, draft, trimmed, parts, caret)\n },\n (error: unknown) => failSend(error, draft, trimmed, parts, caret),\n )\n return\n }\n if (isRejectedOutcome(outcome)) failSend(outcome, draft, trimmed, parts, caret)\n },\n [onSend, onSendParts, failSend],\n )\n\n const send = useCallback(() => {\n const trimmed = text.trim()\n if (isStreaming || disabled) return\n const readyFiles = pendingFiles.filter((f) => f.status === 'ready')\n if (!trimmed && readyFiles.length === 0) return\n // Only a parts-aware send carries parts; `onSend`'s files travel through the\n // host's own `pendingFiles`, so its failure payload names none.\n const parts = onSendParts\n ? readyFiles.filter((f) => f.part).map((f) => f.part as ComposerFilePart)\n : []\n const el = textareaRef.current\n const caret = { start: el?.selectionStart ?? text.length, end: el?.selectionEnd ?? text.length }\n setFailedSend(null)\n setText('')\n textRef.current = ''\n dispatchSend(text, trimmed, parts, caret)\n }, [text, isStreaming, disabled, onSendParts, pendingFiles, setText, dispatchSend])\n\n // Re-send the message the notice is holding. Reached only when the draft was\n // NOT restored (the restored path leaves the text in the box, where Send is\n // the affordance), so it never competes with the primary control.\n const retryFailedSend = useCallback(() => {\n const failure = failedSend\n if (!failure || isStreaming || disabled) return\n setFailedSend(null)\n const caret = { start: failure.text.length, end: failure.text.length }\n dispatchSend(failure.text, failure.trimmed, failure.parts, caret)\n }, [failedSend, isStreaming, disabled, dispatchSend])\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n // Respect IME composition — Enter commits the candidate, it doesn't send.\n if (e.nativeEvent.isComposing) return\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n send()\n }\n }\n\n const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.files?.length) onAttach?.(e.target.files)\n e.target.value = ''\n }\n\n const handleFolderChange = (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.files?.length) (onAttachFolder ?? onAttach)?.(e.target.files)\n e.target.value = ''\n }\n\n const handleDragEnter = useCallback((e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n dragDepth.current++\n if (e.dataTransfer?.types.includes('Files')) setDragOver(true)\n }, [])\n\n const handleDragLeave = useCallback((e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n dragDepth.current--\n if (dragDepth.current <= 0) {\n dragDepth.current = 0\n setDragOver(false)\n }\n }, [])\n\n const handleDragOver = useCallback((e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy'\n }, [])\n\n const handleDrop = useCallback(\n (e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n dragDepth.current = 0\n setDragOver(false)\n const files = e.dataTransfer?.files\n if (files?.length) onAttach?.(files)\n },\n [onAttach],\n )\n\n const folderChips = pendingFiles.filter((f) => f.kind === 'folder')\n const fileChips = pendingFiles.filter((f) => f.kind !== 'folder')\n // `above` is the only placement that takes controls OUT of the card, so it is\n // the only one matched exactly; everything else falls to inline. That keeps a\n // retired value (this prop used to accept `footer` for the same placement) or a\n // typo rendering the controls somewhere rather than nowhere — dropping them\n // silently is the one outcome with no recovery for the reader.\n const showAbove = controls != null && controlsPlacement === 'above'\n const showInline = controls != null && !showAbove\n\n return (\n <div\n className={`relative ${className ?? ''}`}\n onDragEnter={onAttach ? handleDragEnter : undefined}\n onDragLeave={onAttach ? handleDragLeave : undefined}\n onDragOver={onAttach ? handleDragOver : undefined}\n onDrop={onAttach ? handleDrop : undefined}\n >\n {dragOver && (\n <div className=\"pointer-events-none absolute inset-0 z-10 flex items-center justify-center rounded-2xl border-2 border-dashed border-primary/50 bg-card\">\n <div className=\"text-center\">\n <span className=\"mx-auto mb-2 flex h-11 w-11 items-center justify-center rounded-xl bg-primary/10 text-primary\">\n <UploadGlyph className=\"h-5 w-5\" />\n </span>\n <p className=\"text-sm font-semibold text-foreground\">{dropTitle}</p>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">{dropDescription}</p>\n </div>\n </div>\n )}\n\n {showAbove && <div className=\"mb-1.5 flex flex-wrap items-center gap-1.5 px-1\">{controls}</div>}\n\n {failedSend && (\n <div\n role=\"alert\"\n data-testid=\"composer-send-error\"\n className=\"mb-2 rounded-xl border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive\"\n >\n <div className=\"flex items-start gap-2\">\n <span className=\"min-w-0 flex-1\">{failedSend.message}</span>\n <button\n type=\"button\"\n aria-label=\"Dismiss send error\"\n onClick={() => setFailedSend(null)}\n className=\"shrink-0 font-medium underline-offset-2 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-destructive/50\"\n >\n Dismiss\n </button>\n </div>\n {/* The draft is only held here when it could NOT go back in the box —\n the user typed a replacement. Showing the bytes is what makes the\n message recoverable by hand even if Retry keeps failing. */}\n {!failedSend.restored && (\n <div className=\"mt-1.5\">\n <p\n data-testid=\"composer-unsent-draft\"\n className=\"max-h-20 overflow-y-auto whitespace-pre-wrap rounded-lg border border-destructive/30 bg-card px-2 py-1 text-foreground\"\n >\n {failedSend.text}\n </p>\n <button\n type=\"button\"\n aria-label=\"Retry sending the unsent message\"\n onClick={retryFailedSend}\n disabled={isStreaming || disabled}\n className=\"mt-1.5 font-medium underline-offset-2 hover:underline disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-destructive/50\"\n >\n Retry\n </button>\n </div>\n )}\n </div>\n )}\n\n {pendingFiles.length > 0 && (\n <div className=\"mb-2 flex flex-wrap gap-1.5\">\n {[...folderChips, ...fileChips].map((f) => (\n <span\n key={f.id}\n className={`inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs ${\n f.status === 'error'\n ? 'border-destructive/40 text-destructive'\n : 'border-border bg-secondary text-foreground'\n }`}\n >\n {f.kind === 'folder' ? <FolderGlyph className=\"h-3 w-3 shrink-0\" /> : <PaperclipGlyph className=\"h-3 w-3 shrink-0\" />}\n <span className=\"max-w-[150px] truncate\">{f.name}</span>\n {f.fileCount !== undefined && <span className=\"text-muted-foreground\">({f.fileCount})</span>}\n {f.status === 'uploading' && (\n <span className=\"h-3 w-3 animate-spin rounded-full border-2 border-primary border-t-transparent\" />\n )}\n {onRemoveFile && (\n <button\n type=\"button\"\n aria-label={`Remove ${f.name}`}\n onClick={() => onRemoveFile(f.id)}\n className=\"rounded p-0.5 text-muted-foreground transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <CloseGlyph className=\"h-3 w-3\" />\n </button>\n )}\n </span>\n ))}\n </div>\n )}\n\n {/* Two rows inside one card: the message gets the full width, and every\n affordance that acts on it — attach, the controls slot, send — sits on\n its own row beneath. A single row would make the textarea share its\n line with the buttons, which is what squeezed the input and pushed the\n controls out of the card in the first place. */}\n <div\n data-testid=\"composer-card\"\n className={`flex flex-col gap-1.5 rounded-2xl border border-card-edge bg-card px-3 py-2.5 transition focus-within:border-primary/40 focus-within:ring-2 focus-within:ring-primary/15 ${\n floating ? 'shadow-raised' : ''\n }`}\n >\n <textarea\n ref={textareaRef}\n value={text}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n // Two lines before it grows. `rows` is what actually holds the floor:\n // the autosize measures `scrollHeight` against `height: auto`, which a\n // textarea resolves through `rows`, so the measurement cannot come back\n // shorter. The paired `min-h-[56px]` is those same two lines in CSS\n // (2 x 24px `leading-6` + 8px `py-1`, and `box-sizing: border-box` puts\n // the padding inside the 56). It sits exactly AT the natural height on\n // purpose: a floor is meant to be inert until something tries to go\n // under it, which here means an inline height arriving from anywhere\n // but the autosize. Setting it higher would buy no protection and cost\n // permanent dead space under the caret.\n rows={2}\n aria-label=\"Message input\"\n className=\"max-h-[168px] min-h-[56px] w-full resize-none bg-transparent px-1.5 py-1 text-[15px] leading-6 text-foreground outline-none placeholder:text-muted-foreground disabled:opacity-50\"\n />\n\n <div className=\"flex items-end gap-2\">\n {onAttach && (\n <>\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n disabled={disabled}\n aria-label=\"Attach files\"\n title=\"Attach files\"\n className=\"shrink-0 rounded-lg p-2 text-muted-foreground transition hover:bg-accent hover:text-foreground disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <PaperclipGlyph className=\"h-4 w-4\" />\n </button>\n <input ref={fileInputRef} type=\"file\" multiple className=\"hidden\" accept={accept} onChange={handleFileChange} />\n </>\n )}\n {onAttachFolder && (\n <>\n <button\n type=\"button\"\n onClick={() => folderInputRef.current?.click()}\n disabled={disabled}\n aria-label=\"Attach folder\"\n title=\"Attach folder\"\n className=\"shrink-0 rounded-lg p-2 text-muted-foreground transition hover:bg-accent hover:text-foreground disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <FolderGlyph className=\"h-4 w-4\" />\n </button>\n {/* webkitdirectory is non-standard but widely supported for folder picks. */}\n <input\n ref={folderInputRef}\n type=\"file\"\n multiple\n className=\"hidden\"\n onChange={handleFolderChange}\n {...({ webkitdirectory: '' } as Record<string, string>)}\n />\n </>\n )}\n\n {/* The controls take the row's slack and wrap onto a second line when\n a long picker set outgrows it. This slot must never establish an\n overflow box: a control owns its popover (ModelPicker, EffortPicker)\n and anchors it absolutely to itself, so a scroll/clip box here traps\n a 400px-tall list inside a ~34px row — the list renders and is never\n visible — and the scroll offset that comes with it cuts the trigger's\n own left edge. Growing a second line is the cost of controls that\n stay operable. Rendered even when empty so Send stays right-aligned. */}\n <div\n data-testid=\"composer-controls\"\n className=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\"\n >\n {showInline && controls}\n </div>\n\n {isStreaming ? (\n <button\n type=\"button\"\n onClick={onCancel}\n aria-label=\"Stop response\"\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-full bg-destructive/15 px-3.5 py-2 text-sm font-medium text-destructive transition hover:bg-destructive/25 focus:outline-none focus-visible:ring-2 focus-visible:ring-destructive/50\"\n >\n <StopGlyph className=\"h-3.5 w-3.5\" />\n <span>Stop</span>\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={send}\n disabled={!canSend}\n aria-label={sendLabel}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-full bg-primary px-3.5 py-2 text-sm font-medium text-primary-foreground shadow-sm transition hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-40 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-card\"\n >\n <SendGlyph className=\"h-3.5 w-3.5\" />\n <span>{sendLabel}</span>\n </button>\n )}\n </div>\n </div>\n\n {focusShortcut && (\n <div className=\"mt-1.5 flex justify-end px-1\">\n <span className=\"text-xs text-muted-foreground\">\n <kbd className=\"rounded border border-border bg-background px-1 py-0.5 text-[10px]\">Cmd</kbd>\n <kbd className=\"ml-0.5 rounded border border-border bg-background px-1 py-0.5 text-[10px]\">L</kbd>\n <span className=\"ml-1\">to focus</span>\n </span>\n </div>\n )}\n </div>\n )\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { ChatPlan } from '../plans/index'\n\n/** Represent durable plan decisions as either approved or rejected */\nexport type DurablePlanDecision = 'approved' | 'rejected'\n\n/** Stable authority receipt for the follow-up turn dispatched by a plan\n * decision. Consumers must make `attachFollowUp` idempotent by `receiptId`;\n * reload and retry deliberately invoke it again. */\nexport interface DurablePlanFollowUpReceipt {\n receiptId: string\n planId: string\n revision: number\n turnId: string\n state: string\n}\n\n/** Describe the result of a durable plan decision including plan details and pending statuses */\nexport interface DurablePlanDecisionResult {\n plan: ChatPlan\n followUp?: DurablePlanFollowUpReceipt\n idempotent: boolean\n projectionPending?: boolean\n effectPending?: boolean\n}\n\n/** Define input parameters for making a durable plan decision including optional feedback */\nexport interface DurablePlanDecisionInput {\n planId: string\n revision: number\n decision: DurablePlanDecision\n feedback?: string\n}\n\n/** Define input parameters for retrieving the current durable plan including optional revision number */\nexport interface DurablePlanCurrentInput {\n planId: string\n revision?: number\n}\n\n/** Define methods to obtain and decide durable plan decisions asynchronously */\nexport interface DurablePlanDecisionClient {\n current: (input: DurablePlanCurrentInput) => Promise<DurablePlanDecisionResult>\n decide: (input: DurablePlanDecisionInput) => Promise<DurablePlanDecisionResult>\n}\n\n/** Represent errors from DurablePlanClient operations including status, code, and current plan details */\nexport class DurablePlanClientError extends Error {\n constructor(\n message: string,\n readonly status: number,\n readonly code?: string,\n readonly currentPlan?: ChatPlan,\n ) {\n super(message)\n this.name = 'DurablePlanClientError'\n }\n}\n\n/** Define configuration options for creating a durable plan decision client */\nexport interface DurablePlanDecisionClientOptions {\n url: string | ((input: DurablePlanCurrentInput | DurablePlanDecisionInput) => string)\n body?: Record<string, unknown> | ((input: DurablePlanDecisionInput) => Record<string, unknown>)\n fetchImpl?: typeof fetch\n}\n\nfunction recordOf(value: unknown): Record<string, unknown> | null {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? value as Record<string, unknown>\n : null\n}\n\nfunction readPlan(value: unknown): ChatPlan | null {\n const plan = recordOf(value)\n if (!plan) return null\n const planId = typeof plan.planId === 'string' ? plan.planId : typeof plan.id === 'string' ? plan.id : null\n if (!planId || typeof plan.revision !== 'number' || typeof plan.body !== 'string' ||\n typeof plan.submittedAt !== 'string' || typeof plan.status !== 'string') return null\n return { ...plan, planId } as ChatPlan\n}\n\nfunction receiptIdentity(plan: ChatPlan, followUp: Record<string, unknown>): string {\n if (typeof followUp.receiptId === 'string' && followUp.receiptId) return followUp.receiptId\n const turnId = typeof followUp.turnId === 'string' ? followUp.turnId : ''\n return `${plan.planId}:${plan.revision}:${turnId}`\n}\n\nfunction parseDecisionResult(value: unknown): DurablePlanDecisionResult | null {\n const body = recordOf(value)\n const plan = readPlan(body?.plan)\n if (!body || !plan) return null\n const rawFollowUp = recordOf(body.followUp) ?? recordOf(body.receipt)\n const followUp = rawFollowUp && typeof rawFollowUp.turnId === 'string'\n ? {\n receiptId: receiptIdentity(plan, rawFollowUp),\n planId: plan.planId,\n revision: plan.revision,\n turnId: rawFollowUp.turnId,\n state: typeof rawFollowUp.state === 'string' ? rawFollowUp.state : 'unknown',\n }\n : undefined\n return {\n plan,\n ...(followUp ? { followUp } : {}),\n idempotent: body.idempotent === true || body.replayed === true,\n ...(body.projectionPending === true ? { projectionPending: true } : {}),\n ...(body.effectPending === true ? { effectPending: true } : {}),\n }\n}\n\nasync function responseBody(response: Response): Promise<Record<string, unknown>> {\n return recordOf(await response.json().catch(() => null)) ?? {}\n}\n\n/** Browser client for the shared durable-plan route. The route URL and all\n * product routing fields are injected; workspace/session identity is still\n * resolved and authorized on the server. */\nexport function createDurablePlanDecisionClient(\n options: DurablePlanDecisionClientOptions,\n): DurablePlanDecisionClient {\n const fetchImpl = options.fetchImpl ?? fetch\n const urlFor = (input: DurablePlanCurrentInput | DurablePlanDecisionInput) =>\n typeof options.url === 'function' ? options.url(input) : options.url\n\n const read = async (response: Response): Promise<DurablePlanDecisionResult> => {\n const body = await responseBody(response)\n const result = parseDecisionResult(body)\n if (response.ok && result) return result\n const currentPlan = readPlan(body.plan) ?? undefined\n const message = typeof body.error === 'string'\n ? body.error\n : typeof body.message === 'string' ? body.message : `Plan request failed (${response.status})`\n throw new DurablePlanClientError(\n message,\n response.status,\n typeof body.code === 'string' ? body.code : undefined,\n currentPlan,\n )\n }\n\n return {\n async current(input) {\n const rawUrl = urlFor(input)\n const url = new URL(rawUrl, globalThis.location?.origin ?? 'http://localhost')\n url.searchParams.set('planId', input.planId)\n if (input.revision !== undefined) url.searchParams.set('revision', String(input.revision))\n const target = /^https?:/.test(rawUrl)\n ? url.toString()\n : `${url.pathname}${url.search}`\n return read(await fetchImpl(target, { method: 'GET' }))\n },\n async decide(input) {\n const extra = typeof options.body === 'function' ? options.body(input) : options.body ?? {}\n return read(await fetchImpl(urlFor(input), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ ...extra, ...input }),\n }))\n },\n }\n}\n\n/** Define options to configure durable plan flow with plan, client, and optional callbacks */\nexport interface UseDurablePlanFlowOptions {\n plan: ChatPlan\n client: DurablePlanDecisionClient\n /** Must be idempotent by receipt.receiptId. */\n attachFollowUp?: (receipt: DurablePlanFollowUpReceipt) => Promise<void> | void\n onUpdated?: (plan: ChatPlan) => void\n}\n\n/** Define the result and actions for managing a durable plan flow including decisions, restoration, and error handling */\nexport interface UseDurablePlanFlowResult {\n plan: ChatPlan\n deciding: DurablePlanDecision | null\n restoring: boolean\n error: string | null\n decide: (decision: DurablePlanDecision, feedback?: string) => Promise<DurablePlanDecisionResult | null>\n restore: () => Promise<DurablePlanDecisionResult | null>\n clearError: () => void\n}\n\n/** Shared plan decision controller. It coalesces only concurrent attachment\n * attempts; a later retry/restore calls the consumer's idempotent transport\n * again so a lost response cannot strand an already-dispatched follow-up. */\nexport function useDurablePlanFlow(options: UseDurablePlanFlowOptions): UseDurablePlanFlowResult {\n const [plan, setPlan] = useState(options.plan)\n const [deciding, setDeciding] = useState<DurablePlanDecision | null>(null)\n const [restoring, setRestoring] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const attachments = useRef(new Map<string, Promise<void>>())\n const decisionInFlight = useRef(false)\n\n useEffect(() => setPlan(options.plan), [options.plan])\n\n const apply = useCallback(async (result: DurablePlanDecisionResult) => {\n setPlan(result.plan)\n options.onUpdated?.(result.plan)\n const receipt = result.followUp\n if (!receipt || !options.attachFollowUp) return\n let pending = attachments.current.get(receipt.receiptId)\n if (!pending) {\n pending = Promise.resolve(options.attachFollowUp(receipt))\n attachments.current.set(receipt.receiptId, pending)\n void pending.finally(() => attachments.current.delete(receipt.receiptId))\n }\n await pending\n }, [options.attachFollowUp, options.onUpdated])\n\n const decide = useCallback(async (decision: DurablePlanDecision, feedback?: string) => {\n if (decisionInFlight.current) return null\n decisionInFlight.current = true\n setDeciding(decision)\n setError(null)\n try {\n const result = await options.client.decide({\n planId: plan.planId,\n revision: plan.revision,\n decision,\n ...(feedback?.trim() ? { feedback: feedback.trim() } : {}),\n })\n await apply(result)\n return result\n } catch (cause) {\n if (cause instanceof DurablePlanClientError && cause.currentPlan) {\n setPlan(cause.currentPlan)\n options.onUpdated?.(cause.currentPlan)\n }\n setError(cause instanceof Error ? cause.message : 'Could not decide the plan.')\n return null\n } finally {\n decisionInFlight.current = false\n setDeciding(null)\n }\n }, [apply, options.client, options.onUpdated, plan.planId, plan.revision])\n\n const restore = useCallback(async () => {\n setRestoring(true)\n setError(null)\n try {\n const result = await options.client.current({ planId: plan.planId, revision: plan.revision })\n await apply(result)\n return result\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : 'Could not restore the plan.')\n return null\n } finally {\n setRestoring(false)\n }\n }, [apply, options.client, plan.planId, plan.revision])\n\n return { plan, deciding, restoring, error, decide, restore, clearError: () => setError(null) }\n}\n","import {\n INTERACTION_SUBMIT_TIMEOUT_MESSAGE,\n INTERACTION_SUBMIT_TIMEOUT_MS,\n responseErrorMessage,\n type InteractionAnswerSubmission,\n type InteractionAnswerSubmitterOptions,\n type SubmitInteractionAnswer,\n} from './interaction-card-support'\n\n/** Manage storage and retrieval of interaction attempt keys by interaction and submission identifiers */\nexport interface InteractionAttemptStore {\n get(interactionId: string, submissionSignature: string): string | null\n set(interactionId: string, submissionSignature: string, attemptKey: string): void\n delete(interactionId: string, submissionSignature: string): void\n}\n\nfunction attemptStorageKey(namespace: string, interactionId: string): string {\n return `${namespace}:${encodeURIComponent(interactionId)}`\n}\n\nfunction storedAttempts(storage: Pick<Storage, 'getItem'>, key: string): Record<string, string> {\n try {\n const value = JSON.parse(storage.getItem(key) ?? '{}') as unknown\n return value && typeof value === 'object' && !Array.isArray(value)\n ? value as Record<string, string>\n : {}\n } catch {\n return {}\n }\n}\n\n/** Create a session-based store to manage interaction attempts using provided storage and optional namespace */\nexport function createSessionInteractionAttemptStore(\n storage: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>,\n namespace = 'agent-app:interaction-attempt',\n): InteractionAttemptStore {\n return {\n get(id, signature) {\n return storedAttempts(storage, attemptStorageKey(namespace, id))[signature] ?? null\n },\n set(id, signature, attemptKey) {\n const key = attemptStorageKey(namespace, id)\n storage.setItem(key, JSON.stringify({ ...storedAttempts(storage, key), [signature]: attemptKey }))\n },\n delete(id, signature) {\n const key = attemptStorageKey(namespace, id)\n const attempts = storedAttempts(storage, key)\n delete attempts[signature]\n if (Object.keys(attempts).length === 0) storage.removeItem(key)\n else storage.setItem(key, JSON.stringify(attempts))\n },\n }\n}\n\n/** Create an in-memory store to manage interaction attempts keyed by ID and signature */\nexport function createMemoryInteractionAttemptStore(): InteractionAttemptStore {\n const attempts = new Map<string, string>()\n const key = (id: string, signature: string) => `${id}\\u0000${signature}`\n return {\n get: (id, signature) => attempts.get(key(id, signature)) ?? null,\n set: (id, signature, attemptKey) => attempts.set(key(id, signature), attemptKey),\n delete: (id, signature) => { attempts.delete(key(id, signature)) },\n }\n}\n\nfunction stableValue(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(stableValue)\n if (!value || typeof value !== 'object') return value\n return Object.fromEntries(Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, nested]) => [key, stableValue(nested)]))\n}\n\n/** Generate a stable string signature from an interaction answer submission */\nexport function interactionSubmissionSignature(submission: InteractionAnswerSubmission): string {\n return JSON.stringify(stableValue(submission))\n}\n\n/** Define options for submitting durable interaction answers with attempt tracking and optional key creation */\nexport interface DurableInteractionAnswerSubmitterOptions extends InteractionAnswerSubmitterOptions {\n attempts: InteractionAttemptStore\n createAttemptKey?: () => string\n}\n\nfunction defaultAttemptKey(): string {\n if (globalThis.crypto?.randomUUID) return globalThis.crypto.randomUUID()\n return `attempt-${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\n/** Answer submitter for a durable interaction route. One opaque attempt key is\n * retained for an ambiguous transport/5xx result and reused after reload. A\n * changed answer has a different signature and therefore a new attempt. */\nexport function createDurableInteractionAnswerSubmitter(\n options: DurableInteractionAnswerSubmitterOptions,\n): SubmitInteractionAnswer {\n const timeoutMs = options.timeoutMs ?? INTERACTION_SUBMIT_TIMEOUT_MS\n const fetchImpl = options.fetchImpl ?? fetch\n return async (submission) => {\n const signature = interactionSubmissionSignature(submission)\n let attemptKey: string\n try {\n attemptKey = options.attempts.get(submission.id, signature) ?? ''\n if (!attemptKey) {\n attemptKey = (options.createAttemptKey ?? defaultAttemptKey)()\n options.attempts.set(submission.id, signature, attemptKey)\n }\n } catch (cause) {\n return {\n ok: false,\n expired: false,\n message: cause instanceof Error ? cause.message : 'Failed to submit the answer',\n }\n }\n const url = typeof options.url === 'function' ? options.url(submission) : options.url\n const extra = typeof options.body === 'function' ? options.body(submission) : options.body ?? {}\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(INTERACTION_SUBMIT_TIMEOUT_MESSAGE), timeoutMs)\n try {\n const response = await fetchImpl(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n signal: controller.signal,\n body: JSON.stringify({\n ...extra,\n id: submission.id,\n outcome: submission.outcome,\n attemptKey,\n ...(submission.data ? { data: submission.data } : {}),\n }),\n })\n if (response.ok) {\n options.attempts.delete(submission.id, signature)\n return { ok: true }\n }\n const failure = await responseErrorMessage(response)\n if (response.status < 500) options.attempts.delete(submission.id, signature)\n return { ok: false, expired: response.status === 410, message: failure.message }\n } catch (cause) {\n if (controller.signal.aborted) {\n return { ok: false, expired: false, message: INTERACTION_SUBMIT_TIMEOUT_MESSAGE }\n }\n return {\n ok: false,\n expired: false,\n message: cause instanceof Error ? cause.message : 'Failed to submit the answer',\n }\n } finally {\n clearTimeout(timer)\n }\n }\n}\n","/**\n * useChatInteractions — the interaction-state wiring every consumer of\n * `ChatStreamCallbacks.onInteraction` re-implements: an id-keyed,\n * insertion-ordered list with\n *\n * - forward-only status transitions (a replayed/stale `pending` never\n * resurrects a resolved card),\n * - pending-question content dedupe (a re-emitted duplicate ask never renders\n * a second card),\n * - cancel-event application (`interaction.cancel` → cancelled/expired),\n * - local resolution marking (the card's `onResolved`),\n * - reload restore from the answer route's GET list (sidecar registry is the\n * source of truth after a reload),\n * - turn-end settling (client mirror of the server's finalize pass: a turn\n * that completed without a cancel was answered; a failed turn can make no\n * such claim).\n *\n * The reducer functions are pure and exported for non-React consumers/tests;\n * the hook is a thin `useState` shell over them.\n */\n\nimport { useCallback, useMemo, useState } from 'react'\nimport {\n cancelStatusFor,\n interactionFromWireRequest,\n isTerminalInteractionStatus,\n questionInteractionContentSignature,\n type ChatInteraction,\n type ChatInteractionStatus,\n type InteractionAnswers,\n type InteractionCancelData,\n type InteractionRequestWire,\n} from './chat-interactions'\n\nfunction hasPendingContentDuplicate(list: ChatInteraction[], interaction: ChatInteraction): boolean {\n if (interaction.status !== 'pending') return false\n const signature = questionInteractionContentSignature(interaction)\n if (!signature) return false\n return list.some((item) =>\n item.id !== interaction.id &&\n item.status === 'pending' &&\n questionInteractionContentSignature(item) === signature)\n}\n\n/** Insert or update one interaction. A terminal existing entry wins over any\n * incoming state for the same id; a new pending ask that duplicates another\n * pending ask's content is dropped. Returns the same array when unchanged. */\nexport function upsertChatInteraction(list: ChatInteraction[], interaction: ChatInteraction): ChatInteraction[] {\n const index = list.findIndex((item) => item.id === interaction.id)\n if (index === -1) {\n if (hasPendingContentDuplicate(list, interaction)) return list\n return [...list, interaction]\n }\n const existing = list[index]\n if (!existing) return list\n if (isTerminalInteractionStatus(existing.status)) {\n if (\n existing.status === interaction.status &&\n (!existing.answers && interaction.answers || !existing.cancelReason && interaction.cancelReason)\n ) {\n const next = [...list]\n next[index] = { ...existing, ...interaction }\n return next\n }\n return list\n }\n const next = [...list]\n next[index] = interaction\n return next\n}\n\n/** Applies an `interaction.cancel` event: only a pending ask moves, to\n * `expired` (reason:\"timeout\") or `cancelled`. */\nexport function cancelChatInteraction(list: ChatInteraction[], cancel: InteractionCancelData): ChatInteraction[] {\n const index = list.findIndex((item) => item.id === cancel.id)\n const existing = list[index]\n if (!existing || existing.status !== 'pending') return list\n const next = [...list]\n next[index] = {\n ...existing,\n status: cancelStatusFor(cancel.reason),\n ...(cancel.reason ? { cancelReason: cancel.reason } : {}),\n }\n return next\n}\n\n/** Marks one ask resolved locally (the card's `onResolved`). Forward-only. */\nexport function resolveChatInteraction(\n list: ChatInteraction[],\n id: string,\n status: Exclude<ChatInteractionStatus, 'pending'>,\n answers?: InteractionAnswers,\n): ChatInteraction[] {\n const index = list.findIndex((item) => item.id === id)\n const existing = list[index]\n if (!existing || existing.status !== 'pending') return list\n const next = [...list]\n next[index] = { ...existing, status, ...(answers ? { answers } : {}) }\n return next\n}\n\n/** Settles every still-pending ask when the turn ends: `answered` for a turn\n * that completed cleanly, `expired` for one that failed. */\nexport function terminalizePendingChatInteractions(\n list: ChatInteraction[],\n status: Extract<ChatInteractionStatus, 'answered' | 'expired'>,\n): ChatInteraction[] {\n if (!list.some((item) => item.status === 'pending')) return list\n return list.map((item) => (item.status === 'pending' ? { ...item, status } : item))\n}\n\n/** Define modes for restoring chat interactions with legacy or durable strategies */\nexport type ChatInteractionRestoreMode = 'legacy' | 'durable'\n\n/** Define options to control how chat interactions are restored during the restore process */\nexport interface RestoreChatInteractionsOptions {\n /**\n * `legacy` settles pending asks absent from the sidecar list as answered,\n * preserving the pre-durable restore contract. `durable` leaves them\n * pending because absence is ambiguous until `hydrateChatInteractions`\n * applies the durable projection.\n */\n mode?: ChatInteractionRestoreMode\n}\n\n/** Reload restore from the answer route's GET list. Legacy consumers retain\n * the historical absence→answered behavior; durable consumers opt into the\n * ambiguity-preserving mode and apply terminal parts through `hydrate`. */\nexport function restoreChatInteractions(\n list: ChatInteraction[],\n outstanding: InteractionRequestWire[],\n options: RestoreChatInteractionsOptions = {},\n): ChatInteraction[] {\n let next = list\n for (const request of outstanding) {\n const interaction = interactionFromWireRequest(request)\n const exact = next.findIndex((item) => item.id === interaction.id)\n if (exact !== -1) {\n next = upsertChatInteraction(next, interaction)\n continue\n }\n const signature = questionInteractionContentSignature(interaction)\n const obsolete = signature\n ? next.findIndex((item) => item.status === 'pending' && questionInteractionContentSignature(item) === signature)\n : -1\n if (obsolete === -1) {\n next = [...next, interaction]\n continue\n }\n next = [...next]\n next[obsolete] = interaction\n }\n if (options.mode !== 'durable') {\n const outstandingIds = new Set(outstanding.map((request) => request.id))\n next = next.map((item) =>\n item.status === 'pending' && !outstandingIds.has(item.id)\n ? { ...item, status: 'answered' as const }\n : item)\n }\n return next\n}\n\n/** Applies transcript/state-store projections after reload. Terminal state and\n * acknowledged answer values enrich an existing pending card without relying\n * on the sidecar's outstanding-list absence. */\nexport function hydrateChatInteractions(\n list: ChatInteraction[],\n persisted: ChatInteraction[],\n): ChatInteraction[] {\n return persisted.reduce(upsertChatInteraction, list)\n}\n\n/** Resolve and manage chat interactions with methods to update, cancel, mark resolved, and restore state */\nexport interface UseChatInteractionsResult {\n /** All known interactions, insertion-ordered. */\n interactions: ChatInteraction[]\n /** The asks currently blocking the run (waiting on the user). */\n pending: ChatInteraction[]\n /** Wire to `ChatStreamCallbacks.onInteraction` (and persisted-part replay). */\n upsert: (interaction: ChatInteraction) => void\n /** Wire to `interaction.cancel` events. */\n applyCancel: (cancel: InteractionCancelData) => void\n /** Wire to the cards' `onResolved`. */\n markResolved: (id: string, status: Exclude<ChatInteractionStatus, 'pending'>, answers?: InteractionAnswers) => void\n /** Wire to the answer route's GET list after a reload/reconnect. */\n restore: (outstanding: InteractionRequestWire[], options?: RestoreChatInteractionsOptions) => void\n /** Apply durable transcript/state projections after a reload. */\n hydrate: (persisted: ChatInteraction[]) => void\n /** Settle still-pending asks when the turn ends. */\n terminalizePending: (status: Extract<ChatInteractionStatus, 'answered' | 'expired'>) => void\n /** Drop everything (thread switch). */\n reset: () => void\n}\n\n/** Resolve options for restoring chat interactions from previous sessions */\nexport type UseChatInteractionsOptions = RestoreChatInteractionsOptions\n\n/** Manage chat interactions state with upsert, cancel, resolve, and restore capabilities */\nexport function useChatInteractions(options: UseChatInteractionsOptions = {}): UseChatInteractionsResult {\n const [interactions, setInteractions] = useState<ChatInteraction[]>([])\n\n const upsert = useCallback((interaction: ChatInteraction) => {\n setInteractions((prev) => upsertChatInteraction(prev, interaction))\n }, [])\n const applyCancel = useCallback((cancel: InteractionCancelData) => {\n setInteractions((prev) => cancelChatInteraction(prev, cancel))\n }, [])\n const markResolved = useCallback((id: string, status: Exclude<ChatInteractionStatus, 'pending'>, answers?: InteractionAnswers) => {\n setInteractions((prev) => resolveChatInteraction(prev, id, status, answers))\n }, [])\n const restore = useCallback((outstanding: InteractionRequestWire[], restoreOptions?: RestoreChatInteractionsOptions) => {\n setInteractions((prev) => restoreChatInteractions(prev, outstanding, {\n mode: restoreOptions?.mode ?? options.mode,\n }))\n }, [options.mode])\n const hydrate = useCallback((persisted: ChatInteraction[]) => {\n setInteractions((prev) => hydrateChatInteractions(prev, persisted))\n }, [])\n const terminalizePending = useCallback((status: Extract<ChatInteractionStatus, 'answered' | 'expired'>) => {\n setInteractions((prev) => terminalizePendingChatInteractions(prev, status))\n }, [])\n const reset = useCallback(() => setInteractions([]), [])\n\n const pending = useMemo(() => interactions.filter((item) => item.status === 'pending'), [interactions])\n\n return { interactions, pending, upsert, applyCancel, markResolved, restore, hydrate, terminalizePending, reset }\n}\n","/**\n * `useFileMentions` — the glue a host passes straight into `AgentComposer`'s\n * `mention` prop (`@tangle-network/sandbox-ui#184`) to wire up `@`-file\n * mentions against `createSandboxFileIndexRoute` (`/chat-routes`).\n *\n * Fetches the index once per session from `indexUrl`, refreshes it in the\n * background whenever the popover opens (a `fetchItems` call) if the cached\n * copy has aged past `refreshAfterMs`, and answers every keystroke from an\n * in-memory fuzzy filter — no per-keystroke network round trip. The returned\n * `refresh()` lets a caller force a re-fetch immediately instead of waiting\n * on `refreshAfterMs` — e.g. right after the agent creates a file mid-session.\n *\n * `MentionItem`/the `mention` prop shape mirror the FROZEN contract from\n * sandbox-ui#184 structurally (no import: `/web-react` stays dependency-free\n * beyond React, and `@tangle-network/sandbox-ui` is an optional peer).\n */\n\nimport { useCallback, useMemo, useRef, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport type { FileIndexResponse, FileIndexReadyResponse } from '../chat-routes/file-index'\nimport type { FileMention } from '../chat-routes/wire'\n\n/** Mirrors sandbox-ui#184's `MentionItem` — the atomic pill's payload. For a\n * file mention, `id` is the workspace-relative path (the pill's stable\n * identity and the `@<id>` serialization sandbox-ui uses to round-trip\n * `value`), `label` is the display name, and `detail` carries the full path\n * for the popover row's secondary line. */\nexport interface MentionItem {\n id: string\n label: string\n detail?: string\n kind?: string\n}\n\n/** Mirrors sandbox-ui#184's `AgentComposerProps['mention']` shape — plug the\n * hook's `mention` return value straight into that prop. */\nexport interface ComposerMentionProp {\n trigger?: string\n fetchItems(query: string): Promise<MentionItem[]>\n onMentionsChange?(mentions: MentionItem[]): void\n renderItem?(item: MentionItem): ReactNode\n emptyText?: string\n}\n\nconst FILE_MENTION_KIND = 'file'\n\nfunction toMentionItem(file: FileMention): MentionItem {\n return { id: file.path, label: file.name, detail: file.path, kind: FILE_MENTION_KIND }\n}\n\nfunction toFileMention(item: MentionItem): FileMention {\n return { path: item.id, name: item.label }\n}\n\n/**\n * Ranks `files` against `query` (case-insensitive), capped to `limit`:\n * name-prefix matches first, then name-substring, then path-substring.\n * Within a tier, shorter names sort first (the more specific match), then\n * alphabetically by path for a stable order. An empty query returns the\n * first `limit` entries unranked — the popover's default list before typing.\n * Pure and dependency-free (no fuzzy-match library) so it's cheap enough to\n * re-run on every keystroke against a 10k-entry index.\n */\nexport function rankFileMentions(\n files: readonly FileMention[],\n query: string,\n limit: number,\n): FileMention[] {\n const q = query.trim().toLowerCase()\n if (!q) return files.slice(0, limit)\n const scored: Array<{ file: FileMention; tier: 0 | 1 | 2 }> = []\n for (const file of files) {\n const name = file.name.toLowerCase()\n if (name.startsWith(q)) {\n scored.push({ file, tier: 0 })\n continue\n }\n if (name.includes(q)) {\n scored.push({ file, tier: 1 })\n continue\n }\n if (file.path.toLowerCase().includes(q)) {\n scored.push({ file, tier: 2 })\n }\n }\n scored.sort((a, b) => {\n if (a.tier !== b.tier) return a.tier - b.tier\n if (a.file.name.length !== b.file.name.length) return a.file.name.length - b.file.name.length\n return a.file.path.localeCompare(b.file.path)\n })\n return scored.slice(0, limit).map((s) => s.file)\n}\n\ntype IndexState =\n | { kind: 'idle' }\n | { kind: 'loading' }\n | { kind: 'ready'; files: FileMention[]; truncated: boolean; fetchedAt: number }\n | { kind: 'warming'; attemptedAt: number }\n | { kind: 'error'; message: string; attemptedAt: number }\n\n/** Minimum spacing between automatic retries while the box is warming or the\n * last attempt errored — a query per keystroke would otherwise hammer the\n * index endpoint the whole time the box is cold. */\nconst RETRY_AFTER_MS = 3000\n\n/** Max popover results per query — enough to show a useful spread of matches\n * without pushing the fuzzy-filtered list past what a popover can usefully\n * render in one screen. */\nexport const DEFAULT_MENTION_LIMIT = 20\n\n/** How long a `ready` index is served before a background refetch — long\n * enough that a full session's worth of popover opens don't repeatedly hit\n * the index endpoint, short enough that a stale listing doesn't linger too\n * far past workspace file changes. Callers who need the index current right\n * now (e.g. just after the agent creates a file) call `refresh()` instead of\n * waiting on this window. */\nexport const INDEX_REFRESH_AFTER_MS = 5 * 60 * 1000\n\n/** Popover empty-state copy for a `ready` index whose query matched nothing.\n * Loading/warming/error states have their own copy — see `emptyTextFor`. */\nexport const DEFAULT_MENTION_EMPTY_TEXT = 'No matching files'\n\n/** Define options for configuring file mention fetching, caching, and display behavior */\nexport interface UseFileMentionsOptions {\n /** GET endpoint returning `FileIndexResponse` (a `createSandboxFileIndexRoute`). */\n indexUrl: string\n /** Max popover results per query. Default {@link DEFAULT_MENTION_LIMIT}. */\n limit?: number\n /** How long a `ready` index is served without a background refetch.\n * Default {@link INDEX_REFRESH_AFTER_MS}. */\n refreshAfterMs?: number\n /** `fetch` override for tests / non-global-fetch hosts. Default `fetch`. */\n fetchImpl?: typeof fetch\n /** Text shown in the popover's empty state once the index is loaded and\n * the query matched nothing. Default {@link DEFAULT_MENTION_EMPTY_TEXT}. */\n emptyText?: string\n}\n\n/** Provide properties and methods to manage and refresh file mentions in a composer interface */\nexport interface UseFileMentionsResult {\n /** Spread straight into `AgentComposer`'s `mention` prop. */\n mention: ComposerMentionProp\n /** The files currently referenced by mentions in the composer's value —\n * the send-body list (map through `fileMentionsToParts`). */\n mentions: FileMention[]\n /** Drop all currently-referenced mentions (e.g. after a successful send). */\n clearMentions: () => void\n /** Force a re-fetch of the index right now, ignoring `refreshAfterMs` — for\n * example right after the agent creates a file mid-session, so the next\n * popover open sees it. Dedupes against an already-in-flight load rather\n * than firing a second request. */\n refresh: () => Promise<void>\n}\n\n/** Never blocks — a `warming` or `error` index answers `fetchItems` with an\n * empty list plus an explanatory `emptyText`, since the frozen composer\n * contract has no separate loading/warming slot. */\nfunction emptyTextFor(state: IndexState, fallback: string): string {\n switch (state.kind) {\n case 'idle':\n case 'loading':\n return 'Loading files…'\n case 'warming':\n return 'Sandbox is starting — try again in a moment'\n case 'error':\n return `Couldn't load files: ${state.message}`\n case 'ready':\n return fallback\n }\n}\n\n/** Resolve and manage file mention data with configurable fetching and state handling */\nexport function useFileMentions(options: UseFileMentionsOptions): UseFileMentionsResult {\n const {\n indexUrl,\n limit = DEFAULT_MENTION_LIMIT,\n refreshAfterMs = INDEX_REFRESH_AFTER_MS,\n emptyText = DEFAULT_MENTION_EMPTY_TEXT,\n } = options\n const fetchImpl = options.fetchImpl ?? fetch\n\n const [state, setState] = useState<IndexState>({ kind: 'idle' })\n // `fetchItems` needs the settled result of a fetch it just awaited, but a\n // `setState` call doesn't synchronously update anything a plain callback\n // can read — the re-render (and this ref's refresh) lands on a later tick.\n // `load()` returns its resolved `IndexState` directly (and mirrors it onto\n // this ref) so `fetchItems` never depends on render timing for its answer;\n // the ref separately lets `fetchItems` read the CURRENT state up front\n // without subscribing to it (which would break `mention`'s referential\n // stability on every keystroke).\n const stateRef = useRef(state)\n stateRef.current = state\n const inFlightRef = useRef<Promise<IndexState> | null>(null)\n const [mentions, setMentions] = useState<FileMention[]>([])\n\n const load = useCallback((): Promise<IndexState> => {\n if (inFlightRef.current) return inFlightRef.current\n if (stateRef.current.kind === 'idle') {\n stateRef.current = { kind: 'loading' }\n setState(stateRef.current)\n }\n const attempt = (async (): Promise<IndexState> => {\n let next: IndexState\n try {\n const res = await fetchImpl(indexUrl)\n if (!res.ok) {\n next = { kind: 'error', message: `HTTP ${res.status}`, attemptedAt: Date.now() }\n } else {\n const body = (await res.json()) as FileIndexResponse\n next =\n body.status === 'warming'\n ? { kind: 'warming', attemptedAt: Date.now() }\n : {\n kind: 'ready',\n files: (body as FileIndexReadyResponse).files,\n truncated: (body as FileIndexReadyResponse).truncated,\n fetchedAt: Date.now(),\n }\n }\n } catch (err) {\n next = { kind: 'error', message: err instanceof Error ? err.message : String(err), attemptedAt: Date.now() }\n }\n stateRef.current = next\n setState(next)\n inFlightRef.current = null\n return next\n })()\n inFlightRef.current = attempt\n return attempt\n }, [fetchImpl, indexUrl])\n\n // `load()` itself never consults `refreshAfterMs` — that gate lives in\n // `fetchItems` — so calling it directly here already bypasses the TTL. The\n // in-flight dedup inside `load()` covers the case where a background\n // refresh from `fetchItems` is already running.\n const refresh = useCallback(async (): Promise<void> => {\n await load()\n }, [load])\n\n const fetchItems = useCallback(\n async (query: string): Promise<MentionItem[]> => {\n let current = stateRef.current\n // First open: block on the fetch so the popover's first result set\n // reflects it. Once `ready`, background-refresh a stale cache without\n // blocking this query's answer. A warming/errored index retries at\n // most every RETRY_AFTER_MS — not on every keystroke.\n if (current.kind === 'idle' || current.kind === 'loading') {\n current = await load()\n } else if (current.kind === 'ready') {\n if (Date.now() - current.fetchedAt > refreshAfterMs) void load()\n } else if (Date.now() - current.attemptedAt > RETRY_AFTER_MS) {\n void load()\n }\n if (current.kind !== 'ready') return []\n return rankFileMentions(current.files, query, limit).map(toMentionItem)\n },\n [load, limit, refreshAfterMs],\n )\n\n const onMentionsChange = useCallback((items: MentionItem[]) => {\n setMentions(items.filter((item) => item.kind === undefined || item.kind === FILE_MENTION_KIND).map(toFileMention))\n }, [])\n\n const clearMentions = useCallback(() => setMentions([]), [])\n\n const mention = useMemo<ComposerMentionProp>(\n () => ({\n fetchItems,\n onMentionsChange,\n emptyText: emptyTextFor(state, emptyText),\n }),\n [fetchItems, onMentionsChange, state, emptyText],\n )\n\n return { mention, mentions, clearMentions, refresh }\n}\n","/**\n * Transcript-side counterpart to the composer's `@`-mention primitive\n * (sandbox-ui#184). The composer serializes a picked file into the message\n * text as `@<path>`; this module is the exact inverse — it finds those tokens\n * again in a PERSISTED message and splits the text so a renderer can draw a\n * pill where the user typed one and leave the rest as prose.\n *\n * Pure and product-agnostic: no React, no fetch, no DOM. The only input beyond\n * the text is the message's OWN mention parts, so one message can never render\n * a pill for a path another message mentioned.\n *\n * `ChatMentionPart` and the runtime helpers `mentionInputToPart` /\n * `mentionPartsFromMessageParts` are re-exported here from `../chat-store/parts`\n * directly (not the `/chat-store` barrel), so a browser bundle gets the mention\n * vocabulary and its converters without importing `/chat-store`, whose barrel\n * pulls the drizzle peer.\n */\n\nimport { mentionInputToPart, mentionPartsFromMessageParts, type ChatMentionKind, type ChatMentionPart } from '../chat-store/parts'\n\nexport type { ChatMentionKind, ChatMentionPart }\nexport { mentionInputToPart, mentionPartsFromMessageParts }\n\n/** One run of a segmented message: literal prose, or a matched mention with\n * the part that produced it. `text` for a mention segment is the token as it\n * appears in the message (`@<path>`), so a renderer that ignores `part` still\n * reproduces the original string exactly. */\nexport interface MentionTextSegment {\n type: 'text' | 'mention'\n text: string\n part?: ChatMentionPart\n}\n\n/** A character that could plausibly continue the SAME path/filename past a\n * matched token. Without this lookahead a mention of `@a/b.md` would match\n * inside the unrelated `@a/b.md.bak` and split it mid-filename.\n *\n * Unicode-aware because the wire validator (`validateSandboxMentionPath`)\n * deliberately ALLOWS non-ASCII paths — in-box filenames are arbitrary. An\n * ASCII-only class here would accept input the segmenter then mangles. */\nconst PATH_CONTINUATION_CHAR = /[\\p{L}\\p{N}._\\-/]/u\n/** A character that, immediately BEFORE an `@`, means the `@` is part of a\n * longer token (an email local part, a handle) rather than a mention start.\n * Unicode-aware for the same reason. */\nconst WORD_CHAR = /[\\p{L}\\p{N}]/u\n\n/**\n * Split a message's text into plain-text and mention segments by matching\n * `@<path>` runs against that message's own mention parts.\n *\n * Only a part whose exact `@<path>` token appears in `content`, at a token\n * boundary on both sides, counts as a match; everything else — including\n * unrelated `@` text — passes through as plain text untouched. When two parts'\n * tokens both match at the same position (one path a prefix of another), the\n * LONGEST token wins, so nested-looking paths split at the right boundary.\n *\n * Returns the matched parts alongside the segments: a caller that also renders\n * a fallback chip row can drop the chip for anything now shown inline and keep\n * it only for mentions the text does not actually contain (a restored draft, a\n * queued message whose text was edited).\n */\nexport function segmentMentionContent(\n content: string,\n parts: ReadonlyArray<ChatMentionPart>,\n): { segments: MentionTextSegment[]; matched: Set<ChatMentionPart> } {\n const matched = new Set<ChatMentionPart>()\n if (!content) return { segments: [], matched }\n if (parts.length === 0) return { segments: [{ type: 'text', text: content }], matched }\n\n const candidates = parts\n .map((part) => ({ part, token: `@${part.path}` }))\n .sort((a, b) => b.token.length - a.token.length)\n\n const segments: MentionTextSegment[] = []\n let cursor = 0\n let textStart = 0\n while (cursor < content.length) {\n if (content[cursor] !== '@') {\n cursor += 1\n continue\n }\n const prevChar = cursor > 0 ? content[cursor - 1] : undefined\n if (prevChar && WORD_CHAR.test(prevChar)) {\n cursor += 1\n continue\n }\n const candidate = candidates.find(({ token }) => content.startsWith(token, cursor))\n if (!candidate) {\n cursor += 1\n continue\n }\n const endIdx = cursor + candidate.token.length\n const nextChar = endIdx < content.length ? content[endIdx] : undefined\n if (nextChar && PATH_CONTINUATION_CHAR.test(nextChar)) {\n cursor += 1\n continue\n }\n\n if (cursor > textStart) segments.push({ type: 'text', text: content.slice(textStart, cursor) })\n segments.push({ type: 'mention', text: candidate.token, part: candidate.part })\n matched.add(candidate.part)\n cursor = endIdx\n textStart = cursor\n }\n if (textStart < content.length) segments.push({ type: 'text', text: content.slice(textStart) })\n\n return { segments, matched }\n}\n","/**\n * Mission + delegation observability surfaces — different nouns, one trace\n * tree:\n *\n * - {@link MissionActivityLane}: the collapsed sub-rows under a mission step\n * (what the step's agent is actually doing), expanding to a compact web\n * waterfall rendered from the `/trace` converters.\n * - {@link AgentActivityPanel}: the standalone cross-context surface — every\n * delegation a workspace ran, regardless of which mission (if any) spawned\n * it — behind a `fetchActivity` data port with cursor + refresh.\n * - {@link FlowWaterfall}: the web counterpart of `/trace`'s ASCII\n * `renderWaterfall` (which stays CLI) — proportional bars over a FlowTrace.\n *\n * Same styling contract as the rest of `/web-react`: Tailwind classes against\n * the shared design tokens, inline SVG glyphs, no icon library. The pure\n * layout/merge/format helpers are exported for tests and reuse.\n */\n\nimport { useCallback, useEffect, useState, type ReactNode } from 'react'\n\nimport type { StepAgentActivity } from '../missions/agent-activity'\nimport type { FlowTrace } from '../trace/index'\nimport { stepActivityFlowTrace } from '../trace/mission-flow'\n\n// ── pure helpers ──────────────────────────────────────────────────────────\n\nexport type ActivityTone = 'live' | 'ok' | 'error' | 'neutral'\n\nconst LIVE_STATUSES = new Set(['pending', 'running'])\nconst OK_STATUSES = new Set(['completed', 'done', 'succeeded'])\nconst ERROR_STATUSES = new Set(['failed', 'error', 'cancelled', 'aborted'])\n\n/** Map a delegation status (free-form string on the wire) to a render tone. */\nexport function activityTone(status: string): ActivityTone {\n const s = status.toLowerCase()\n if (LIVE_STATUSES.has(s)) return 'live'\n if (OK_STATUSES.has(s)) return 'ok'\n if (ERROR_STATUSES.has(s)) return 'error'\n return 'neutral'\n}\n\n/** \"$0.4000\" under a cent shows 4 decimals; null when unknown/zero. */\nexport function formatActivityCost(costUsd?: number): string | null {\n if (costUsd === undefined || !isFinite(costUsd) || costUsd <= 0) return null\n return costUsd < 0.01 ? `$${costUsd.toFixed(4)}` : `$${costUsd.toFixed(2)}`\n}\n\n/** \"8s\" / \"2m 05s\" / \"1h 12m\"; null when unknown. */\nexport function formatActivityDuration(durationMs?: number): string | null {\n if (durationMs === undefined || !isFinite(durationMs) || durationMs < 0) return null\n const totalSeconds = Math.round(durationMs / 1000)\n if (totalSeconds < 60) return `${totalSeconds}s`\n const minutes = Math.floor(totalSeconds / 60)\n const seconds = totalSeconds % 60\n if (minutes < 60) return `${minutes}m ${String(seconds).padStart(2, '0')}s`\n return `${Math.floor(minutes / 60)}h ${String(minutes % 60).padStart(2, '0')}m`\n}\n\n/** A delegation record on the cross-context surface; `missionRef` links a\n * promoted delegation back to the mission/step that spawned it. */\nexport interface AgentActivityRecord extends StepAgentActivity {\n missionRef?: { missionId: string; stepId?: string; label?: string }\n}\n\nexport interface AgentActivityPage {\n items: AgentActivityRecord[]\n /** Opaque continuation token; absent ⇒ no further pages. */\n nextCursor?: string\n}\n\n/**\n * Fold a fetched page into the held rows: dedupe by `taskId` with the\n * incoming row winning (a refresh re-fetches the head page, so newer\n * snapshots of in-flight runs replace stale ones), newest `startedAt` first.\n */\nexport function mergeActivityPages(\n existing: AgentActivityRecord[],\n incoming: AgentActivityRecord[],\n): AgentActivityRecord[] {\n const byTask = new Map<string, AgentActivityRecord>()\n for (const row of existing) byTask.set(row.taskId, row)\n for (const row of incoming) byTask.set(row.taskId, row)\n return [...byTask.values()].sort((a, b) => Date.parse(b.startedAt) - Date.parse(a.startedAt))\n}\n\nexport interface WaterfallRow {\n name: string\n kind: 'pipeline' | 'model' | 'tool'\n /** Bar geometry as percentages of the trace's total span. */\n offsetPct: number\n widthPct: number\n durationLabel: string\n approx: boolean\n /** False only when the span's meta carries an explicit failure. */\n ok: boolean\n}\n\n/** Project a FlowTrace into proportional bar geometry for {@link FlowWaterfall}. */\nexport function waterfallLayout(trace: FlowTrace): WaterfallRow[] {\n const total = trace.totalMs > 0 ? trace.totalMs : 1\n return [...trace.spans]\n .sort((a, b) => a.startMs - b.startMs)\n .map((span) => {\n const meta = span.meta ?? {}\n const failed =\n meta.ok === false || (typeof meta.status === 'string' && activityTone(meta.status) === 'error')\n return {\n name: span.name,\n kind: span.kind,\n offsetPct: Math.max(0, Math.min(100, (span.startMs / total) * 100)),\n widthPct: Math.max(0.5, Math.min(100, ((span.endMs - span.startMs) / total) * 100)),\n durationLabel: `${((span.endMs - span.startMs) / 1000).toFixed(1)}s${span.approx ? '~' : ''}`,\n approx: span.approx === true,\n ok: !failed,\n }\n })\n}\n\n// ── glyphs ────────────────────────────────────────────────────────────────\n\nfunction ChevronGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\nfunction RefreshGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M21 12a9 9 0 1 1-2.64-6.36M21 3v6h-6\" />\n </svg>\n )\n}\n\nfunction CopyGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n )\n}\n\n/** Copy a trace id to the clipboard — the drill-in's actionable handle instead\n * of a bare, dead-end string. Falls back silently when the Clipboard API is\n * unavailable (insecure context / older browser). */\nfunction TraceIdCopy({ traceId }: { traceId: string }) {\n const [copied, setCopied] = useState(false)\n const copy = useCallback(() => {\n void navigator.clipboard?.writeText(traceId).then(\n () => {\n setCopied(true)\n setTimeout(() => setCopied(false), 1200)\n },\n () => {},\n )\n }, [traceId])\n return (\n <button\n type=\"button\"\n onClick={copy}\n title=\"Copy trace id\"\n aria-label=\"Copy trace id\"\n className=\"inline-flex min-w-0 items-center gap-1.5 rounded text-left font-mono text-muted-foreground transition hover:text-foreground\"\n >\n <span className=\"truncate\">{traceId}</span>\n <CopyGlyph className=\"h-3 w-3 shrink-0\" />\n {copied && <span className=\"shrink-0 not-italic text-success\">copied</span>}\n </button>\n )\n}\n\nfunction StatusDot({ tone }: { tone: ActivityTone }) {\n return (\n <span className=\"inline-flex items-center\">\n <span\n aria-hidden\n className={`h-2 w-2 shrink-0 rounded-full ${\n tone === 'live' ? 'animate-pulse bg-warning' : tone === 'ok' ? 'bg-success' : tone === 'error' ? 'bg-destructive' : 'bg-muted-foreground/40'\n }`}\n />\n <span className=\"sr-only\">{tone}</span>\n </span>\n )\n}\n\n// ── FlowWaterfall ─────────────────────────────────────────────────────────\n\nconst BAR_CLASS: Record<WaterfallRow['kind'], string> = {\n pipeline: 'bg-muted-foreground/30',\n model: 'bg-primary/60',\n tool: 'bg-primary',\n}\n\nexport interface FlowWaterfallProps {\n trace: FlowTrace\n}\n\n/** Compact proportional waterfall over a FlowTrace — span name, bar, duration\n * per row; total + cost in the footer. */\nexport function FlowWaterfall({ trace }: FlowWaterfallProps) {\n const rows = waterfallLayout(trace)\n if (rows.length === 0) return null\n const cost = formatActivityCost(trace.costUsd)\n return (\n <div className=\"space-y-1\">\n {rows.map((row, i) => (\n <div key={i} className=\"grid grid-cols-[minmax(0,2fr)_minmax(0,3fr)_auto] items-center gap-2\">\n <span className=\"truncate font-mono text-[11px] text-muted-foreground\" title={row.name}>\n {row.name}\n </span>\n <div className=\"relative h-2 rounded-sm bg-secondary\">\n <div\n className={`absolute inset-y-0 rounded-sm ${row.ok ? BAR_CLASS[row.kind] : 'bg-destructive/80'} ${row.approx ? 'opacity-70' : ''}`}\n style={{ left: `${row.offsetPct}%`, width: `${row.widthPct}%` }}\n />\n </div>\n <span className=\"shrink-0 font-mono text-[10px] tabular-nums text-muted-foreground/70\">{row.durationLabel}</span>\n </div>\n ))}\n <p className=\"pt-0.5 text-right font-mono text-[10px] tabular-nums text-muted-foreground/60\">\n {(trace.totalMs / 1000).toFixed(1)}s{cost ? ` · ${cost}` : ''}\n </p>\n </div>\n )\n}\n\n// ── MissionActivityLane ───────────────────────────────────────────────────\n\nexport interface MissionActivityLaneProps {\n /** The step's delegated-run snapshot (`MissionStepState.agentActivity`). */\n activity: StepAgentActivity[]\n /** Epoch ms origin for the expanded waterfall — usually the step start. */\n startedAt?: number\n /** Wall clock for extending in-flight runs on the waterfall. */\n nowMs?: number\n}\n\n/**\n * Collapsed sub-rows under a mission step — one row per delegated run —\n * expanding to the step's waterfall. Renders nothing for an empty lane.\n */\nexport function MissionActivityLane({ activity, startedAt, nowMs }: MissionActivityLaneProps) {\n const [expanded, setExpanded] = useState(false)\n if (activity.length === 0) return null\n\n return (\n <div className=\"mt-1 border-l border-border pl-3\">\n {activity.map((run) => {\n const tone = activityTone(run.status)\n const cost = formatActivityCost(run.costUsd)\n const duration = formatActivityDuration(run.durationMs)\n return (\n <div key={run.taskId} className=\"flex items-center gap-2 py-1 text-xs\">\n <StatusDot tone={tone} />\n <span className=\"min-w-0 flex-1 truncate\">\n <span className=\"font-medium\">{run.tool}</span>\n <span className=\"text-muted-foreground\"> — {run.detail}</span>\n </span>\n {tone === 'live' && (run.iteration !== undefined || run.phase !== undefined) && (\n <span className=\"shrink-0 rounded-full bg-warning/10 px-1.5 py-0.5 font-mono text-[10px] text-warning\">\n {[run.iteration !== undefined ? `iter ${run.iteration}` : null, run.phase ?? null]\n .filter(Boolean)\n .join(' · ')}\n </span>\n )}\n <span className=\"flex shrink-0 items-center gap-1.5 font-mono text-[10px] tabular-nums text-muted-foreground/70\">\n {tone !== 'live' && tone !== 'ok' && <span>{run.status}</span>}\n {cost && <span>{cost}</span>}\n {duration && <span>{duration}</span>}\n </span>\n </div>\n )\n })}\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"flex items-center gap-1 py-0.5 text-[10px] font-medium text-muted-foreground/70 transition hover:text-foreground\"\n >\n <ChevronGlyph className={`h-3 w-3 transition-transform ${expanded ? 'rotate-180' : ''}`} />\n timeline\n </button>\n {expanded && (\n <div className=\"rounded-md border border-border bg-secondary p-2\">\n <FlowWaterfall\n trace={stepActivityFlowTrace(activity, {\n ...(startedAt !== undefined ? { startedAt } : {}),\n ...(nowMs !== undefined ? { nowMs } : {}),\n })}\n />\n </div>\n )}\n </div>\n )\n}\n\n// ── AgentActivityPanel ────────────────────────────────────────────────────\n\nexport interface AgentActivityPanelProps {\n /** Data port — page through the product's delegation records. Called with\n * no cursor on mount/refresh, with `nextCursor` for older pages. */\n fetchActivity: (cursor?: string) => Promise<AgentActivityPage>\n /** Render the mission link for a promoted delegation (chip, anchor, router\n * Link — the product's routing, not ours). */\n renderMissionRef?: (ref: NonNullable<AgentActivityRecord['missionRef']>, record: AgentActivityRecord) => ReactNode\n title?: string\n emptyLabel?: string\n}\n\nfunction ActivityRow({\n record,\n renderMissionRef,\n}: {\n record: AgentActivityRecord\n renderMissionRef?: AgentActivityPanelProps['renderMissionRef']\n}) {\n const [open, setOpen] = useState(false)\n const tone = activityTone(record.status)\n const cost = formatActivityCost(record.costUsd)\n const duration = formatActivityDuration(record.durationMs)\n\n return (\n <div className=\"rounded-lg border border-card-edge bg-card\">\n <button type=\"button\" onClick={() => setOpen((v) => !v)} className=\"flex w-full items-center gap-2.5 px-3 py-2 text-left text-sm\">\n <StatusDot tone={tone} />\n <span className=\"min-w-0 flex-1 truncate\">\n <span className=\"font-medium\">{record.tool}</span>\n <span className=\"text-muted-foreground\"> — {record.detail}</span>\n </span>\n {tone === 'live' && (record.iteration !== undefined || record.phase !== undefined) && (\n <span className=\"shrink-0 rounded-full bg-warning/10 px-2 py-0.5 font-mono text-[10px] text-warning\">\n {[record.iteration !== undefined ? `iter ${record.iteration}` : null, record.phase ?? null]\n .filter(Boolean)\n .join(' · ')}\n </span>\n )}\n <span\n className={`shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium ${\n tone === 'ok'\n ? 'bg-success/10 text-success'\n : tone === 'error'\n ? 'bg-destructive/10 text-destructive'\n : tone === 'live'\n ? 'bg-warning/10 text-warning'\n : 'bg-secondary text-muted-foreground'\n }`}\n >\n {record.status}\n </span>\n {cost && <span className=\"shrink-0 font-mono text-[11px] tabular-nums text-muted-foreground\">{cost}</span>}\n <ChevronGlyph className={`h-3 w-3 shrink-0 text-muted-foreground transition-transform ${open ? 'rotate-180' : ''}`} />\n </button>\n {open && (\n <div className=\"space-y-2.5 border-t border-border px-3 py-2.5\">\n {record.durationMs !== undefined && (\n <div className=\"rounded-md border border-border bg-secondary p-2\">\n <FlowWaterfall trace={stepActivityFlowTrace([record])} />\n </div>\n )}\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 font-mono text-[11px]\">\n <dt className=\"text-muted-foreground/60\">task</dt>\n <dd className=\"truncate text-muted-foreground\">{record.taskId}</dd>\n <dt className=\"text-muted-foreground/60\">started</dt>\n <dd className=\"text-muted-foreground\">{new Date(record.startedAt).toLocaleString()}</dd>\n {duration && (\n <>\n <dt className=\"text-muted-foreground/60\">duration</dt>\n <dd className=\"text-muted-foreground\">{duration}</dd>\n </>\n )}\n {record.traceId && (\n <>\n <dt className=\"text-muted-foreground/60\">trace</dt>\n <dd className=\"min-w-0\">\n <TraceIdCopy traceId={record.traceId} />\n </dd>\n </>\n )}\n </dl>\n {record.missionRef && renderMissionRef?.(record.missionRef, record)}\n </div>\n )}\n </div>\n )\n}\n\n/**\n * The standalone cross-context delegation surface: every agent run the\n * product journaled, mission-spawned or not, with status, cost, drill-in, and\n * a mission link slot for promoted delegations.\n */\n/**\n * `loading`/`error` collapsed onto one status rather than two independent\n * booleans, so \"loading and errored at once\" is unrepresentable instead of\n * merely avoided by careful set-ordering — the same discipline\n * `web-react/async`'s `AsyncResourceState` enforces for a single fetch.\n * `rows`/`cursor` stay separate state because they ACCUMULATE across pages,\n * which a single-resolution status can't express — this is a cursor-paged\n * panel (`useSessionHistory`'s shape), not a one-shot resource.\n */\ntype AgentActivityStatus = 'loading' | 'error' | 'ready'\n\nexport function AgentActivityPanel({ fetchActivity, renderMissionRef, title = 'Agent activity', emptyLabel = 'No agent runs yet.' }: AgentActivityPanelProps) {\n const [rows, setRows] = useState<AgentActivityRecord[]>([])\n const [cursor, setCursor] = useState<string | undefined>(undefined)\n const [status, setStatus] = useState<AgentActivityStatus>('loading')\n const [error, setError] = useState<string | null>(null)\n\n const load = useCallback(\n async (from?: string) => {\n setStatus('loading')\n setError(null)\n try {\n const page = await fetchActivity(from)\n setRows((prev) => mergeActivityPages(from === undefined ? [] : prev, page.items))\n setCursor(page.nextCursor)\n setStatus('ready')\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n setStatus('error')\n }\n },\n [fetchActivity],\n )\n\n useEffect(() => {\n void load()\n }, [load])\n\n const loading = status === 'loading'\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"flex-1 text-sm font-semibold\">{title}</h2>\n <button\n type=\"button\"\n onClick={() => void load()}\n disabled={loading}\n aria-label=\"Refresh\"\n className=\"rounded-md p-1.5 text-muted-foreground transition hover:bg-accent hover:text-foreground disabled:opacity-50\"\n >\n <RefreshGlyph className={`h-3.5 w-3.5 ${loading ? 'animate-spin' : ''}`} />\n </button>\n </div>\n {status === 'error' && (\n <p role=\"alert\" className=\"rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-xs text-destructive\">\n {error}\n </p>\n )}\n {status === 'ready' && rows.length === 0 && <p className=\"px-1 text-sm text-muted-foreground\">{emptyLabel}</p>}\n {/* While `loading` the list is empty AND the empty copy is suppressed, so\n without this the panel is silent to a screen reader from first paint\n until rows land. The region stays MOUNTED and its text changes, because\n a live region that is inserted already carrying its message is not\n reliably announced — and emptying it on arrival is what reports the\n wait ending. */}\n <span role=\"status\" aria-live=\"polite\" aria-busy={loading} className=\"sr-only\">\n {loading ? 'Loading activity…' : ''}\n </span>\n <div className=\"space-y-1.5\" aria-busy={loading}>\n {rows.map((record) => (\n <ActivityRow key={record.taskId} record={record} renderMissionRef={renderMissionRef} />\n ))}\n </div>\n {cursor && (\n <button\n type=\"button\"\n onClick={() => void load(cursor)}\n disabled={loading}\n className=\"w-full rounded-md border border-border bg-card px-3 py-1.5 text-xs font-medium text-muted-foreground transition hover:bg-accent disabled:opacity-50\"\n >\n Older runs\n </button>\n )}\n </div>\n )\n}\n","/**\n * `ProvenanceValue` — one value rendered so its origin is discoverable without\n * navigating away, and openable when there is something to open.\n *\n * This is the affordance three verticals each rebuilt: tax renders a source\n * quote under an expanded return line, legal renders authorities under a\n * finding, the record grid renders a per-cell marker. Same product promise,\n * three vocabularies, three sets of gaps.\n *\n * What the primitive holds that a hand-rolled caption does not:\n *\n * 1. The four bases render differently — a person's entry and a model's\n * assertion are never the same pixels. Each carries its own glyph AND its\n * own words, so the distinction survives greyscale and a screen reader.\n * 2. It COMPOSES. A computed value's provenance is its inputs, and each input\n * is itself a `ProvenanceValue` with its own disclosure.\n * 3. Confidence renders as the next move (\"Check the source\"), never as a\n * percentage a reader cannot act on.\n * 4. The disclosure is a real button — keyboard reachable, `aria-expanded`,\n * Escape closes and returns focus, a click outside dismisses, and opening\n * one trail closes the one the reader left. Nothing here discloses on hover,\n * and no fact lives only in a `title` attribute.\n * 5. A source that is loading, unopenable, or absent SAYS so. There is no path\n * through this component that renders a bare number.\n *\n * Layout: an inline-block block-level element, so put it in a table cell, a\n * list item, or a card — not inside a `<p>`. Sandbox-ui-free, like the rest of\n * `/web-react`; the model in `./provenance-model` is React-free.\n */\n\nimport { useCallback, useEffect, useId, useRef, useState, type KeyboardEvent, type ReactNode } from 'react'\n\nimport {\n describeProvenance,\n describeProvenanceSourceStatus,\n loadingProvenanceSources,\n provenanceBasisMeta,\n provenanceGaps,\n provenanceNextMove,\n provenanceStandingMeta,\n provenanceTriggerLabel,\n rollUpProvenanceStanding,\n type ProvenanceBasis,\n type ProvenanceConfidencePolicy,\n type ProvenanceRecord,\n type ProvenanceSource,\n type ProvenanceStanding,\n} from './provenance-model'\n\nexport * from './provenance-model'\n\n// ── marker vocabulary ─────────────────────────────────────────────────────\n\n// Tone AND glyph differ per basis. Colour alone fails the reader who cannot\n// see it and the one whose theme flattens it; the words in\n// `provenanceBasisMeta` carry the same distinction a third time.\nconst BASIS_TONES: Record<ProvenanceBasis, string> = {\n extracted: 'border-primary/30 bg-primary/10 text-primary',\n entered: 'border-success/30 bg-success/10 text-success',\n computed: 'border-border bg-secondary text-foreground',\n asserted: 'border-warning/40 bg-warning/10 text-warning',\n}\n\nconst STANDING_TONES: Record<ProvenanceStanding, string> = {\n settled: 'text-muted-foreground',\n check: 'text-warning',\n confirm: 'text-destructive',\n}\n\nfunction BasisGlyph({ basis, className }: { basis: ProvenanceBasis; className?: string }) {\n const shared = {\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 2,\n strokeLinecap: 'round' as const,\n strokeLinejoin: 'round' as const,\n 'aria-hidden': true,\n className,\n }\n switch (basis) {\n case 'extracted':\n return (\n <svg {...shared}>\n <path d=\"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 3 14 8 19 8\" />\n <line x1=\"9\" y1=\"13\" x2=\"15\" y2=\"13\" />\n </svg>\n )\n case 'entered':\n return (\n <svg {...shared}>\n <path d=\"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2\" />\n <circle cx=\"12\" cy=\"7\" r=\"4\" />\n </svg>\n )\n case 'computed':\n return (\n <svg {...shared}>\n <line x1=\"4\" y1=\"9\" x2=\"20\" y2=\"9\" />\n <line x1=\"4\" y1=\"15\" x2=\"20\" y2=\"15\" />\n <line x1=\"10\" y1=\"3\" x2=\"8\" y2=\"21\" />\n <line x1=\"16\" y1=\"3\" x2=\"14\" y2=\"21\" />\n </svg>\n )\n case 'asserted':\n return (\n <svg {...shared}>\n <path d=\"M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M18.4 5.6l-2.1 2.1M7.7 16.3l-2.1 2.1\" />\n <circle cx=\"12\" cy=\"12\" r=\"3.2\" />\n </svg>\n )\n }\n}\n\n// ── open panels ───────────────────────────────────────────────────────────\n\ninterface OpenPanel {\n root: HTMLElement\n close: () => void\n}\n\n// Two trails open beside each other leave the reader matching a quote to a\n// number by position, which is the failure a marker adjacent to its own value\n// exists to remove.\nconst openPanels = new Set<OpenPanel>()\n\n/**\n * Close every open trail this one does not sit INSIDE. A composed input's panel\n * is nested in its parent's, so closing \"everything else\" would close the row\n * the reader just drilled into — an ancestor stays open.\n *\n * Only a reader opening a trail closes another one. A `defaultOpen` surface has\n * deliberately asked for several trails at once, and mount order is not a\n * decision anyone made.\n */\nfunction closeTrailsOutside(root: HTMLElement | null): void {\n for (const other of Array.from(openPanels)) {\n if (root === null || !other.root.contains(root)) other.close()\n }\n}\n\n// ── props ─────────────────────────────────────────────────────────────────\n\n/** Properties for one provenanced value and its disclosure. */\nexport interface ProvenanceValueProps {\n /** The value and where it came from. */\n record: ProvenanceRecord\n /**\n * Open one source in the product's own way (a document pane at the right\n * page, a drawer, a route). Takes precedence over `href` when both are\n * present, because a product that routes wants its router — a source with\n * neither is named but not openable, which is a legitimate state and is\n * rendered as such.\n */\n onOpenSource?: (source: ProvenanceSource, record: ProvenanceRecord) => void\n /** Retry resolving an `unavailable` source. Absent → the failure is stated\n * without a retry control, never swallowed. */\n onRetrySource?: (source: ProvenanceSource, record: ProvenanceRecord) => void\n /** Where this product draws its confidence lines. */\n confidencePolicy?: ProvenanceConfidencePolicy\n /**\n * How many levels of composed inputs stay expandable. Past it an input still\n * renders its value, its basis and its origin sentence — it just stops\n * carrying its own disclosure, so a deep tree cannot run away and a record\n * that reaches itself cannot recurse forever. Default 2.\n */\n maxDepth?: number\n /** Open the disclosure on first render — for a review surface where the\n * trail is the point. Several of these coexist: only a reader opening a\n * trail closes another one. */\n defaultOpen?: boolean\n /** What an empty `display` renders as. A blank cell is the defect this\n * component exists to remove. */\n missingValueLabel?: string\n className?: string\n}\n\nconst DEFAULT_MISSING_VALUE_LABEL = 'No value recorded'\n\n// ── source rows ───────────────────────────────────────────────────────────\n\nfunction SourceRow({\n source,\n record,\n onOpenSource,\n onRetrySource,\n}: {\n source: ProvenanceSource\n record: ProvenanceRecord\n onOpenSource?: (source: ProvenanceSource, record: ProvenanceRecord) => void\n onRetrySource?: (source: ProvenanceSource, record: ProvenanceRecord) => void\n}) {\n const status = source.status ?? 'ready'\n const statusLine = describeProvenanceSourceStatus(source)\n const openable = status === 'ready' && (onOpenSource !== undefined || source.href !== undefined)\n\n return (\n <li className=\"rounded-md border border-card-edge bg-card px-2.5 py-2\">\n <div className=\"flex flex-wrap items-baseline gap-x-2 gap-y-1\">\n <span className=\"text-[13px] font-medium text-foreground\">{source.label}</span>\n {source.locator && <span className=\"text-[11px] text-muted-foreground\">{source.locator}</span>}\n {openable &&\n (onOpenSource ? (\n <button\n type=\"button\"\n onClick={() => onOpenSource(source, record)}\n className=\"rounded px-1 text-[11px] font-medium text-primary underline-offset-2 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n Open {source.label}\n </button>\n ) : (\n <a\n href={source.href}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"rounded px-1 text-[11px] font-medium text-primary underline-offset-2 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n Open {source.label}\n </a>\n ))}\n </div>\n {source.quote && (\n <blockquote className=\"mt-1 border-l-2 border-primary/50 pl-2 text-[12px] italic leading-snug text-foreground\">\n “{source.quote}”\n </blockquote>\n )}\n {statusLine && (\n // `role=\"status\"` and not `alert`: the reader opened this panel, so the\n // update is theirs to read, not an interruption. Either way it is TEXT\n // — a spinner alone and a greyed row alone both render as \"nothing\n // here\".\n <p\n role=\"status\"\n className={`mt-1 text-[11px] ${status === 'unavailable' ? 'text-destructive' : 'text-muted-foreground'}`}\n >\n {statusLine}\n {status === 'unavailable' && onRetrySource && (\n <button\n type=\"button\"\n onClick={() => onRetrySource(source, record)}\n className=\"ml-2 rounded border border-border px-1.5 py-0.5 text-[11px] font-medium text-foreground hover:bg-accent focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n Try again\n </button>\n )}\n </p>\n )}\n </li>\n )\n}\n\n// ── the value ─────────────────────────────────────────────────────────────\n\n/**\n * A value, its origin marker, and the disclosure that shows where it came\n * from. The marker states the basis in words and, whenever there is something\n * to do about the value, the next move — so the standing is legible at rest\n * and does not depend on anyone opening the panel.\n */\nexport function ProvenanceValue({\n record,\n onOpenSource,\n onRetrySource,\n confidencePolicy,\n maxDepth = 2,\n defaultOpen = false,\n missingValueLabel = DEFAULT_MISSING_VALUE_LABEL,\n className,\n}: ProvenanceValueProps) {\n const [open, setOpen] = useState(defaultOpen)\n const triggerRef = useRef<HTMLButtonElement | null>(null)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const panelId = useId()\n\n const standing = rollUpProvenanceStanding(record, confidencePolicy)\n const basisMeta = provenanceBasisMeta(record.basis)\n const standingMeta = provenanceStandingMeta(standing)\n const gaps = provenanceGaps(record)\n const loading = loadingProvenanceSources(record)\n const sources = record.sources ?? []\n const inputs = record.inputs ?? []\n const hasValue = record.display.trim() !== ''\n\n // Escape closes the value the focus is inside and hands focus back to its own\n // trigger; `stopPropagation` keeps a nested input from also closing the\n // parent that contains it.\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key !== 'Escape' || !open) return\n event.stopPropagation()\n setOpen(false)\n triggerRef.current?.focus()\n },\n [open],\n )\n\n // Opening is a reader's decision, so it is the one moment another trail is\n // closed — see `closeTrailsOutside`.\n const onToggle = useCallback(() => {\n if (!open) closeTrailsOutside(rootRef.current)\n setOpen(!open)\n }, [open])\n\n // A click landing anywhere else dismisses the trail. Registered in the\n // capture phase so a product's own click handler under the pointer cannot\n // swallow it, and paired with the registry above so the two dismissals agree.\n useEffect(() => {\n const root = rootRef.current\n if (!open || root === null) return\n\n const entry: OpenPanel = { root, close: () => setOpen(false) }\n openPanels.add(entry)\n\n const onPointerDown = (event: Event) => {\n const target = event.target\n if (target instanceof Node && root.contains(target)) return\n setOpen(false)\n }\n document.addEventListener('mousedown', onPointerDown, true)\n document.addEventListener('touchstart', onPointerDown, true)\n\n return () => {\n openPanels.delete(entry)\n document.removeEventListener('mousedown', onPointerDown, true)\n document.removeEventListener('touchstart', onPointerDown, true)\n }\n }, [open])\n\n const summary: ReactNode = (\n <span className=\"inline-flex flex-wrap items-baseline gap-x-1.5\">\n {record.label && <span className=\"text-[11px] text-muted-foreground\">{record.label}</span>}\n <span className={hasValue ? 'text-sm text-foreground' : 'text-sm italic text-muted-foreground'}>\n {hasValue ? record.display : missingValueLabel}\n </span>\n </span>\n )\n\n // Depth exhausted: still the value, still the basis, still the origin\n // sentence — only the disclosure goes. A truncated tree must not silently\n // become a bare number.\n if (maxDepth <= 0) {\n return (\n <div\n className={`inline-block max-w-full ${className ?? ''}`}\n data-provenance-basis={record.basis}\n data-provenance-standing={standing}\n >\n {summary}\n <span\n className={`ml-1.5 inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium ${BASIS_TONES[record.basis]}`}\n >\n <BasisGlyph basis={record.basis} className=\"h-3 w-3\" />\n {basisMeta.label}\n </span>\n <span className=\"mt-0.5 block text-[11px] text-muted-foreground\">{describeProvenance(record)}</span>\n </div>\n )\n }\n\n return (\n <div\n ref={rootRef}\n className={`inline-block max-w-full ${className ?? ''}`}\n onKeyDown={onKeyDown}\n data-provenance-basis={record.basis}\n data-provenance-standing={standing}\n >\n <span className=\"inline-flex flex-wrap items-baseline gap-1.5\">\n {summary}\n <button\n ref={triggerRef}\n type=\"button\"\n onClick={onToggle}\n aria-expanded={open}\n aria-controls={panelId}\n aria-label={provenanceTriggerLabel(record, standing)}\n className={`inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition hover:brightness-105 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring ${BASIS_TONES[record.basis]}`}\n >\n <BasisGlyph basis={record.basis} className=\"h-3 w-3\" />\n <span aria-hidden>{basisMeta.label}</span>\n </button>\n {standing !== 'settled' && (\n // Legible at rest: what to do about the value does not wait for\n // someone to open the panel. `aria-hidden` because the trigger's\n // accessible name already carries it — this is the visual half.\n <span aria-hidden className={`text-[10px] font-medium ${STANDING_TONES[standing]}`}>\n {standingMeta.label}\n </span>\n )}\n </span>\n\n {open && (\n <div\n id={panelId}\n role=\"group\"\n aria-label={provenanceTriggerLabel(record, standing)}\n className=\"mt-1.5 w-full min-w-0 space-y-2 rounded-lg border border-border bg-card px-3 py-2.5 text-left\"\n >\n <div>\n <p className=\"text-[12px] leading-snug text-foreground\">{describeProvenance(record)}</p>\n <p className={`mt-0.5 text-[11px] leading-snug ${STANDING_TONES[standing]}`}>\n {standingMeta.label} — {provenanceNextMove(record, standing, confidencePolicy)}\n </p>\n {basisMeta.checkableAgainst === null && (\n <p className=\"mt-0.5 text-[11px] leading-snug text-muted-foreground\">\n {basisMeta.meaning} There is nothing outside the model to check it against.\n </p>\n )}\n </div>\n\n {sources.length > 0 && (\n <ul className=\"space-y-1.5\">\n {sources.map((source, index) => (\n <SourceRow\n key={`${source.label}-${source.locator ?? ''}-${index}`}\n source={source}\n record={record}\n onOpenSource={onOpenSource}\n onRetrySource={onRetrySource}\n />\n ))}\n </ul>\n )}\n\n {gaps\n .filter((gap) => gap.kind !== 'unavailable-source')\n .map((gap) => (\n // An unavailable source already states itself on its own row; a\n // structural gap has no row to state it, so it gets one here.\n <p key={gap.kind} className=\"rounded-md bg-destructive/10 px-2 py-1.5 text-[11px] leading-snug text-destructive\">\n {gap.message}\n </p>\n ))}\n\n {loading.length > 0 && sources.length === 0 && (\n <p role=\"status\" className=\"text-[11px] text-muted-foreground\">\n Looking up where this came from…\n </p>\n )}\n\n {inputs.length > 0 && (\n <div className=\"border-t border-border pt-2\">\n <p className=\"text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {record.derivation ? `Computed from ${record.derivation}` : 'Computed from'}\n </p>\n <ul className=\"mt-1.5 space-y-1.5\">\n {inputs.map((input, index) => (\n <li key={`${input.label ?? input.display}-${index}`}>\n <ProvenanceValue\n record={input}\n onOpenSource={onOpenSource}\n onRetrySource={onRetrySource}\n confidencePolicy={confidencePolicy}\n maxDepth={maxDepth - 1}\n missingValueLabel={missingValueLabel}\n />\n </li>\n ))}\n </ul>\n </div>\n )}\n </div>\n )}\n </div>\n )\n}\n\n/** Properties for the basis legend. */\nexport interface ProvenanceLegendProps {\n /** Only the bases present on screen. Passing all four when only two appear\n * teaches distinctions the reader cannot use. */\n bases: readonly ProvenanceBasis[]\n className?: string\n}\n\n/** The marker key for a surface that renders several bases at once — a review\n * pane, a grid, a return. Each row is the same glyph, tone and words the\n * markers use, plus what the basis MEANS. */\nexport function ProvenanceLegend({ bases, className }: ProvenanceLegendProps) {\n if (bases.length === 0) return null\n return (\n <ul className={`flex flex-wrap items-center gap-x-3 gap-y-1.5 ${className ?? ''}`}>\n {bases.map((basis) => {\n const meta = provenanceBasisMeta(basis)\n return (\n <li key={basis} className=\"flex items-center gap-1.5 text-[11px] text-muted-foreground\">\n <span\n className={`inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium ${BASIS_TONES[basis]}`}\n >\n <BasisGlyph basis={basis} className=\"h-3 w-3\" />\n {meta.label}\n </span>\n <span>{meta.meaning}</span>\n </li>\n )\n })}\n </ul>\n )\n}\n","/**\n * The pure half of the provenance affordance: what kind of claim a value is,\n * what a reader should DO about it, and what has to be SAID when its origin\n * cannot be shown.\n *\n * Zero React, zero DOM — a loader or a worker can decide a value's standing\n * before it reaches a screen, and `./provenance`'s `ProvenanceValue` renders\n * exactly what these functions decide.\n *\n * The distinction the module exists to hold: a person typing a number, a\n * document carrying it, a formula producing it, and a model claiming it are\n * four different kinds of evidence. Rendered as one grey caption they are\n * indistinguishable, which is how an unverified model assertion reads to a\n * reviewer as a transcribed fact.\n *\n * Every domain word is a caller parameter: no field names, no document kinds,\n * and no confidence policy beyond a default the product overrides.\n */\n\n/**\n * How a value came to exist. Four kinds, never interchangeable:\n *\n * - `extracted` — read out of a document or message the product can open.\n * - `entered` — a person typed or confirmed it.\n * - `computed` — produced from other values, each carrying its own provenance.\n * - `asserted` — the agent stated it, with nothing outside the model behind it.\n */\nexport type ProvenanceBasis = 'extracted' | 'entered' | 'computed' | 'asserted'\n\n/** Every basis, in the order a legend should list them. */\nexport const PROVENANCE_BASES: readonly ProvenanceBasis[] = ['extracted', 'entered', 'computed', 'asserted']\n\n/** The words one basis is rendered and announced with. */\nexport interface ProvenanceBasisMeta {\n /** Marker text next to the value — short, and never only a colour. */\n label: string\n /** One plain sentence naming what kind of claim this is. */\n meaning: string\n /** What a reader can hold the value against, or `null` when nothing outside\n * the model can. `null` is what makes an `asserted` value uncertifiable at\n * any confidence. */\n checkableAgainst: string | null\n}\n\nconst BASIS_META: Record<ProvenanceBasis, ProvenanceBasisMeta> = {\n extracted: {\n label: 'From document',\n meaning: 'Read out of a source document.',\n checkableAgainst: 'the document it was read from',\n },\n entered: {\n label: 'Entered by a person',\n meaning: 'A person typed or confirmed this value.',\n checkableAgainst: 'the person who entered it',\n },\n computed: {\n label: 'Computed',\n meaning: 'Produced from other values.',\n checkableAgainst: 'the values it was computed from',\n },\n asserted: {\n label: 'Agent, unverified',\n meaning: 'The agent stated this. No source was recorded behind it.',\n checkableAgainst: null,\n },\n}\n\n/** Words for one basis. */\nexport function provenanceBasisMeta(basis: ProvenanceBasis): ProvenanceBasisMeta {\n return BASIS_META[basis]\n}\n\n/** Whether a source could be resolved. `ready` is the default for a source that\n * says nothing. */\nexport type ProvenanceSourceStatus = 'ready' | 'loading' | 'unavailable'\n\n/** One thing a value came from. A `label` is mandatory because an unnamed\n * source is the same as no source. */\nexport interface ProvenanceSource {\n /** What the source IS, in the reader's words: \"Form W-2 (Acme Corp)\",\n * \"Dana Whitfield\", \"Engagement letter\". */\n label: string\n /** The text in the source that carries the value. */\n quote?: string\n /** Position inside the source — a page, a line, a span, a timestamp. The\n * caller's words; nothing here parses it. */\n locator?: string\n /** Click-through target. Absent → the source is named but not openable. */\n href?: string\n /** Defaults to `ready`. */\n status?: ProvenanceSourceStatus\n /** Why an `unavailable` source cannot be opened, in one sentence. */\n unavailableReason?: string\n}\n\n/**\n * What the reader should DO about a value — the only form confidence takes on\n * screen. \"89% confidence\" names no next move; these three do.\n *\n * - `settled` — nothing to do.\n * - `check` — open the source and confirm before relying on it.\n * - `confirm` — a person has to confirm the value before it is used.\n */\nexport type ProvenanceStanding = 'settled' | 'check' | 'confirm'\n\n/** The words one standing is rendered and announced with. */\nexport interface ProvenanceStandingMeta {\n /** Short state label. */\n label: string\n /** The next move, as a sentence a person can follow. */\n action: string\n}\n\nconst STANDING_META: Record<ProvenanceStanding, ProvenanceStandingMeta> = {\n settled: { label: 'Traced', action: 'Nothing to check — this value can be traced to where it came from.' },\n check: { label: 'Check the source', action: 'Open the source and confirm this value before you rely on it.' },\n confirm: { label: 'Needs a person', action: 'Someone has to confirm this value before it is used.' },\n}\n\n/** Words for one standing. */\nexport function provenanceStandingMeta(standing: ProvenanceStanding): ProvenanceStandingMeta {\n return STANDING_META[standing]\n}\n\nconst STANDING_SEVERITY: Record<ProvenanceStanding, number> = { settled: 0, check: 1, confirm: 2 }\n\n/** The weaker of two standings — `confirm` beats `check` beats `settled`. */\nexport function weakerProvenanceStanding(a: ProvenanceStanding, b: ProvenanceStanding): ProvenanceStanding {\n return STANDING_SEVERITY[a] >= STANDING_SEVERITY[b] ? a : b\n}\n\n/**\n * Where a product draws its confidence lines. These are a POLICY, not a truth:\n * a number a model reports about itself means different things per surface, so\n * the thresholds are a parameter and the number itself never reaches the screen.\n */\nexport interface ProvenanceConfidencePolicy {\n /** At or above this, a value is `settled`. */\n settledAtOrAbove: number\n /** At or above this (and below `settledAtOrAbove`), a value is `check`.\n * Below it, `confirm`. */\n checkAtOrAbove: number\n}\n\n/** The starting policy. Products with a different tolerance pass their own. */\nexport const DEFAULT_PROVENANCE_CONFIDENCE_POLICY: ProvenanceConfidencePolicy = {\n settledAtOrAbove: 0.9,\n checkAtOrAbove: 0.6,\n}\n\n/** A value, where it came from, and — when it was computed — the provenanced\n * values it came from. The `inputs` field is what makes the shape compose:\n * a computed value's provenance IS its inputs. */\nexport interface ProvenanceRecord {\n /** The value as the reader should see it, already formatted. An empty string\n * is a missing value and renders as one, never as blank space. */\n display: string\n /** What the value IS (\"Wages\", \"Filing deadline\"). Optional at the top level,\n * where the surface around it usually says; rendered for every composed\n * input, where nothing else names them. */\n label?: string\n basis: ProvenanceBasis\n /** Where it came from. An `extracted` value without one is a gap, not a\n * detail. */\n sources?: readonly ProvenanceSource[]\n /** The provenanced values a `computed` value was produced from. */\n inputs?: readonly ProvenanceRecord[]\n /** How the inputs combine, in the caller's words (\"wages + interest\"). */\n derivation?: string\n /** 0–1. Never rendered as a number — it selects a standing. */\n confidence?: number\n /** Overrides the standing confidence and basis would produce — a reviewer\n * approved it, a gate failed. It can only make a value WEAKER: the\n * structural floors below still apply, so a product cannot mark a value\n * settled that has no origin on file. */\n standing?: ProvenanceStanding\n}\n\n/** The standing a bare confidence maps to under a policy. */\nexport function standingFromConfidence(\n confidence: number,\n policy: ProvenanceConfidencePolicy = DEFAULT_PROVENANCE_CONFIDENCE_POLICY,\n): ProvenanceStanding {\n if (confidence >= policy.settledAtOrAbove) return 'settled'\n if (confidence >= policy.checkAtOrAbove) return 'check'\n return 'confirm'\n}\n\n/** The standing a basis implies before any confidence or gap is considered. */\nfunction standingFromBasis(basis: ProvenanceBasis): ProvenanceStanding {\n // Only `asserted` starts weak: the other three name something outside the\n // model — a document, a person, a computation — that a reader can go check.\n return basis === 'asserted' ? 'check' : 'settled'\n}\n\n/** Something missing that the reader has to be TOLD about, because the value\n * renders either way and a bare number reads as a fact. */\nexport type ProvenanceGapKind = 'no-source' | 'no-inputs' | 'unavailable-source'\n\n/** One stated gap. `message` is rendered verbatim. */\nexport interface ProvenanceGap {\n kind: ProvenanceGapKind\n message: string\n /** The source that could not be resolved (`unavailable-source` only). */\n source?: ProvenanceSource\n}\n\n/** The sentence for a source that is not `ready`, or `null` when it is. One\n * source of this copy, so the row and the gap list never disagree. */\nexport function describeProvenanceSourceStatus(source: ProvenanceSource): string | null {\n if (source.status === 'loading') return `Looking up ${source.label}…`\n if (source.status === 'unavailable') {\n return source.unavailableReason\n ? `${source.label} could not be opened — ${source.unavailableReason}`\n : `${source.label} could not be opened.`\n }\n return null\n}\n\n/**\n * What this record cannot show, at its own level. Inputs are not walked: every\n * composed input renders its own gaps next to its own value, where a reader can\n * act on them.\n */\nexport function provenanceGaps(record: ProvenanceRecord): ProvenanceGap[] {\n const gaps: ProvenanceGap[] = []\n const sources = record.sources ?? []\n if (record.basis === 'extracted' && sources.length === 0) {\n gaps.push({\n kind: 'no-source',\n message: 'Read from a document, but no document is on file — nothing here shows where this came from.',\n })\n }\n if (record.basis === 'computed' && (record.inputs ?? []).length === 0) {\n gaps.push({\n kind: 'no-inputs',\n message: 'Computed, but the values it was computed from are not recorded.',\n })\n }\n for (const source of sources) {\n if (source.status !== 'unavailable') continue\n gaps.push({\n kind: 'unavailable-source',\n message: describeProvenanceSourceStatus(source) ?? `${source.label} could not be opened.`,\n source,\n })\n }\n return gaps\n}\n\n/** The sources still resolving — rendered as their own state, never as an\n * absence. A load in flight is not a missing source. */\nexport function loadingProvenanceSources(record: ProvenanceRecord): ProvenanceSource[] {\n return (record.sources ?? []).filter((source) => source.status === 'loading')\n}\n\n/**\n * This record's own standing, ignoring its inputs.\n *\n * The order is: start from the explicit standing, else from confidence, else\n * from the basis — then apply every structural floor, taking the WEAKEST. The\n * floors are what a caller cannot talk its way out of:\n *\n * - an `asserted` value never reaches `settled` (a model's own confidence\n * cannot certify the model's claim — there is nothing to check it against),\n * - a `no-source` / `no-inputs` gap forces `confirm` (a value dressed as\n * evidence with no evidence behind it is worse than an open guess),\n * - an unopenable source forces `check` (the value may be right; the reader\n * just cannot confirm it).\n */\nexport function resolveProvenanceStanding(\n record: ProvenanceRecord,\n policy: ProvenanceConfidencePolicy = DEFAULT_PROVENANCE_CONFIDENCE_POLICY,\n): ProvenanceStanding {\n let standing =\n record.standing ??\n (record.confidence === undefined ? standingFromBasis(record.basis) : standingFromConfidence(record.confidence, policy))\n\n if (record.basis === 'asserted') standing = weakerProvenanceStanding(standing, 'check')\n for (const gap of provenanceGaps(record)) {\n standing = weakerProvenanceStanding(standing, gap.kind === 'unavailable-source' ? 'check' : 'confirm')\n }\n return standing\n}\n\n/**\n * The standing a reader should see: this record's own, weakened by every value\n * it was computed from, however deep.\n *\n * A total is only as trustworthy as the weakest number in it. Rendering the\n * parent's own standing instead is how an exact sum of one document figure and\n * one model guess presents as traced.\n *\n * Cycle-safe: a record reachable from itself is counted once.\n */\nexport function rollUpProvenanceStanding(\n record: ProvenanceRecord,\n policy: ProvenanceConfidencePolicy = DEFAULT_PROVENANCE_CONFIDENCE_POLICY,\n seen: Set<ProvenanceRecord> = new Set(),\n): ProvenanceStanding {\n if (seen.has(record)) return 'settled'\n seen.add(record)\n let standing = resolveProvenanceStanding(record, policy)\n for (const input of record.inputs ?? []) {\n standing = weakerProvenanceStanding(standing, rollUpProvenanceStanding(input, policy, seen))\n }\n return standing\n}\n\nfunction sourcePhrase(source: ProvenanceSource): string {\n return source.locator ? `${source.label}, ${source.locator}` : source.label\n}\n\nfunction inputPhrase(input: ProvenanceRecord): string {\n return input.label ?? input.display\n}\n\n/**\n * One plain sentence naming where the value came from — the panel's first line\n * and part of what a screen reader announces. It states the absence when there\n * is one, so no code path produces silence.\n */\nexport function describeProvenance(record: ProvenanceRecord): string {\n const sources = record.sources ?? []\n const first = sources[0]\n const more = sources.length > 1 ? ` and ${sources.length - 1} more source${sources.length > 2 ? 's' : ''}` : ''\n\n switch (record.basis) {\n case 'extracted':\n return first ? `Read from ${sourcePhrase(first)}${more}.` : 'Read from a document, but no document is on file.'\n case 'entered':\n return first ? `Entered by ${sourcePhrase(first)}.` : 'Entered by a person.'\n case 'computed': {\n const inputs = record.inputs ?? []\n if (record.derivation) return `Computed from ${record.derivation}.`\n if (inputs.length === 0) return 'Computed, but the values it was computed from are not recorded.'\n return `Computed from ${inputs.map(inputPhrase).join(', ')}.`\n }\n case 'asserted':\n return first\n ? `Stated by the agent, pointing at ${sourcePhrase(first)} — not verified against it.`\n : 'Stated by the agent, with no source to check it against.'\n }\n}\n\n/**\n * The move THIS value's reader can actually make.\n *\n * `provenanceStandingMeta().action` is the generic sentence for a standing;\n * this is the one that accounts for what is on file. \"Open the source and\n * confirm it\" is a dead instruction on a value that has no source — an action\n * a reader cannot perform is the same defect as no action at all.\n */\nexport function provenanceNextMove(\n record: ProvenanceRecord,\n standing: ProvenanceStanding,\n policy: ProvenanceConfidencePolicy = DEFAULT_PROVENANCE_CONFIDENCE_POLICY,\n): string {\n const generic = provenanceStandingMeta(standing).action\n if (standing === 'settled') return generic\n\n const gaps = provenanceGaps(record)\n if (gaps.some((gap) => gap.kind === 'no-source')) {\n return 'Nobody recorded where this came from. Confirm the value and record its source before it is used.'\n }\n if (gaps.some((gap) => gap.kind === 'no-inputs')) {\n return 'Nobody recorded what this was computed from. Confirm the value and record its inputs before it is used.'\n }\n if (gaps.some((gap) => gap.kind === 'unavailable-source')) {\n return 'The source could not be opened. Try again, or confirm this value another way before you rely on it.'\n }\n if (record.basis === 'asserted' && (record.sources ?? []).length === 0) {\n return 'The agent gave no source. Check this against the real document before you rely on it.'\n }\n // Weakened only by what it was computed from: the move is one level down,\n // not on this row.\n if (record.basis === 'computed' && (record.inputs ?? []).length > 0 && resolveProvenanceStanding(record, policy) === 'settled') {\n return 'One of the values this was computed from still needs checking — open the marked ones below.'\n }\n return generic\n}\n\n/**\n * The accessible name of the disclosure control: the value, how it came to\n * exist, and — unless there is nothing to do — the next move. This is the\n * whole affordance for someone who never sees the colour.\n */\nexport function provenanceTriggerLabel(record: ProvenanceRecord, standing: ProvenanceStanding): string {\n const value = record.display.trim() === '' ? 'this missing value' : `“${record.display}”`\n const named = record.label ? `${record.label} ${value}` : value\n const basis = provenanceBasisMeta(record.basis).label\n const next = standing === 'settled' ? '' : ` ${provenanceStandingMeta(standing).label}.`\n return `Where ${named} came from — ${basis}.${next}`\n}\n","/**\n * `SeatPaywall` — the shared \"unlock this product\" screen every agent app\n * shows when a user has no active seat and has spent past the free tier.\n *\n * Copy contract (design §6.8): the included monthly AI usage is framed as a\n * BENEFIT the buyer receives — never the ratio, never the word \"margin\", never\n * \"we debit 50%\". Surface the allowance, hide the economics.\n *\n * Styling contract matches the rest of `web-react`: Tailwind classes over the\n * shared design tokens (`bg-card`, `border-border`, `text-muted-foreground`,\n * `bg-primary`, …); glyphs are inline SVGs; no icon or UI library.\n */\n\nimport type { ReactNode } from 'react'\n\nimport type { ProductSeatOffer } from '../platform/billing'\nimport { usePending } from './controls'\n\nexport interface SeatPaywallProps {\n /** Human product name shown in the headline, e.g. \"Creative\". */\n product: string\n /** Fired when the user clicks the unlock CTA — route them to checkout. When\n * it returns a promise the button shows a pending state and ignores repeat\n * clicks until it settles (no double-charge on a slow checkout open). */\n onCheckout: () => void | Promise<void>\n /** Monthly seat price in whole dollars. Default 100. */\n priceUsd?: number\n /** Included monthly AI usage in whole dollars. Default 50. */\n includedUsageUsd?: number\n /** Platform catalog terms. When present, these override the legacy dollar\n * props and show any introductory period without product-local price copy. */\n offer?: ProductSeatOffer\n /** Optional one-line value prop under the headline. */\n tagline?: string\n /** CTA label. Default \"Unlock {product}\". */\n ctaLabel?: string\n /** Value-prop bullets. Default = product/usage-derived only; pass your own to\n * supply product-specific value props (the shell bakes no GTM copy). */\n benefits?: ReactNode[]\n /** Optional fine print under the CTA (e.g. \"Cancel anytime.\"). Omitted by default. */\n footnote?: ReactNode\n}\n\nfunction usd(cents: number): string {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n minimumFractionDigits: cents % 100 === 0 ? 0 : 2,\n maximumFractionDigits: cents % 100 === 0 ? 0 : 2,\n }).format(cents / 100)\n}\n\nfunction CheckGlyph(): ReactNode {\n return (\n <svg\n className=\"h-4 w-4 shrink-0 text-primary\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n )\n}\n\nfunction Benefit({ children }: { children: ReactNode }): ReactNode {\n return (\n <li className=\"flex items-start gap-2.5 text-sm text-foreground\">\n <span className=\"mt-0.5\">\n <CheckGlyph />\n </span>\n <span>{children}</span>\n </li>\n )\n}\n\n/**\n * Centered card paywall. The price line reads\n * \"$100/mo · includes $50/mo of AI usage\" so the included allowance anchors the\n * value without ever exposing the ratio.\n */\nexport function SeatPaywall({\n product,\n onCheckout,\n priceUsd = 100,\n includedUsageUsd = 50,\n offer,\n tagline,\n ctaLabel,\n benefits,\n footnote,\n}: SeatPaywallProps): ReactNode {\n const { pending, run } = usePending()\n const recurringPrice = offer ? usd(offer.recurring.priceCents) : `$${priceUsd}`\n const recurringUsage = offer\n ? usd(offer.recurring.includedCreditsCents)\n : `$${includedUsageUsd}`\n const introductory = offer?.introductory ?? null\n return (\n <div className=\"flex min-h-[60vh] w-full items-center justify-center p-6\">\n <div className=\"w-full max-w-md rounded-2xl border border-card-edge bg-card p-8\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {product}\n </p>\n <h1 className=\"mt-2 text-2xl font-semibold tracking-tight text-foreground\">\n Unlock {product}\n </h1>\n {tagline && <p className=\"mt-2 text-sm text-muted-foreground\">{tagline}</p>}\n\n {introductory ? (\n <>\n <div className=\"mt-6 flex items-baseline gap-1.5\">\n <span className=\"text-3xl font-semibold text-foreground\">\n {usd(introductory.priceCents)}\n </span>\n <span className=\"text-sm text-muted-foreground\">first month</span>\n </div>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Includes {usd(introductory.includedCreditsCents)} of AI usage in your first month\n </p>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Then {recurringPrice}/mo · includes {recurringUsage}/mo of AI usage\n </p>\n </>\n ) : (\n <>\n <div className=\"mt-6 flex items-baseline gap-1.5\">\n <span className=\"text-3xl font-semibold text-foreground\">{recurringPrice}</span>\n <span className=\"text-sm text-muted-foreground\">/mo</span>\n </div>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Includes {recurringUsage}/mo of AI usage\n </p>\n </>\n )}\n\n <ul className=\"mt-6 space-y-2.5\">\n {(benefits ?? [\n `Full access to ${product}`,\n `${recurringUsage}/mo of AI usage included`,\n ]).map((benefit, i) => (\n <Benefit key={i}>{benefit}</Benefit>\n ))}\n </ul>\n\n <button\n type=\"button\"\n disabled={pending}\n onClick={() => run(onCheckout)}\n className=\"mt-7 inline-flex w-full items-center justify-center rounded-xl bg-primary px-4 py-2.5 text-sm font-medium text-primary-foreground transition hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-70\"\n >\n {pending ? 'Opening checkout…' : ctaLabel ?? `Unlock ${product}`}\n </button>\n {footnote && (\n <p className=\"mt-3 text-center text-xs text-muted-foreground/70\">\n {footnote}\n </p>\n )}\n </div>\n </div>\n )\n}\n","/**\n * The rendered half of the session shell: the history view behind the rail's\n * session list, and the rename/delete dialogs both surfaces drive.\n *\n * Storage is a seam, not a dependency. Every product keeps sessions somewhere\n * different (gtm threads, tax sessions, legal matters), so this takes a\n * `fetchPage` data port and injected mutations — the same shape\n * `AgentActivityPanel` (`fetchActivity`) and `ReviewQueuePanel` (`fetchQueue`)\n * already use, rather than a fifth pattern.\n *\n * sandbox-ui free on purpose: `/web-react` must not force the optional peer, so\n * these render on the shared design tokens like the rest of the subpath. The\n * pure logic (nav items, routing, cookies, merging) lives in `/session-shell`,\n * which a server loader can import without pulling React.\n */\n\nimport {\n type ReactNode,\n type RefObject,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react'\n\nimport {\n type SessionPage,\n type SessionRailAction,\n type SessionSort,\n type SessionSummary,\n mergeSessionPages,\n sessionLabel,\n UNTITLED_SESSION_LABEL,\n} from '../session-shell/index'\nimport { OVERLAY_SHADOW, PopoverSurface, usePopover } from './controls'\n\n// ---------------------------------------------------------------------------\n// useInfiniteScroll\n// ---------------------------------------------------------------------------\n\nexport interface UseInfiniteScrollOptions {\n /** Only fire `onLoadMore` while true (a next page exists, none in flight). */\n enabled: boolean\n /** Scroll container the sentinel lives in. Defaults to the viewport. */\n root?: RefObject<HTMLElement | null>\n /** Prefetch distance before the sentinel is actually reached. */\n rootMargin?: string\n}\n\nfunction rethrowAsync(error: unknown) {\n queueMicrotask(() => {\n throw error\n })\n}\n\n/**\n * Fires `onLoadMore` when a sentinel element scrolls into view. Returns a ref\n * callback for that sentinel (typically the last element in a list).\n *\n * The observer is re-created whenever `enabled` flips, so a short first page\n * that leaves the sentinel on-screen keeps loading: when a load finishes and\n * `enabled` returns to true, the fresh observer re-reads the current\n * intersection state and fires again until the sentinel is pushed off-screen.\n */\nexport function useInfiniteScroll(\n onLoadMore: () => void,\n { enabled, root, rootMargin = '300px' }: UseInfiniteScrollOptions,\n): (node: HTMLElement | null) => void {\n const [sentinel, setSentinel] = useState<HTMLElement | null>(null)\n const sentinelRef = useCallback((node: HTMLElement | null) => setSentinel(node), [])\n const onLoadMoreRef = useRef(onLoadMore)\n\n useEffect(() => {\n onLoadMoreRef.current = onLoadMore\n }, [onLoadMore])\n\n useEffect(() => {\n if (!sentinel || !enabled) return\n if (typeof IntersectionObserver === 'undefined') return\n const observer = new IntersectionObserver(\n (entries) => {\n if (!entries.some((entry) => entry.isIntersecting)) return\n try {\n onLoadMoreRef.current()\n } catch (error) {\n rethrowAsync(error)\n }\n },\n { root: root?.current ?? null, rootMargin },\n )\n observer.observe(sentinel)\n return () => observer.disconnect()\n }, [sentinel, enabled, root, rootMargin])\n\n return sentinelRef\n}\n\n// ---------------------------------------------------------------------------\n// useSessionHistory — cursor-paged data over an injected port\n// ---------------------------------------------------------------------------\n\nexport interface SessionPageQuery {\n /** Trimmed search term; empty string means no filter. */\n q: string\n sort: SessionSort\n /** `null` for the first page. */\n cursor: string | null\n /** Aborted when the view changes or the component unmounts. */\n signal: AbortSignal\n}\n\n/** Data port — one page of sessions for the current view. */\nexport type FetchSessionPage = (query: SessionPageQuery) => Promise<SessionPage>\n\nexport interface UseSessionHistoryOptions {\n fetchPage: FetchSessionPage\n /** Trimmed search term driving the fetch. */\n q: string\n sort: SessionSort\n /** SSR page 1 of the default view, so the first paint costs no request. */\n initialPage: SessionPage\n /** The sort `initialPage` was rendered for. Default `'newest'`. */\n defaultSort?: SessionSort\n}\n\nexport interface SessionHistoryState {\n items: SessionSummary[]\n hasMore: boolean\n isLoadingFirst: boolean\n isLoadingMore: boolean\n isError: boolean\n loadMore: () => void\n /** Re-run whichever load failed. */\n retry: () => void\n /** Refetch page 1 — call after a client-side mutation (e.g. a delete). */\n reload: () => void\n}\n\n/** Cheap content signature so a consumer inlining `initialPage={{items}}` on\n * every render does not reseed (and re-render) forever. Identity alone — what\n * the per-product versions keyed on — makes that an infinite loop. */\nfunction seedSignature(page: SessionPage): string {\n return `${page.nextCursor ?? ''}|${page.items.map((item) => item.id).join(',')}`\n}\n\n/**\n * Infinite-scroll data source for the history view. Seeds from `initialPage`\n * for the default view (no fetch) and otherwise fetches page 1 for the current\n * search/sort; `loadMore` appends the next cursor page.\n *\n * Raw promises + `AbortController` rather than a router fetcher, so a filter\n * change cancels in-flight requests, pages accumulate, and a late response from\n * a superseded view is dropped by the monotonic `seq` guard.\n */\nexport function useSessionHistory({\n fetchPage,\n q,\n sort,\n initialPage,\n defaultSort = 'newest',\n}: UseSessionHistoryOptions): SessionHistoryState {\n const [items, setItems] = useState<SessionSummary[]>(initialPage.items)\n const [nextCursor, setNextCursor] = useState<string | null>(initialPage.nextCursor ?? null)\n const [phase, setPhase] = useState<'idle' | 'loadingFirst' | 'loadingMore' | 'error'>('idle')\n const [reloadKey, setReloadKey] = useState(0)\n\n const seqRef = useRef(0)\n const resetAbortRef = useRef<AbortController | null>(null)\n const loadMoreAbortRef = useRef<AbortController | null>(null)\n const loadingMoreRef = useRef(false)\n const lastOpRef = useRef<'first' | 'more'>('first')\n\n // Live values read inside the stable `loadMore` callback.\n const nextCursorRef = useRef(nextCursor)\n nextCursorRef.current = nextCursor\n const viewRef = useRef({ q, sort, fetchPage })\n viewRef.current = { q, sort, fetchPage }\n const seedRef = useRef(initialPage)\n seedRef.current = initialPage\n\n const isDefaultView = q === '' && sort === defaultSort\n const seedKey = useMemo(() => seedSignature(initialPage), [initialPage])\n\n // Reset on view change (q/sort), on a new SSR seed (loader revalidation), or\n // on an explicit retry/reload. The default view comes straight from SSR;\n // explicit reloads fetch page 1 so a client-only mutation refreshes this list\n // without waiting on a route loader.\n useEffect(() => {\n resetAbortRef.current?.abort()\n loadMoreAbortRef.current?.abort()\n loadingMoreRef.current = false\n const seq = ++seqRef.current\n\n if (isDefaultView && reloadKey === 0) {\n setItems(seedRef.current.items)\n setNextCursor(seedRef.current.nextCursor ?? null)\n setPhase('idle')\n return\n }\n\n const controller = new AbortController()\n resetAbortRef.current = controller\n lastOpRef.current = 'first'\n setItems([])\n setNextCursor(null)\n setPhase('loadingFirst')\n\n void (async () => {\n try {\n const page = await viewRef.current.fetchPage({ q, sort, cursor: null, signal: controller.signal })\n if (seq !== seqRef.current) return\n setItems(page.items)\n setNextCursor(page.nextCursor ?? null)\n setPhase('idle')\n } catch {\n if (controller.signal.aborted || seq !== seqRef.current) return\n setPhase('error')\n }\n })()\n\n return () => controller.abort()\n }, [q, sort, seedKey, isDefaultView, reloadKey])\n\n const loadMore = useCallback(() => {\n const cursor = nextCursorRef.current\n if (!cursor || loadingMoreRef.current) return\n\n const { q: currentQ, sort: currentSort, fetchPage: currentFetch } = viewRef.current\n const seq = seqRef.current\n loadingMoreRef.current = true\n lastOpRef.current = 'more'\n const controller = new AbortController()\n loadMoreAbortRef.current = controller\n setPhase('loadingMore')\n\n void (async () => {\n try {\n const page = await currentFetch({ q: currentQ, sort: currentSort, cursor, signal: controller.signal })\n if (seq !== seqRef.current) return\n setItems((prev) => mergeSessionPages(prev, page.items))\n setNextCursor(page.nextCursor ?? null)\n setPhase('idle')\n } catch {\n if (controller.signal.aborted || seq !== seqRef.current) return\n setPhase('error')\n } finally {\n if (seq === seqRef.current) loadingMoreRef.current = false\n }\n })()\n }, [])\n\n const retry = useCallback(() => {\n if (lastOpRef.current === 'more') loadMore()\n else setReloadKey((key) => key + 1)\n }, [loadMore])\n\n const reload = useCallback(() => {\n setReloadKey((key) => key + 1)\n }, [])\n\n useEffect(\n () => () => {\n resetAbortRef.current?.abort()\n loadMoreAbortRef.current?.abort()\n },\n [],\n )\n\n return {\n items,\n hasMore: nextCursor !== null,\n isLoadingFirst: phase === 'loadingFirst',\n isLoadingMore: phase === 'loadingMore',\n isError: phase === 'error',\n loadMore,\n retry,\n reload,\n }\n}\n\n// ---------------------------------------------------------------------------\n// useSessionActions — rename / delete over injected mutations\n// ---------------------------------------------------------------------------\n\nexport interface SessionActionsOptions {\n /** Persist a new title. Reject to surface the error in the dialog. */\n renameSession: (sessionId: string, title: string) => Promise<void>\n deleteSession: (sessionId: string) => Promise<void>\n /** Called after a successful rename/delete — revalidate the rail here. */\n onChanged?: () => void\n /** Called after deleting the session the user is currently viewing, so the\n * product can navigate away from a route that no longer resolves. */\n onDeletedCurrent?: () => void\n /** The open session, compared against the delete target. */\n currentSessionId?: string | null\n /** Product toast/log seam. Errors also render inside the dialog. */\n notify?: (level: 'success' | 'error', message: string) => void\n labels?: Partial<SessionActionLabels>\n}\n\nexport interface SessionActionLabels {\n renameTitle: string\n renameField: string\n renameSubmit: string\n deleteTitle: string\n deleteBody: (title: string) => string\n deleteSubmit: string\n cancel: string\n renamed: string\n deleted: string\n renameFailed: string\n deleteFailed: string\n}\n\nconst DEFAULT_LABELS: SessionActionLabels = {\n renameTitle: 'Rename session',\n renameField: 'Title',\n renameSubmit: 'Save',\n deleteTitle: 'Delete session?',\n deleteBody: (title) => `This will permanently delete “${title}” and its messages. This cannot be undone.`,\n deleteSubmit: 'Delete',\n cancel: 'Cancel',\n renamed: 'Session renamed',\n deleted: 'Session deleted',\n renameFailed: 'Failed to rename session',\n deleteFailed: 'Failed to delete session',\n}\n\nexport interface SessionActions {\n openRename: (session: SessionSummary) => void\n openDelete: (session: SessionSummary) => void\n /** Render once, anywhere that survives navigation (the layout). */\n dialogs: ReactNode\n busy: boolean\n}\n\n/**\n * Rename + delete for one session, shared by the rail kebab and the history\n * row menu so both drive the same dialogs and the same product mutations.\n *\n * Dialogs are owned here rather than returned as raw state: two surfaces\n * needing the same confirm step is exactly how a product ends up with two\n * subtly different delete confirmations.\n */\nexport function useSessionActions({\n renameSession,\n deleteSession,\n onChanged,\n onDeletedCurrent,\n currentSessionId,\n notify,\n labels,\n}: SessionActionsOptions): SessionActions {\n const text = { ...DEFAULT_LABELS, ...labels }\n const [renameTarget, setRenameTarget] = useState<SessionSummary | null>(null)\n const [renameValue, setRenameValue] = useState('')\n const [deleteTarget, setDeleteTarget] = useState<SessionSummary | null>(null)\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const openRename = useCallback((session: SessionSummary) => {\n setError(null)\n setRenameTarget(session)\n setRenameValue(session.title ?? '')\n }, [])\n\n const openDelete = useCallback((session: SessionSummary) => {\n setError(null)\n setDeleteTarget(session)\n }, [])\n\n const submitRename = useCallback(async () => {\n if (!renameTarget) return\n const title = renameValue.trim()\n // A no-op rename closes rather than writing — otherwise every accidental\n // open costs a request and a revalidation.\n if (!title || title === renameTarget.title) {\n setRenameTarget(null)\n return\n }\n setBusy(true)\n setError(null)\n try {\n await renameSession(renameTarget.id, title)\n setRenameTarget(null)\n notify?.('success', text.renamed)\n onChanged?.()\n } catch (e) {\n const message = e instanceof Error ? e.message : text.renameFailed\n setError(message)\n notify?.('error', message)\n } finally {\n setBusy(false)\n }\n }, [renameTarget, renameValue, renameSession, notify, onChanged, text.renamed, text.renameFailed])\n\n const confirmDelete = useCallback(async () => {\n if (!deleteTarget) return\n const deletingCurrent = currentSessionId != null && deleteTarget.id === currentSessionId\n setBusy(true)\n setError(null)\n try {\n await deleteSession(deleteTarget.id)\n setDeleteTarget(null)\n notify?.('success', text.deleted)\n onChanged?.()\n if (deletingCurrent) onDeletedCurrent?.()\n } catch (e) {\n const message = e instanceof Error ? e.message : text.deleteFailed\n setError(message)\n notify?.('error', message)\n } finally {\n setBusy(false)\n }\n }, [deleteTarget, currentSessionId, deleteSession, notify, onChanged, onDeletedCurrent, text.deleted, text.deleteFailed])\n\n const dialogs = (\n <>\n {renameTarget && (\n <SessionDialog\n title={text.renameTitle}\n onClose={() => setRenameTarget(null)}\n busy={busy}\n error={error}\n footer={\n <>\n <DialogButton onClick={() => setRenameTarget(null)} disabled={busy} variant=\"ghost\">\n {text.cancel}\n </DialogButton>\n <DialogButton onClick={() => void submitRename()} disabled={busy || !renameValue.trim()}>\n {text.renameSubmit}\n </DialogButton>\n </>\n }\n >\n <label htmlFor=\"agent-app-rename-session\" className=\"text-xs text-muted-foreground\">\n {text.renameField}\n </label>\n <input\n id=\"agent-app-rename-session\"\n value={renameValue}\n autoFocus\n onChange={(e) => setRenameValue(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !busy) {\n e.preventDefault()\n void submitRename()\n }\n }}\n className=\"mt-1.5 h-9 w-full rounded-md border border-strong bg-background px-3 text-sm text-foreground\"\n />\n </SessionDialog>\n )}\n\n {deleteTarget && (\n <SessionDialog\n title={text.deleteTitle}\n onClose={() => setDeleteTarget(null)}\n busy={busy}\n error={error}\n footer={\n <>\n <DialogButton onClick={() => setDeleteTarget(null)} disabled={busy} variant=\"ghost\">\n {text.cancel}\n </DialogButton>\n <DialogButton onClick={() => void confirmDelete()} disabled={busy} variant=\"destructive\">\n {text.deleteSubmit}\n </DialogButton>\n </>\n }\n >\n <p className=\"text-sm text-muted-foreground\">{text.deleteBody(sessionLabel(deleteTarget))}</p>\n </SessionDialog>\n )}\n </>\n )\n\n return { openRename, openDelete, dialogs, busy }\n}\n\nfunction DialogButton({\n children,\n onClick,\n disabled,\n variant = 'primary',\n}: {\n children: ReactNode\n onClick: () => void\n disabled?: boolean\n variant?: 'primary' | 'ghost' | 'destructive'\n}) {\n const tone =\n variant === 'ghost'\n ? 'text-muted-foreground hover:bg-accent hover:text-foreground'\n : variant === 'destructive'\n ? 'bg-destructive text-destructive-foreground hover:opacity-90'\n : 'bg-primary text-primary-foreground hover:opacity-90'\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n className={`h-9 rounded-md px-3 text-sm font-medium transition disabled:opacity-50 ${tone}`}\n >\n {children}\n </button>\n )\n}\n\nfunction SessionDialog({\n title,\n children,\n footer,\n onClose,\n busy,\n error,\n}: {\n title: string\n children: ReactNode\n footer: ReactNode\n onClose: () => void\n busy: boolean\n error: string | null\n}) {\n // Escape closes unless a mutation is in flight — closing mid-write would hide\n // the error the user needs to see.\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && !busy) onClose()\n }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [busy, onClose])\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <div\n className=\"absolute inset-0 bg-black/50\"\n onClick={() => {\n if (!busy) onClose()\n }}\n aria-hidden\n />\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n className={`relative w-full max-w-sm rounded-xl border border-card-edge bg-popover p-5 ${OVERLAY_SHADOW}`}\n >\n <h2 className=\"text-sm font-semibold text-foreground\">{title}</h2>\n <div className=\"mt-3\">{children}</div>\n {error && (\n <p role=\"alert\" className=\"mt-3 rounded-md bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </p>\n )}\n <div className=\"mt-5 flex justify-end gap-2\">{footer}</div>\n </div>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// SessionHistoryPanel\n// ---------------------------------------------------------------------------\n\nexport interface SessionHistoryPanelProps {\n history: SessionHistoryState\n /** Whether the workspace has any sessions at all — decided by the SSR page,\n * independent of the active search, so filtering to zero shows \"no matches\"\n * rather than the first-run empty state. */\n hasAnySessions: boolean\n query: string\n onQueryChange: (value: string) => void\n sort: SessionSort\n onSortChange: (value: SessionSort) => void\n /** Product route for one session row. */\n hrefForSession: (sessionId: string) => string\n /** Rendered as the row link. Defaults to an `<a>`; pass a router Link to keep\n * client-side navigation. */\n linkComponent?: LinkLikeComponent\n /** Ids currently mid-turn — renders the responding treatment. */\n respondingSessionIds?: ReadonlySet<string>\n onRename?: (session: SessionSummary) => void\n onDelete?: (session: SessionSummary) => void\n /** Product-owned mutation for selected rows or a workspace-wide age range. */\n onBulkAction?: (action: SessionBulkAction) => Promise<void>\n /** Menu wording, so this surface and the rail name the same act the same way\n * — a product whose delete is really an archive says so in both places. */\n renameLabel?: string\n deleteLabel?: string\n /**\n * Row actions this shell has no opinion about — pin, categorise, share.\n * Same seam and same ordering as the rail's `SessionRowActions.extraActions`:\n * evaluated per session, placed between rename and delete. This menu is\n * text-only, so `icon` is ignored here and honoured on the rail.\n */\n extraActions?: (session: SessionSummary) => SessionRailAction[]\n /** New-session destination for the header action. Omitted ⇒ no button. */\n newSessionHref?: string\n title?: string\n untitledLabel?: string\n emptyTitle?: string\n emptyDescription?: string\n /** Absolute → relative timestamp. Defaults to a compact built-in. */\n formatTimestamp?: (isoDate: string | null) => string\n /** Max width of the reading column. `'full'` opts out for a product whose\n * surface really is a wide table. Default keeps title and timestamp inside\n * one scannable line rather than at opposite edges of a 1440px viewport. */\n contentWidth?: 'reading' | 'full'\n className?: string\n}\n\nexport type SessionBulkAction =\n | { kind: 'selected'; ids: string[] }\n | { kind: 'older-than'; days: number }\n | { kind: 'newer-than'; days: number }\n\nexport interface LinkLikeProps {\n to: string\n className?: string\n children?: ReactNode\n}\n\nexport type LinkLikeComponent = (props: LinkLikeProps) => ReactNode\n\nfunction AnchorLink({ to, className, children }: LinkLikeProps) {\n return (\n <a href={to} className={className}>\n {children}\n </a>\n )\n}\n\nconst MINUTE = 60_000\nconst HOUR = 60 * MINUTE\nconst DAY = 24 * HOUR\n\n/** Compact relative time. Overridable — a product with its own i18n passes\n * `formatTimestamp` rather than this being the only option. */\nexport function formatSessionTimestamp(isoDate: string | null): string {\n if (!isoDate) return ''\n const at = Date.parse(isoDate)\n if (Number.isNaN(at)) return ''\n const delta = Date.now() - at\n if (delta < MINUTE) return 'just now'\n if (delta < HOUR) return `${Math.floor(delta / MINUTE)}m ago`\n if (delta < DAY) return `${Math.floor(delta / HOUR)}h ago`\n if (delta < 7 * DAY) return `${Math.floor(delta / DAY)}d ago`\n return new Date(at).toLocaleDateString(undefined, { month: 'short', day: 'numeric' })\n}\n\nfunction SkeletonRows() {\n // The shimmer rows stay hidden from assistive tech — they say nothing a\n // reader can use — but the wait itself has to be announced, or the panel is\n // silent from the first paint until the rows arrive. The live region is a\n // sibling so the rows' own flex layout is untouched.\n return (\n <>\n <span role=\"status\" aria-live=\"polite\" aria-busy={true} className=\"sr-only\">\n Loading sessions…\n </span>\n <div className=\"flex flex-col gap-0.5\" aria-hidden>\n {Array.from({ length: 8 }).map((_, i) => (\n <div key={i} className=\"flex items-center gap-3 px-3 py-2.5\">\n <div className=\"h-4 w-4 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-1/2 animate-pulse rounded bg-muted\" />\n <div className=\"ml-auto h-3 w-12 animate-pulse rounded bg-muted\" />\n </div>\n ))}\n </div>\n </>\n )\n}\n\nfunction MessageIcon({ className }: { className?: string }) {\n return (\n <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n )\n}\n\n/**\n * The full session history: search, sort, cursor-paged rows with per-row\n * actions, and the states in between (first-run empty, loading, no matches,\n * error + retry).\n *\n * This is the surface the rail's capped list overflows into — the reason the\n * rail can stay short without hiding the user's work.\n */\nexport function SessionHistoryPanel({\n history,\n hasAnySessions,\n query,\n onQueryChange,\n sort,\n onSortChange,\n hrefForSession,\n linkComponent: Link = AnchorLink,\n respondingSessionIds,\n onRename,\n onDelete,\n onBulkAction,\n renameLabel = 'Rename',\n deleteLabel = 'Delete',\n extraActions,\n newSessionHref,\n title = 'History',\n untitledLabel = UNTITLED_SESSION_LABEL,\n emptyTitle = 'No sessions yet',\n emptyDescription = 'Your chat sessions will show up here once you start one.',\n formatTimestamp = formatSessionTimestamp,\n contentWidth = 'reading',\n className,\n}: SessionHistoryPanelProps) {\n const scrollRef = useRef<HTMLDivElement | null>(null)\n const sentinelRef = useInfiniteScroll(history.loadMore, {\n enabled: history.hasMore && !history.isLoadingMore && !history.isError,\n root: scrollRef,\n rootMargin: '300px',\n })\n const searchTerm = query.trim()\n const isSearching = searchTerm.length > 0\n const column = contentWidth === 'full' ? 'w-full' : 'mx-auto w-full max-w-4xl'\n const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())\n const [ageDays, setAgeDays] = useState('30')\n const [bulkTarget, setBulkTarget] = useState<{\n action: SessionBulkAction\n title: string\n body: string\n } | null>(null)\n const [bulkBusy, setBulkBusy] = useState(false)\n const [bulkError, setBulkError] = useState<string | null>(null)\n\n useEffect(() => {\n setSelectedIds(new Set())\n }, [searchTerm, sort])\n\n useEffect(() => {\n const visible = new Set(history.items.map((item) => item.id))\n setSelectedIds((current) => {\n const next = new Set([...current].filter((id) => visible.has(id)))\n return next.size === current.size ? current : next\n })\n }, [history.items])\n\n const selectedCount = selectedIds.size\n const allVisibleSelected = history.items.length > 0 && history.items.every((item) => selectedIds.has(item.id))\n const parsedAgeDays = Number(ageDays)\n const validAgeDays = Number.isInteger(parsedAgeDays) && parsedAgeDays >= 1 && parsedAgeDays <= 36_500\n\n const openBulkAction = useCallback((action: SessionBulkAction) => {\n const verb = deleteLabel.toLowerCase()\n if (action.kind === 'selected') {\n setBulkTarget({\n action,\n title: `${deleteLabel} selected sessions?`,\n body: `${verb === 'delete' ? 'This permanently removes' : `This ${verb}s`} ${action.ids.length} selected session${action.ids.length === 1 ? '' : 's'} and its messages.`,\n })\n return\n }\n const range = action.kind === 'older-than' ? `older than ${action.days} days` : `from the last ${action.days} days`\n setBulkTarget({\n action,\n title: `${deleteLabel} sessions ${range}?`,\n body: 'This applies to every matching session in this workspace, including sessions not currently loaded in this list.',\n })\n }, [deleteLabel])\n\n const confirmBulkAction = useCallback(async () => {\n if (!bulkTarget || !onBulkAction) return\n setBulkBusy(true)\n setBulkError(null)\n try {\n await onBulkAction(bulkTarget.action)\n setBulkTarget(null)\n setSelectedIds(new Set())\n history.reload()\n } catch (error) {\n setBulkError(error instanceof Error ? error.message : `Could not ${deleteLabel.toLowerCase()} sessions`)\n } finally {\n setBulkBusy(false)\n }\n }, [bulkTarget, deleteLabel, history, onBulkAction])\n\n return (\n <div className={`flex min-h-0 min-w-0 flex-1 flex-col ${className ?? ''}`}>\n {/* 56px, matching the rail header the fleet aligned on. */}\n <header className=\"flex h-14 shrink-0 items-center border-b border-border px-4 sm:px-6\">\n <div className={`flex items-center gap-3 px-3 ${column}`}>\n <h1 className=\"flex-1 truncate text-sm font-semibold text-foreground\">{title}</h1>\n {newSessionHref && (\n <Link\n to={newSessionHref}\n className=\"inline-flex h-8 shrink-0 items-center gap-1.5 rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground transition hover:opacity-90\"\n >\n <span aria-hidden className=\"text-sm leading-none\">+</span>\n New chat\n </Link>\n )}\n </div>\n </header>\n\n <div ref={scrollRef} className=\"min-h-0 flex-1 overflow-y-auto\">\n {hasAnySessions && (\n <div className=\"sticky top-0 z-10 bg-background px-4 sm:px-6\">\n <div className={`flex flex-col gap-2 px-3 pb-3 pt-4 sm:flex-row sm:items-center sm:gap-3 ${column}`}>\n <input\n type=\"search\"\n value={query}\n onChange={(e) => onQueryChange(e.target.value)}\n placeholder=\"Search your sessions…\"\n aria-label=\"Search sessions\"\n className=\"h-9 min-w-0 appearance-none rounded-md border border-strong bg-card px-3 text-sm text-foreground placeholder:text-muted-foreground sm:flex-1 [&::-webkit-search-cancel-button]:appearance-none\"\n />\n <select\n value={sort}\n onChange={(e) => onSortChange(e.target.value as SessionSort)}\n aria-label=\"Sort sessions\"\n className=\"h-9 shrink-0 appearance-none rounded-md border border-strong bg-card px-2 text-sm text-foreground sm:w-[132px]\"\n >\n <option value=\"newest\">Newest</option>\n <option value=\"oldest\">Oldest</option>\n </select>\n </div>\n {onBulkAction && (\n <div className={`flex flex-col gap-2 border-t border-border px-3 py-3 ${column}`}>\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setSelectedIds(new Set(history.items.map((item) => item.id)))}\n disabled={allVisibleSelected || history.items.length === 0}\n className=\"h-8 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition hover:bg-accent disabled:opacity-50\"\n >\n Select all\n </button>\n <button\n type=\"button\"\n onClick={() => setSelectedIds(new Set())}\n disabled={selectedCount === 0}\n className=\"h-8 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition hover:bg-accent disabled:opacity-50\"\n >\n Deselect all\n </button>\n <span className=\"text-xs text-muted-foreground\" aria-live=\"polite\">\n {selectedCount} selected\n </span>\n {selectedCount > 0 && (\n <button\n type=\"button\"\n onClick={() => openBulkAction({ kind: 'selected', ids: [...selectedIds] })}\n className=\"h-8 rounded-md bg-destructive px-2.5 text-xs font-medium text-destructive-foreground transition hover:opacity-90\"\n >\n {deleteLabel} selected\n </button>\n )}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <label htmlFor=\"agent-app-session-age\" className=\"text-xs text-muted-foreground\">\n Session age\n </label>\n <input\n id=\"agent-app-session-age\"\n type=\"number\"\n min={1}\n max={36_500}\n value={ageDays}\n onChange={(event) => setAgeDays(event.target.value)}\n aria-invalid={ageDays.length > 0 && !validAgeDays}\n className=\"h-8 w-20 rounded-md border border-strong bg-card px-2 text-xs tabular-nums text-foreground\"\n />\n <span className=\"text-xs text-muted-foreground\">days</span>\n <button\n type=\"button\"\n onClick={() => openBulkAction({ kind: 'older-than', days: parsedAgeDays })}\n disabled={!validAgeDays}\n className=\"h-8 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition hover:bg-accent disabled:opacity-50\"\n >\n {deleteLabel} older\n </button>\n <button\n type=\"button\"\n onClick={() => openBulkAction({ kind: 'newer-than', days: parsedAgeDays })}\n disabled={!validAgeDays}\n className=\"h-8 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition hover:bg-accent disabled:opacity-50\"\n >\n {deleteLabel} recent\n </button>\n </div>\n </div>\n )}\n </div>\n )}\n\n <div className={`px-4 pb-8 pt-1 sm:px-6 ${column}`}>\n {!hasAnySessions ? (\n <div className=\"flex min-h-[50vh] flex-col items-center justify-center gap-2 text-center\">\n <p className=\"text-sm font-medium text-foreground\">{emptyTitle}</p>\n <p className=\"max-w-xs text-xs text-muted-foreground\">{emptyDescription}</p>\n </div>\n ) : history.isLoadingFirst ? (\n <SkeletonRows />\n ) : history.items.length === 0 ? (\n history.isError ? (\n <ErrorBlock onRetry={history.retry} message=\"Couldn’t load your sessions.\" />\n ) : isSearching ? (\n <p className=\"py-16 text-center text-sm text-muted-foreground\">\n No sessions match “{searchTerm}”.\n </p>\n ) : (\n <p className=\"py-16 text-center text-sm text-muted-foreground\">No sessions remain.</p>\n )\n ) : (\n <div className=\"flex flex-col gap-0.5\">\n {history.items.map((session) => (\n <SessionRow\n key={session.id}\n session={session}\n href={hrefForSession(session.id)}\n Link={Link}\n responding={respondingSessionIds?.has(session.id) ?? false}\n untitledLabel={untitledLabel}\n timestamp={formatTimestamp(session.updatedAt)}\n onRename={onRename}\n onDelete={onDelete}\n selectable={Boolean(onBulkAction)}\n selected={selectedIds.has(session.id)}\n onSelectedChange={(selected) => {\n setSelectedIds((current) => {\n const next = new Set(current)\n if (selected) next.add(session.id)\n else next.delete(session.id)\n return next\n })\n }}\n renameLabel={renameLabel}\n deleteLabel={deleteLabel}\n extraActions={extraActions}\n />\n ))}\n\n {history.isError ? (\n <ErrorBlock onRetry={history.retry} message=\"Couldn’t load more sessions.\" inline />\n ) : history.hasMore ? (\n <div ref={sentinelRef} className=\"flex items-center justify-center py-6\">\n {history.isLoadingMore && (\n <span role=\"status\" aria-live=\"polite\" aria-busy={true} className=\"text-xs text-muted-foreground\">\n Loading…\n </span>\n )}\n </div>\n ) : null}\n </div>\n )}\n </div>\n </div>\n {bulkTarget && (\n <SessionDialog\n title={bulkTarget.title}\n onClose={() => {\n if (!bulkBusy) {\n setBulkTarget(null)\n setBulkError(null)\n }\n }}\n busy={bulkBusy}\n error={bulkError}\n footer={\n <>\n <DialogButton\n onClick={() => {\n setBulkTarget(null)\n setBulkError(null)\n }}\n disabled={bulkBusy}\n variant=\"ghost\"\n >\n Cancel\n </DialogButton>\n <DialogButton onClick={() => void confirmBulkAction()} disabled={bulkBusy} variant=\"destructive\">\n {bulkBusy ? 'Working…' : deleteLabel}\n </DialogButton>\n </>\n }\n >\n <p className=\"text-sm text-muted-foreground\">{bulkTarget.body}</p>\n </SessionDialog>\n )}\n </div>\n )\n}\n\nfunction ErrorBlock({ message, onRetry, inline }: { message: string; onRetry: () => void; inline?: boolean }) {\n return (\n <div\n className={\n inline\n ? 'flex items-center justify-center gap-3 py-6 text-sm text-muted-foreground'\n : 'flex min-h-[40vh] flex-col items-center justify-center gap-3 text-center'\n }\n >\n <span className=\"text-sm text-muted-foreground\">{message}</span>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"h-8 rounded-md border border-border px-3 text-xs font-medium text-foreground transition hover:bg-accent\"\n >\n Retry\n </button>\n </div>\n )\n}\n\nfunction SessionRow({\n session,\n href,\n Link,\n responding,\n untitledLabel,\n timestamp,\n onRename,\n onDelete,\n renameLabel,\n deleteLabel,\n extraActions,\n selectable,\n selected,\n onSelectedChange,\n}: {\n session: SessionSummary\n href: string\n Link: LinkLikeComponent\n responding: boolean\n untitledLabel: string\n timestamp: string\n onRename?: (session: SessionSummary) => void\n onDelete?: (session: SessionSummary) => void\n renameLabel: string\n deleteLabel: string\n extraActions?: (session: SessionSummary) => SessionRailAction[]\n selectable: boolean\n selected: boolean\n onSelectedChange: (selected: boolean) => void\n}) {\n const [menuOpen, setMenuOpen] = useState(false)\n const panelId = useId()\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(menuOpen, setMenuOpen)\n const extras = extraActions?.(session) ?? []\n const hasMenu = Boolean(onRename) || Boolean(onDelete) || extras.length > 0\n // An unread dot next to a live responding indicator is two signals for one\n // state; the working indicator wins while the turn runs.\n const showUnread = Boolean(session.unread) && !responding\n\n return (\n <div className={`group relative flex items-center gap-2 rounded-lg px-3 py-2.5 transition-colors hover:bg-accent ${selected ? 'bg-primary/10' : ''}`}>\n {selectable && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(event) => onSelectedChange(event.target.checked)}\n aria-label={`Select ${sessionLabel(session, untitledLabel)}`}\n className=\"h-4 w-4 shrink-0 rounded border-border accent-primary\"\n />\n )}\n <Link to={href} className=\"flex min-w-0 flex-1 items-center gap-3\">\n {showUnread && <span className=\"h-1.5 w-1.5 shrink-0 rounded-full bg-primary\" aria-hidden />}\n <MessageIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span\n className={`truncate text-sm ${responding ? 'text-muted-foreground' : 'text-foreground'} ${showUnread ? 'font-semibold' : ''}`}\n {...(responding ? { role: 'status', 'aria-label': 'Agent responding' } : {})}\n >\n {sessionLabel(session, untitledLabel)}\n </span>\n </Link>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">{timestamp}</span>\n {hasMenu && (\n <div ref={containerRef} className=\"relative shrink-0\">\n <button\n type=\"button\"\n {...triggerProps}\n aria-label=\"Session actions\"\n aria-controls={menuOpen ? panelId : undefined}\n onClick={() => setMenuOpen((open) => !open)}\n // Visible by default and hover-revealed only from `sm:` up: a\n // touch device has no hover, so an opacity-0 kebab is an action\n // the user can never reach.\n className=\"flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:bg-muted hover:text-foreground focus-visible:opacity-100 sm:opacity-0 sm:group-hover:opacity-100 aria-expanded:opacity-100\"\n >\n <span aria-hidden className=\"text-base leading-none\">⋯</span>\n </button>\n <PopoverSurface\n open={menuOpen}\n id={panelId}\n role=\"menu\"\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={`w-36 overflow-hidden rounded-md border border-card-edge bg-popover py-1 ${OVERLAY_SHADOW}`}\n >\n {onRename && (\n <button\n type=\"button\"\n role=\"menuitem\"\n onClick={() => {\n setMenuOpen(false)\n onRename(session)\n }}\n className=\"block w-full px-3 py-1.5 text-left text-xs text-foreground transition hover:bg-accent\"\n >\n {renameLabel}\n </button>\n )}\n {extras.map((action) => (\n <button\n key={action.id}\n type=\"button\"\n role=\"menuitem\"\n onClick={() => {\n setMenuOpen(false)\n action.onSelect()\n }}\n className={`block w-full px-3 py-1.5 text-left text-xs transition ${\n action.destructive\n ? 'text-destructive hover:bg-destructive/10'\n : 'text-foreground hover:bg-accent'\n }`}\n >\n {action.label}\n </button>\n ))}\n {onDelete && (\n <button\n type=\"button\"\n role=\"menuitem\"\n onClick={() => {\n setMenuOpen(false)\n onDelete(session)\n }}\n className=\"block w-full px-3 py-1.5 text-left text-xs text-destructive transition hover:bg-destructive/10\"\n >\n {deleteLabel}\n </button>\n )}\n </PopoverSurface>\n </div>\n )}\n </div>\n )\n}\n","/**\n * `RecordGrid` — the editable record table four verticals each hand-rolled: a\n * cap table, two relationship record pages, a content board, and an entities\n * panel. Every copy re-derived the same mechanism and each one lost a\n * different part of it.\n *\n * What this owns:\n *\n * - **Typed columns with correctable errors.** A cell is text / number /\n * currency / date / select / boolean (`./record-grid-model`), so a rejected\n * edit explains itself next to the control instead of storing a coerced\n * value.\n * - **Optimistic write with a real rollback.** The edit lands instantly, the\n * caller's writer returns a typed outcome, and a failure puts the previous\n * value back AND says why. A grid that keeps a value the server refused is\n * the defect this replaces.\n * - **Provenance per cell.** An optional quote + link + basis, so a\n * record-backed grid shows where a value came from without the product\n * building a second surface for it.\n * - **Three distinct data states, on `web-react/async`'s own contract.**\n * `state: AsyncResourceState<Row[]>` and `empty: AsyncEmptySpec` are the\n * same types every other screen fetches through — loading, error-with-\n * retry and empty are different renders, a failed fetch never looks like\n * \"no data yet\", and the empty state carries the CALLER's next action.\n * The optimistic overlay is layered on top of whichever `ready`/`empty`\n * value the caller last supplied, so a row created while the caller's own\n * status is still `empty` renders immediately rather than waiting for a\n * refetch.\n * - **Keyboard-navigable, labelled controls.** Arrow keys move between cells,\n * Enter edits, Escape cancels, and no destructive control is an unlabelled\n * icon.\n *\n * Presentation is Tailwind against the shared design tokens, with no icon\n * library and no sandbox-ui — the same contract as the rest of `/web-react`.\n */\n\nimport {\n Fragment,\n isValidElement,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type ReactNode,\n} from 'react'\n\nimport { type AsyncEmptyAction, type AsyncEmptySpec, type AsyncResourceState } from './async'\nimport { OVERLAY_SHADOW, PopoverSurface, usePopover } from './controls'\nimport {\n EMPTY_RECORD_GRID_OVERLAY,\n formatRecordGridValue,\n isRecordGridCellApplicable,\n projectRecordGridRows,\n pruneRecordGridOverlay,\n readRecordGridCell,\n recordGridEditorText,\n recordGridRowLabel,\n sameRecordGridValue,\n validateRecordGridRow,\n withRecordGridCreated,\n withRecordGridRemoved,\n withRecordGridServerRow,\n withRecordGridUpdate,\n withoutRecordGridCreated,\n withoutRecordGridRemoved,\n withoutRecordGridUpdate,\n type RecordGridCellSource,\n type RecordGridColumn,\n type RecordGridOverlay,\n type RecordGridRow,\n type RecordGridSourceBasis,\n type RecordGridValue,\n} from './record-grid-model'\n\nexport * from './record-grid-model'\n\n/** One committed cell edit, handed to `onUpdate`. */\nexport interface RecordGridCellChange {\n /** The row as it was BEFORE the edit — what rollback restores. */\n row: RecordGridRow\n columnId: string\n value: RecordGridValue\n /** The full value bag after the edit: what a whole-row write would send. */\n values: Readonly<Record<string, RecordGridValue>>\n}\n\n/** Outcome of an update or a delete. `value` optionally carries the server's\n * canonical row, which replaces the optimistic one. */\nexport type RecordGridWriteOutcome =\n | { succeeded: true; value?: RecordGridRow }\n | { succeeded: false; error: string }\n\n/** Outcome of a create. The row is REQUIRED on success: a create that does not\n * name the row it wrote leaves the grid unable to address it. */\nexport type RecordGridCreateOutcome =\n | { succeeded: true; value: RecordGridRow }\n | { succeeded: false; error: string }\n\n/** Properties for the editable, provenance-aware record grid. */\nexport interface RecordGridProps {\n /** Column definitions, in render order. */\n columns: readonly RecordGridColumn[]\n /** Fetch state over the caller's rows — `web-react/async`'s\n * `AsyncResourceState`, the same three-state contract every other screen\n * in the shell fetches through. `ready`/`empty`'s value is the base rows;\n * optimistic edits are layered over it and dropped as a later value\n * catches up. `error` always carries `retry` — there is no way to render a\n * failed fetch with no recovery action, by construction. */\n state: AsyncResourceState<readonly RecordGridRow[]>\n /** Accessible name for the grid. Required — an unnamed grid is unusable with\n * a screen reader. */\n caption: string\n /** What the empty state says, and what it offers next — `web-react/async`'s\n * `AsyncEmptySpec`, so an empty grid reads in the same words as an empty\n * list or panel elsewhere in the product. */\n empty: AsyncEmptySpec\n /** Persist one created row. Absent → no add affordance. */\n onCreate?: (values: Readonly<Record<string, RecordGridValue>>) => Promise<RecordGridCreateOutcome>\n /** Persist one cell edit. Absent → every cell renders read-only. */\n onUpdate?: (change: RecordGridCellChange) => Promise<RecordGridWriteOutcome>\n /** Delete one row. Absent → no delete affordance. */\n onDelete?: (row: RecordGridRow) => Promise<RecordGridWriteOutcome>\n /** Starting values for the add form. */\n newRowDefaults?: Readonly<Record<string, RecordGridValue>>\n /** Label of the add control and of the add form. Defaults to `Add row`. */\n addLabel?: string\n /** BCP-47 locale for number, currency, and date display. */\n locale?: string\n /** Rendered above the grid — filters, counts, a product action row. */\n toolbar?: ReactNode\n /** Skeleton rows in the loading state. Defaults to 3. */\n loadingRowCount?: number\n className?: string\n}\n\n/** Stable empty base for `idle`/`loading`/`error` — a fresh `[]` every render\n * would retrigger the overlay-pruning effect for no reason. */\nconst EMPTY_RECORD_GRID_ROWS: readonly RecordGridRow[] = []\n\n/** Internal map key. NUL cannot occur in a column or row id a product would\n * write, and this key never reaches the DOM. */\nconst CELL_KEY_SEPARATOR = '\\u0000'\n\nfunction cellKey(rowId: string, columnId: string): string {\n return `${rowId}${CELL_KEY_SEPARATOR}${columnId}`\n}\n\nconst NAVIGATION_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'])\n\nfunction clamp(value: number, max: number): number {\n if (value < 0) return 0\n if (value > max) return max\n return value\n}\n\nfunction alignmentClass(column: RecordGridColumn): string {\n const align = column.align ?? (column.kind === 'number' || column.kind === 'currency' ? 'right' : 'left')\n return align === 'right' ? 'text-right' : 'text-left'\n}\n\n/** Columns bucketed by their `group`, preserving first-appearance order. Each\n * bucket becomes one labelled sub-form in the add form — how a nested\n * schedule stays a set of flat, individually-typed columns. */\nfunction groupColumns(\n columns: readonly RecordGridColumn[],\n): Array<{ label: string | null; columns: RecordGridColumn[] }> {\n const groups: Array<{ label: string | null; columns: RecordGridColumn[] }> = []\n for (const column of columns) {\n const label = column.group ?? null\n const existing = groups.find((group) => group.label === label)\n if (existing) existing.columns.push(column)\n else groups.push({ label, columns: [column] })\n }\n return groups\n}\n\nconst INPUT_CLASS =\n 'w-full rounded-md border border-strong bg-background px-2 py-1 text-sm text-foreground outline-none focus:border-primary/60 focus:ring-1 focus:ring-primary/40'\n\nconst BASIS_TONES: Record<RecordGridSourceBasis, string> = {\n extracted: 'border-primary/60 text-primary',\n entered: 'border-success/60 text-success',\n computed: 'border-border text-muted-foreground',\n asserted: 'border-warning/60 text-warning',\n}\n\nconst BASIS_TITLES: Record<RecordGridSourceBasis, string> = {\n extracted: 'Extracted from a source document',\n entered: 'Confirmed by a person',\n computed: 'Computed from other values',\n asserted: 'Agent, unverified — no source recorded',\n}\n\n/**\n * The shared editable record table. A row is a flat value bag keyed by column\n * id, so a record store's fold output maps straight on: one cell per entry,\n * its quote and link in `sources`.\n */\nexport function RecordGrid({\n columns,\n caption,\n state,\n empty,\n onCreate,\n onUpdate,\n onDelete,\n newRowDefaults,\n addLabel = 'Add row',\n locale,\n toolbar,\n loadingRowCount = 3,\n className,\n}: RecordGridProps) {\n const fieldPrefix = useId()\n const [overlay, setOverlay] = useState<RecordGridOverlay>(EMPTY_RECORD_GRID_OVERLAY)\n const [editing, setEditingState] = useState<{ rowId: string; columnId: string; text: string } | null>(null)\n const [cellErrors, setCellErrors] = useState<Readonly<Record<string, string>>>({})\n const [rowErrors, setRowErrors] = useState<Readonly<Record<string, string>>>({})\n const [pendingRows, setPendingRows] = useState<Readonly<Record<string, true>>>({})\n const [focus, setFocus] = useState<{ rowId: string; columnId: string } | null>(null)\n const [openSource, setOpenSource] = useState<string | null>(null)\n const [confirmDelete, setConfirmDelete] = useState<string | null>(null)\n const [adding, setAdding] = useState(false)\n const [draft, setDraft] = useState<Record<string, RecordGridValue>>({ ...(newRowDefaults ?? {}) })\n const [draftErrors, setDraftErrors] = useState<Readonly<Record<string, string>>>({})\n const [draftError, setDraftError] = useState<string | null>(null)\n const [creating, setCreating] = useState(false)\n\n const cellRefs = useRef(new Map<string, HTMLElement | null>())\n const settling = useRef(false)\n const draftCounter = useRef(0)\n // Mirrors `editing` synchronously: a blur that arrives after the editor\n // already closed must not re-commit the value it was holding.\n const editingRef = useRef<{ rowId: string; columnId: string; text: string } | null>(null)\n\n const setEditing = useCallback((next: { rowId: string; columnId: string; text: string } | null) => {\n editingRef.current = next\n setEditingState(next)\n }, [])\n\n // `ready` and `empty` are the only variants carrying rows to project; the\n // other three short-circuit below before `visibleRows` is ever read, so an\n // empty base here is inert rather than wrong.\n const callerRows = state.status === 'ready' || state.status === 'empty' ? state.value : EMPTY_RECORD_GRID_ROWS\n\n // Overlay entries the caller's own rows have caught up with are dropped, so\n // a later refresh of the same cell is never masked by a settled edit.\n useEffect(() => {\n setOverlay((current) => pruneRecordGridOverlay(callerRows, current))\n }, [callerRows])\n\n const visibleRows = useMemo(() => projectRecordGridRows(callerRows, overlay), [callerRows, overlay])\n\n const activeFocus = useMemo(() => {\n if (focus === null) return null\n if (!visibleRows.some((row) => row.id === focus.rowId)) return null\n if (!columns.some((column) => column.id === focus.columnId)) return null\n return focus\n }, [columns, focus, visibleRows])\n\n const setCellError = useCallback((key: string, message: string | null) => {\n setCellErrors((current) => {\n if (message === null) {\n if (!(key in current)) return current\n const next = { ...current }\n delete next[key]\n return next\n }\n if (current[key] === message) return current\n return { ...current, [key]: message }\n })\n }, [])\n\n const setRowError = useCallback((rowId: string, message: string | null) => {\n setRowErrors((current) => {\n if (message === null) {\n if (!(rowId in current)) return current\n const next = { ...current }\n delete next[rowId]\n return next\n }\n return { ...current, [rowId]: message }\n })\n }, [])\n\n const setRowPending = useCallback((rowId: string, pending: boolean) => {\n setPendingRows((current) => {\n if (pending) return rowId in current ? current : { ...current, [rowId]: true }\n if (!(rowId in current)) return current\n const next = { ...current }\n delete next[rowId]\n return next\n })\n }, [])\n\n const focusCell = useCallback((rowId: string, columnId: string) => {\n setFocus({ rowId, columnId })\n cellRefs.current.get(cellKey(rowId, columnId))?.focus()\n }, [])\n\n const beginEdit = useCallback(\n (row: RecordGridRow, column: RecordGridColumn) => {\n // An editor always opens on the STORED value, so the message from a\n // previous rejected attempt must not survive into it.\n setCellError(cellKey(row.id, column.id), null)\n setEditing({\n rowId: row.id,\n columnId: column.id,\n text: recordGridEditorText(column, row.values[column.id] ?? null),\n })\n },\n [setCellError, setEditing],\n )\n\n /** Apply one cell value optimistically, write it, and on failure put the\n * previous value back with the reason attached to the row. */\n const applyCellWrite = useCallback(\n async (row: RecordGridRow, column: RecordGridColumn, value: RecordGridValue) => {\n if (!onUpdate) return\n const values = { ...row.values, [column.id]: value }\n setOverlay((current) => withRecordGridUpdate(current, row.id, column.id, value))\n setRowError(row.id, null)\n setRowPending(row.id, true)\n\n let outcome: RecordGridWriteOutcome\n try {\n outcome = await onUpdate({ row, columnId: column.id, value, values })\n } catch (cause) {\n outcome = { succeeded: false, error: cause instanceof Error ? cause.message : String(cause) }\n }\n\n setRowPending(row.id, false)\n if (outcome.succeeded) {\n const canonical = outcome.value\n if (canonical) setOverlay((current) => withRecordGridServerRow(current, row.id, canonical))\n return\n }\n setOverlay((current) => withoutRecordGridUpdate(current, row.id, column.id))\n const rejected = formatRecordGridValue(column, value, locale)\n setRowError(\n row.id,\n rejected === ''\n ? `Could not save ${column.header}: ${outcome.error}`\n : `Could not save ${column.header} as ${rejected}: ${outcome.error}`,\n )\n },\n [locale, onUpdate, setRowError, setRowPending],\n )\n\n const commitEdit = useCallback(\n async (row: RecordGridRow, column: RecordGridColumn, text: string) => {\n const open = editingRef.current\n if (open === null || open.rowId !== row.id || open.columnId !== column.id) return\n if (settling.current) return\n settling.current = true\n try {\n const key = cellKey(row.id, column.id)\n const parsed = readRecordGridCell(column, text)\n if (!parsed.succeeded) {\n // The editor stays open holding the rejected text: the point of a\n // typed cell is that a person can correct it in place.\n setCellError(key, parsed.error)\n setEditing({ rowId: row.id, columnId: column.id, text })\n return\n }\n setCellError(key, null)\n setEditing(null)\n if (sameRecordGridValue(row.values[column.id], parsed.value)) return\n await applyCellWrite(row, column, parsed.value)\n } finally {\n settling.current = false\n }\n },\n [applyCellWrite, setCellError, setEditing],\n )\n\n const cancelEdit = useCallback(\n (row: RecordGridRow, column: RecordGridColumn) => {\n setCellError(cellKey(row.id, column.id), null)\n setEditing(null)\n focusCell(row.id, column.id)\n },\n [focusCell, setCellError, setEditing],\n )\n\n const performDelete = useCallback(\n async (row: RecordGridRow) => {\n if (!onDelete) return\n setConfirmDelete(null)\n setRowError(row.id, null)\n setOverlay((current) => withRecordGridRemoved(current, row.id))\n\n let outcome: RecordGridWriteOutcome\n try {\n outcome = await onDelete(row)\n } catch (cause) {\n outcome = { succeeded: false, error: cause instanceof Error ? cause.message : String(cause) }\n }\n if (outcome.succeeded) return\n setOverlay((current) => withoutRecordGridRemoved(current, row.id))\n setRowError(row.id, `Could not delete ${recordGridRowLabel(columns, row)}: ${outcome.error}`)\n },\n [columns, onDelete, setRowError],\n )\n\n const resetDraft = useCallback(() => {\n setDraft({ ...(newRowDefaults ?? {}) })\n setDraftErrors({})\n setDraftError(null)\n }, [newRowDefaults])\n\n const openAdd = useCallback(() => {\n resetDraft()\n setAdding(true)\n }, [resetDraft])\n\n const submitDraft = useCallback(async () => {\n if (!onCreate) return\n const validated = validateRecordGridRow(columns, draft)\n if (!validated.succeeded) {\n setDraftErrors(validated.cellErrors)\n setDraftError(validated.error)\n return\n }\n setDraftErrors({})\n setDraftError(null)\n\n draftCounter.current += 1\n const draftId = `${fieldPrefix}-draft-${draftCounter.current}`\n setOverlay((current) => withRecordGridCreated(current, { id: draftId, values: validated.value }))\n setCreating(true)\n\n let outcome: RecordGridCreateOutcome\n try {\n outcome = await onCreate(validated.value)\n } catch (cause) {\n outcome = { succeeded: false, error: cause instanceof Error ? cause.message : String(cause) }\n }\n\n setCreating(false)\n if (outcome.succeeded) {\n setOverlay((current) => withRecordGridServerRow(current, draftId, outcome.value))\n setAdding(false)\n resetDraft()\n return\n }\n // The optimistic row goes away and the form keeps what was typed: a\n // rejected create is correctable, never silently lost.\n setOverlay((current) => withoutRecordGridCreated(current, draftId))\n setDraftError(outcome.error)\n }, [columns, draft, fieldPrefix, onCreate, resetDraft])\n\n const handleGridKeyDown = useCallback(\n (event: KeyboardEvent<HTMLTableElement>) => {\n if (editing !== null) return\n const target = event.target as HTMLElement\n const rowId = target.dataset?.recordGridRow\n const columnId = target.dataset?.recordGridColumn\n if (rowId === undefined || columnId === undefined) return\n const rowIndex = visibleRows.findIndex((row) => row.id === rowId)\n const columnIndex = columns.findIndex((column) => column.id === columnId)\n if (rowIndex < 0 || columnIndex < 0) return\n\n if (event.key === 'Enter') {\n const row = visibleRows[rowIndex]\n const column = columns[columnIndex]\n if (!row || !column) return\n if (!onUpdate || column.editable === false || row.readOnly === true) return\n if (column.kind === 'boolean') return\n if (!isRecordGridCellApplicable(column, row.values)) return\n event.preventDefault()\n beginEdit(row, column)\n return\n }\n if (!NAVIGATION_KEYS.has(event.key)) return\n event.preventDefault()\n\n let nextRow = rowIndex\n let nextColumn = columnIndex\n if (event.key === 'ArrowUp') nextRow = clamp(rowIndex - 1, visibleRows.length - 1)\n if (event.key === 'ArrowDown') nextRow = clamp(rowIndex + 1, visibleRows.length - 1)\n if (event.key === 'ArrowLeft') nextColumn = clamp(columnIndex - 1, columns.length - 1)\n if (event.key === 'ArrowRight') nextColumn = clamp(columnIndex + 1, columns.length - 1)\n if (event.key === 'Home') nextColumn = 0\n if (event.key === 'End') nextColumn = columns.length - 1\n\n const destinationRow = visibleRows[nextRow]\n const destinationColumn = columns[nextColumn]\n if (!destinationRow || !destinationColumn) return\n focusCell(destinationRow.id, destinationColumn.id)\n },\n [beginEdit, columns, editing, focusCell, onUpdate, visibleRows],\n )\n\n // `idle` and `loading` render the same busy block — from the reader's\n // side, \"not started\" and \"in flight\" are the same wait\n // (`web-react/async`'s own rule for the same two variants).\n if (state.status === 'idle' || state.status === 'loading') {\n return (\n <div className={`space-y-3 ${className ?? ''}`}>\n {toolbar}\n <div\n role=\"status\"\n aria-busy=\"true\"\n aria-live=\"polite\"\n className=\"space-y-2 rounded-xl border border-card-edge bg-card p-4\"\n >\n <span className=\"sr-only\">Loading {caption}</span>\n {Array.from({ length: Math.max(1, loadingRowCount) }, (_, index) => (\n <div key={index} className=\"h-8 animate-pulse rounded-md bg-secondary\" aria-hidden />\n ))}\n </div>\n </div>\n )\n }\n\n if (state.status === 'error') {\n return (\n <div className={`space-y-3 ${className ?? ''}`}>\n {toolbar}\n <div role=\"alert\" className=\"rounded-xl border border-destructive/40 bg-destructive/10 px-4 py-4\">\n <p className=\"text-sm font-medium text-destructive\">{state.message}</p>\n <button\n type=\"button\"\n onClick={state.retry}\n className=\"mt-3 rounded-md border border-destructive/40 px-3 py-1.5 text-xs font-medium text-destructive transition hover:bg-destructive/10\"\n >\n Try again\n </button>\n </div>\n </div>\n )\n }\n\n const addForm =\n adding && onCreate ? (\n <AddRecordForm\n columns={columns}\n draft={draft}\n setDraft={setDraft}\n errors={draftErrors}\n formError={draftError}\n busy={creating}\n label={addLabel}\n fieldPrefix={fieldPrefix}\n onSubmit={() => void submitDraft()}\n onCancel={() => {\n setAdding(false)\n resetDraft()\n }}\n />\n ) : null\n\n if (visibleRows.length === 0) {\n return (\n <div className={`space-y-3 ${className ?? ''}`}>\n {toolbar}\n {addForm ?? (\n <div className=\"rounded-xl border border-dashed border-border px-6 py-10 text-center\">\n <p className=\"text-sm font-medium text-foreground\">{empty.title}</p>\n {empty.description && (\n <p className=\"mx-auto mt-1 max-w-md text-sm text-muted-foreground\">{empty.description}</p>\n )}\n <div className=\"mt-4 flex flex-wrap items-center justify-center gap-2\">\n {empty.action &&\n (isValidElement(empty.action) ? (\n empty.action\n ) : (\n <button\n type=\"button\"\n onClick={(empty.action as AsyncEmptyAction).onClick}\n className=\"rounded-md border border-border px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent\"\n >\n {(empty.action as AsyncEmptyAction).label}\n </button>\n ))}\n {onCreate && (\n <button\n type=\"button\"\n onClick={openAdd}\n className=\"rounded-md border border-border px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent\"\n >\n {addLabel}\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n )\n }\n\n const hasFooter = columns.some((column) => column.footerValue !== undefined)\n const columnSpan = columns.length + (onDelete ? 1 : 0)\n\n return (\n <div className={`space-y-3 ${className ?? ''}`}>\n {toolbar}\n <div className=\"overflow-x-auto rounded-xl border border-card-edge bg-card\">\n <table\n role=\"grid\"\n aria-label={caption}\n className=\"w-full border-collapse text-left text-sm\"\n onKeyDown={handleGridKeyDown}\n >\n <thead>\n <tr role=\"row\" className=\"border-b border-border text-[11px] uppercase tracking-wide text-muted-foreground\">\n {columns.map((column) => (\n <th\n key={column.id}\n role=\"columnheader\"\n scope=\"col\"\n className={`px-3 py-2 font-medium ${alignmentClass(column)}`}\n >\n {column.header}\n </th>\n ))}\n {onDelete && (\n <th role=\"columnheader\" scope=\"col\" className=\"w-px px-3 py-2 font-medium\">\n <span className=\"sr-only\">Row actions</span>\n </th>\n )}\n </tr>\n </thead>\n <tbody>\n {visibleRows.map((row) => {\n const rowLabel = recordGridRowLabel(columns, row)\n const pending = row.id in pendingRows\n const rowError = rowErrors[row.id]\n return (\n <Fragment key={row.id}>\n <tr role=\"row\" aria-busy={pending} className={`border-b border-border ${pending ? 'opacity-60' : ''}`}>\n {columns.map((column) => {\n const key = cellKey(row.id, column.id)\n const applicable = isRecordGridCellApplicable(column, row.values)\n const editable =\n onUpdate !== undefined && column.editable !== false && row.readOnly !== true && applicable\n const value = row.values[column.id] ?? null\n const isEditing = editing?.rowId === row.id && editing.columnId === column.id\n const cellError = cellErrors[key]\n const active =\n activeFocus === null\n ? row.id === visibleRows[0]?.id && column.id === columns[0]?.id\n : activeFocus.rowId === row.id && activeFocus.columnId === column.id\n const source = row.sources?.[column.id]\n const errorId = `${fieldPrefix}-cell-error-${row.id}-${column.id}`\n\n if (isEditing && editable) {\n return (\n <td key={column.id} role=\"gridcell\" className={`px-3 py-1.5 ${alignmentClass(column)}`}>\n <CellEditor\n column={column}\n rowLabel={rowLabel}\n text={editing.text}\n invalid={cellError !== undefined}\n describedBy={cellError === undefined ? undefined : errorId}\n onText={(text) => setEditing({ rowId: row.id, columnId: column.id, text })}\n onCommit={(text) => void commitEdit(row, column, text)}\n onCancel={() => cancelEdit(row, column)}\n />\n {cellError !== undefined && (\n <p id={errorId} role=\"alert\" className=\"mt-1 text-[11px] leading-snug text-destructive\">\n {cellError}\n </p>\n )}\n </td>\n )\n }\n\n if (column.kind === 'boolean' && editable) {\n return (\n <td key={column.id} role=\"gridcell\" className={`px-3 py-2 ${alignmentClass(column)}`}>\n <input\n type=\"checkbox\"\n checked={value === true}\n aria-label={`${column.header}, ${rowLabel}`}\n data-record-grid-row={row.id}\n data-record-grid-column={column.id}\n tabIndex={active ? 0 : -1}\n ref={(node) => {\n cellRefs.current.set(key, node)\n }}\n onFocus={() => setFocus({ rowId: row.id, columnId: column.id })}\n onChange={(event) => void applyCellWrite(row, column, event.target.checked)}\n className=\"h-4 w-4 rounded border-border accent-primary\"\n />\n </td>\n )\n }\n\n const display = applicable ? formatRecordGridValue(column, value, locale) : ''\n return (\n <td\n key={column.id}\n role=\"gridcell\"\n aria-readonly={editable ? undefined : true}\n data-record-grid-row={row.id}\n data-record-grid-column={column.id}\n tabIndex={active ? 0 : -1}\n ref={(node) => {\n cellRefs.current.set(key, node)\n }}\n onFocus={() => setFocus({ rowId: row.id, columnId: column.id })}\n onClick={() => {\n if (editable) beginEdit(row, column)\n }}\n className={`px-3 py-2 outline-none focus:ring-2 focus:ring-inset focus:ring-primary/50 ${alignmentClass(\n column,\n )} ${editable ? 'cursor-text' : ''}`}\n >\n <span className=\"inline-flex max-w-full items-center gap-1.5\">\n <span className={display === '' ? 'text-muted-foreground' : 'truncate text-foreground'}>\n {display === '' ? (applicable ? '—' : 'n/a') : display}\n </span>\n {source && (\n <SourceMarker\n panelId={`${fieldPrefix}-source-${row.id}-${column.id}`}\n columnHeader={column.header}\n rowLabel={rowLabel}\n source={source}\n open={openSource === key}\n onToggle={() => setOpenSource((current) => (current === key ? null : key))}\n />\n )}\n </span>\n </td>\n )\n })}\n {onDelete && (\n <td role=\"gridcell\" className=\"px-3 py-2 text-right\">\n {row.readOnly === true ? null : confirmDelete === row.id ? (\n <span className=\"inline-flex items-center gap-1.5\">\n <button\n type=\"button\"\n aria-label={`Confirm delete ${rowLabel}`}\n onClick={() => void performDelete(row)}\n className=\"rounded-md bg-destructive/10 px-2 py-1 text-xs font-medium text-destructive transition hover:bg-destructive/20\"\n >\n Delete\n </button>\n <button\n type=\"button\"\n aria-label={`Keep ${rowLabel}`}\n onClick={() => setConfirmDelete(null)}\n className=\"rounded-md border border-border px-2 py-1 text-xs font-medium text-muted-foreground transition hover:bg-accent\"\n >\n Cancel\n </button>\n </span>\n ) : (\n <button\n type=\"button\"\n aria-label={`Delete ${rowLabel}`}\n onClick={() => setConfirmDelete(row.id)}\n className=\"rounded-md p-1.5 text-muted-foreground transition hover:bg-destructive/10 hover:text-destructive\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n className=\"h-3.5 w-3.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <polyline points=\"3 6 5 6 21 6\" />\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n </svg>\n </button>\n )}\n </td>\n )}\n </tr>\n {rowError !== undefined && (\n <tr role=\"row\" className=\"border-b border-border\">\n <td role=\"gridcell\" colSpan={columnSpan} className=\"px-3 pb-2\">\n <p role=\"alert\" className=\"rounded-md bg-destructive/10 px-2.5 py-1.5 text-xs text-destructive\">\n {rowError}\n </p>\n </td>\n </tr>\n )}\n </Fragment>\n )\n })}\n </tbody>\n {hasFooter && (\n <tfoot>\n <tr role=\"row\" className=\"border-t-2 border-border\">\n {columns.map((column) => (\n <td\n key={column.id}\n role=\"gridcell\"\n className={`px-3 py-2 text-sm font-semibold text-foreground ${alignmentClass(column)}`}\n >\n {column.footerValue ? formatRecordGridValue(column, column.footerValue(visibleRows), locale) : ''}\n </td>\n ))}\n {onDelete && <td role=\"gridcell\" />}\n </tr>\n </tfoot>\n )}\n </table>\n </div>\n\n {onCreate &&\n (addForm ?? (\n <button\n type=\"button\"\n onClick={openAdd}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n className=\"h-3.5 w-3.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n {addLabel}\n </button>\n ))}\n </div>\n )\n}\n\ninterface CellEditorProps {\n column: RecordGridColumn\n rowLabel: string\n text: string\n invalid: boolean\n describedBy?: string\n onText: (text: string) => void\n onCommit: (text: string) => void\n onCancel: () => void\n}\n\n/** The in-cell control for one edit. Enter commits, Escape cancels, blur\n * commits — the editor never disappears without deciding. */\nfunction CellEditor({ column, rowLabel, text, invalid, describedBy, onText, onCommit, onCancel }: CellEditorProps) {\n const shared = {\n 'aria-label': `${column.header}, ${rowLabel}`,\n 'aria-invalid': invalid ? true : undefined,\n 'aria-describedby': describedBy,\n autoFocus: true,\n className: INPUT_CLASS,\n }\n\n if (column.kind === 'select') {\n return (\n <select\n {...shared}\n value={text}\n onChange={(event) => {\n onText(event.target.value)\n onCommit(event.target.value)\n }}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n onCancel()\n }\n }}\n onBlur={() => onCommit(text)}\n >\n <option value=\"\">—</option>\n {column.options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n )\n }\n\n const keyDown = (event: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n const multiline = column.kind === 'text' && column.multiline === true\n if (event.key === 'Enter' && !multiline) {\n event.preventDefault()\n onCommit(text)\n return\n }\n if (event.key === 'Escape') {\n event.preventDefault()\n onCancel()\n }\n }\n\n if (column.kind === 'text' && column.multiline === true) {\n return (\n <textarea\n {...shared}\n rows={3}\n value={text}\n onChange={(event) => onText(event.target.value)}\n onKeyDown={keyDown}\n onBlur={() => onCommit(text)}\n />\n )\n }\n\n return (\n <input\n {...shared}\n type={column.kind === 'date' ? 'date' : 'text'}\n inputMode={column.kind === 'number' || column.kind === 'currency' ? 'decimal' : undefined}\n value={text}\n onChange={(event) => onText(event.target.value)}\n onKeyDown={keyDown}\n onBlur={() => onCommit(text)}\n />\n )\n}\n\ninterface SourceMarkerProps {\n panelId: string\n columnHeader: string\n rowLabel: string\n source: RecordGridCellSource\n open: boolean\n onToggle: () => void\n}\n\n/**\n * The per-cell provenance affordance: a marker that opens the quote, the\n * source's name, and a link to it.\n *\n * Renders its panel through `PopoverSurface` (not an in-place `absolute`\n * span): the grid is a scrollable table by construction — `overflow-x-auto`/\n * `overflow-y-auto` on the scroll region is the whole reason `RecordGrid`\n * stays usable with many columns/rows — and that scroll container clips every\n * positioned descendant whose containing block sits inside it exactly the way\n * the composer's control rail clipped the model/thinking menus (see AGENTS.md\n * \"UI chrome ownership (picker canon)\"). `open` stays parent-owned (only one\n * marker across the grid may be open at a time); `usePopover` never calls\n * `setOpen(true)` itself — its listeners only run while `open` is already\n * true — so translating its `setOpen(false)` into the existing `onToggle`\n * flip is safe.\n */\nfunction SourceMarker({ panelId, columnHeader, rowLabel, source, open, onToggle }: SourceMarkerProps) {\n // An omitted basis is the DEFAULT path every first integration takes, so it\n // must resolve to the weakest claim, not the strongest. `extracted` (and\n // `source` before the rename) told the reader the figure was read out of a\n // document the caller never named — a factual claim about a document that may\n // not exist. `asserted` is the union's own \"nothing outside the model behind\n // it\", which is exactly what a caller who stated no basis has established.\n const basis: RecordGridSourceBasis = source.basis ?? 'asserted'\n const setOpen = useCallback(\n (next: boolean) => {\n if (!next) onToggle()\n },\n [onToggle],\n )\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen)\n return (\n <span ref={containerRef} className=\"relative inline-flex\">\n <button\n type=\"button\"\n {...triggerProps}\n aria-label={`Source for ${columnHeader}, ${rowLabel}`}\n aria-controls={open ? panelId : undefined}\n title={BASIS_TITLES[basis]}\n onClick={(event) => {\n event.stopPropagation()\n onToggle()\n }}\n className={`inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full border ${BASIS_TONES[basis]}`}\n >\n <svg\n viewBox=\"0 0 24 24\"\n className=\"h-2.5 w-2.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n aria-hidden\n >\n <path d=\"M9 8h6M9 12h6M9 16h3\" />\n </svg>\n </button>\n <PopoverSurface\n open={open}\n id={panelId}\n role=\"note\"\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={`w-64 rounded-lg border border-card-edge bg-popover p-3 text-left ${OVERLAY_SHADOW}`}\n >\n {source.quote && (\n <span className=\"block border-l-2 border-primary/50 pl-2 text-xs italic leading-snug text-foreground\">\n “{source.quote}”\n </span>\n )}\n <span className=\"mt-2 block text-[11px] text-muted-foreground\">\n {source.label ?? 'Source'}\n {source.locator ? ` · ${source.locator}` : ''}\n {` · ${BASIS_TITLES[basis]}`}\n </span>\n {source.href && (\n <a\n href={source.href}\n target=\"_blank\"\n rel=\"noreferrer\"\n onClick={(event) => event.stopPropagation()}\n className=\"mt-1.5 inline-block text-[11px] font-medium text-primary underline-offset-2 hover:underline\"\n >\n Open source\n </a>\n )}\n </PopoverSurface>\n </span>\n )\n}\n\ninterface AddRecordFormProps {\n columns: readonly RecordGridColumn[]\n draft: Record<string, RecordGridValue>\n setDraft: (next: Record<string, RecordGridValue>) => void\n errors: Readonly<Record<string, string>>\n formError: string | null\n busy: boolean\n label: string\n fieldPrefix: string\n onSubmit: () => void\n onCancel: () => void\n}\n\n/** The inline add form. Every control is labelled, every rejection names its\n * field, and a column whose `dependsOn` is unsatisfied is not rendered — the\n * nested sub-form case. */\nfunction AddRecordForm({\n columns,\n draft,\n setDraft,\n errors,\n formError,\n busy,\n label,\n fieldPrefix,\n onSubmit,\n onCancel,\n}: AddRecordFormProps) {\n const groups = useMemo(() => groupColumns(columns), [columns])\n\n return (\n <form\n noValidate\n aria-label={label}\n onSubmit={(event) => {\n event.preventDefault()\n onSubmit()\n }}\n className=\"space-y-4 rounded-xl border border-card-edge bg-card p-4\"\n >\n <h3 className=\"text-sm font-semibold text-foreground\">{label}</h3>\n {formError !== null && (\n <p role=\"alert\" className=\"rounded-md bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {formError}\n </p>\n )}\n {groups.map((group) => {\n const fields = group.columns.filter((column) => isRecordGridCellApplicable(column, draft))\n if (fields.length === 0) return null\n return (\n <fieldset\n key={group.label ?? '_'}\n className={group.label === null ? 'min-w-0' : 'min-w-0 rounded-lg border border-card-edge p-3'}\n >\n {group.label !== null && (\n <legend className=\"px-1 text-xs font-medium text-muted-foreground\">{group.label}</legend>\n )}\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {fields.map((column) => {\n const fieldId = `${fieldPrefix}-${column.id}`\n const errorId = `${fieldId}-error`\n const message = errors[column.id]\n return (\n <div\n key={column.id}\n className={column.kind === 'text' && column.multiline === true ? 'sm:col-span-2' : ''}\n >\n <label htmlFor={fieldId} className=\"mb-1 block text-xs font-medium text-muted-foreground\">\n {column.header}\n {column.required === true && <span className=\"ml-0.5 text-destructive\">*</span>}\n </label>\n <DraftField\n column={column}\n id={fieldId}\n value={draft[column.id] ?? null}\n invalid={message !== undefined}\n describedBy={message === undefined ? undefined : errorId}\n onValue={(next) => setDraft({ ...draft, [column.id]: next })}\n />\n {column.hint && <p className=\"mt-1 text-[11px] text-muted-foreground\">{column.hint}</p>}\n {message !== undefined && (\n <p id={errorId} role=\"alert\" className=\"mt-1 text-[11px] text-destructive\">\n {message}\n </p>\n )}\n </div>\n )\n })}\n </div>\n </fieldset>\n )\n })}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"submit\"\n disabled={busy}\n className=\"rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground transition hover:bg-primary/90 disabled:opacity-50\"\n >\n {busy ? 'Saving…' : 'Save'}\n </button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"rounded-md border border-border px-3 py-1.5 text-sm font-medium text-muted-foreground transition hover:bg-accent\"\n >\n Cancel\n </button>\n </div>\n </form>\n )\n}\n\ninterface DraftFieldProps {\n column: RecordGridColumn\n id: string\n value: RecordGridValue\n invalid: boolean\n describedBy?: string\n onValue: (value: RecordGridValue) => void\n}\n\n/** One labelled control in the add form. A half-typed number is held verbatim\n * rather than coerced mid-keystroke; submit is where it is refused with a\n * reason. */\nfunction DraftField({ column, id, value, invalid, describedBy, onValue }: DraftFieldProps) {\n const shared = {\n id,\n 'aria-invalid': invalid ? true : undefined,\n 'aria-describedby': describedBy,\n }\n\n if (column.kind === 'boolean') {\n return (\n <input\n {...shared}\n type=\"checkbox\"\n checked={value === true}\n onChange={(event) => onValue(event.target.checked)}\n className=\"h-4 w-4 rounded border-border accent-primary\"\n />\n )\n }\n\n if (column.kind === 'select') {\n return (\n <select\n {...shared}\n className={INPUT_CLASS}\n value={typeof value === 'string' ? value : ''}\n onChange={(event) => onValue(event.target.value === '' ? null : event.target.value)}\n >\n <option value=\"\">—</option>\n {column.options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n )\n }\n\n if (column.kind === 'text' && column.multiline === true) {\n return (\n <textarea\n {...shared}\n className={INPUT_CLASS}\n rows={3}\n value={typeof value === 'string' ? value : ''}\n onChange={(event) => onValue(event.target.value === '' ? null : event.target.value)}\n />\n )\n }\n\n if (column.kind === 'number' || column.kind === 'currency') {\n return (\n <input\n {...shared}\n className={INPUT_CLASS}\n type=\"text\"\n inputMode=\"decimal\"\n value={value === null ? '' : String(value)}\n onChange={(event) => {\n const raw = event.target.value\n if (raw.trim() === '') {\n onValue(null)\n return\n }\n const parsed = readRecordGridCell(column, raw)\n onValue(parsed.succeeded ? parsed.value : raw)\n }}\n />\n )\n }\n\n return (\n <input\n {...shared}\n className={INPUT_CLASS}\n type={column.kind === 'date' ? 'date' : 'text'}\n value={typeof value === 'string' ? value : ''}\n onChange={(event) => onValue(event.target.value === '' ? null : event.target.value)}\n />\n )\n}\n","/**\n * The pure half of the editable record grid: the typed column vocabulary, the\n * per-cell parse/validate rules, display + editor formatting, and the\n * optimistic overlay a caller's rows are projected through.\n *\n * Zero React, zero DOM — a product can validate a row on a worker before it\n * ever reaches storage, and the component in `./record-grid` renders exactly\n * what these functions decide.\n *\n * Every domain word is a caller parameter: the module knows no column names,\n * no currencies, no option sets. What it owns is the mechanism four verticals\n * each re-derived — typed cells, an error a person can act on, and an\n * optimistic edit that can be taken back.\n */\n\nimport type { ProvenanceBasis } from './provenance-model'\n\n/** The value one cell can hold. `null` is \"no value on file\". */\nexport type RecordGridValue = string | number | boolean | null\n\n/** Typed outcome for one cell. Callers MUST inspect `succeeded` before reading\n * `value`; nothing here throws. */\nexport type RecordGridCellOutcome =\n | { succeeded: true; value: RecordGridValue }\n | { succeeded: false; error: string }\n\n/** Typed outcome for a whole row of inputs (the add form). `cellErrors` is\n * keyed by column id so each control can render its own message. */\nexport type RecordGridRowOutcome =\n | { succeeded: true; value: Record<string, RecordGridValue> }\n | { succeeded: false; error: string; cellErrors: Readonly<Record<string, string>> }\n\n/** Build a cell success outcome. */\nexport function recordGridOk(value: RecordGridValue): RecordGridCellOutcome {\n return { succeeded: true, value }\n}\n\n/** Build a cell failure outcome carrying the message shown next to the cell. */\nexport function recordGridFail(error: string): RecordGridCellOutcome {\n return { succeeded: false, error }\n}\n\n/**\n * How a value came to sit in a cell. Rendered as the provenance tone.\n *\n * A type alias of `./provenance-model`'s `ProvenanceBasis`, not a lookalike:\n * two vocabularies for the same concept — a grid cell's origin — shipped one\n * day apart and would have drifted the moment either one added a value. The\n * grid gains `asserted` for free (a cell an agent claimed with nothing behind\n * it), where the caller previously had no way to say that.\n */\nexport type RecordGridSourceBasis = ProvenanceBasis\n\n/**\n * Where one cell's value came from. Optional on every row — a grid over data\n * with no lineage renders identically without it.\n */\nexport interface RecordGridCellSource {\n /** The text in the source that supports this value. */\n quote?: string\n /** Human name of the source document, message, or system. */\n label?: string\n /** Click-through to the source. */\n href?: string\n /** Position inside the source: a page, a line, a span — the caller's words. */\n locator?: string\n /** How the value got here. Absent renders as `asserted` — the weakest claim\n * in the union — because a caller that stated no basis has established\n * nothing about a document, and an omission must never read as one. */\n basis?: RecordGridSourceBasis\n}\n\n/** One option of a `select` column. */\nexport interface RecordGridSelectOption {\n value: string\n label: string\n}\n\n/** A cell is only editable, rendered, and validated when the column it depends\n * on holds `equals`. This is how a nested sub-form (a vesting schedule behind\n * a \"has vesting\" toggle) stays a set of flat, individually-typed columns. */\nexport interface RecordGridDependency {\n column: string\n equals: RecordGridValue\n}\n\n/** Fields every column kind carries. */\nexport interface RecordGridColumnBase {\n /** Key into a row's `values` bag. */\n id: string\n /** Column heading, and the accessible name of every control in the column. */\n header: string\n /** Short hint rendered under the control in the add form. */\n hint?: string\n /** An empty cell is rejected. */\n required?: boolean\n /** Cells are editable unless this is `false`. */\n editable?: boolean\n /** Cell alignment. Numeric kinds default to `right`. */\n align?: 'left' | 'right'\n /** Groups this column under a labelled sub-form in the add form. */\n group?: string\n /** Only applicable when another column holds a given value. */\n dependsOn?: RecordGridDependency\n /** Extra rule, run after the kind's own checks pass. Return the message to\n * reject with, or `null` to accept. */\n validate?: (value: RecordGridValue) => string | null\n /** Column summary rendered in the footer row. */\n footerValue?: (rows: readonly RecordGridRow[]) => RecordGridValue\n}\n\n/** Free text, optionally length- or pattern-constrained. */\nexport interface RecordGridTextColumn extends RecordGridColumnBase {\n kind: 'text'\n minLength?: number\n maxLength?: number\n pattern?: RegExp\n /** Message when `pattern` rejects. Without it the pattern source is shown. */\n patternMessage?: string\n /** Render a textarea instead of a single-line input. */\n multiline?: boolean\n}\n\n/** A plain number. */\nexport interface RecordGridNumberColumn extends RecordGridColumnBase {\n kind: 'number'\n min?: number\n max?: number\n integer?: boolean\n /** Passed through to the editor's `step`. */\n step?: number\n}\n\n/** A money amount. The currency is a caller parameter — this module bakes no\n * domain value, so a product with two currencies declares two columns. */\nexport interface RecordGridCurrencyColumn extends RecordGridColumnBase {\n kind: 'currency'\n /** ISO 4217 code, e.g. `USD`. */\n currency: string\n min?: number\n max?: number\n /** Fraction digits for display. Defaults to the currency's own. */\n fractionDigits?: number\n}\n\n/** A calendar date held as `YYYY-MM-DD`; no time, no zone. */\nexport interface RecordGridDateColumn extends RecordGridColumnBase {\n kind: 'date'\n /** Earliest accepted date, `YYYY-MM-DD`. */\n min?: string\n /** Latest accepted date, `YYYY-MM-DD`. */\n max?: string\n}\n\n/** One of a closed set of values. */\nexport interface RecordGridSelectColumn extends RecordGridColumnBase {\n kind: 'select'\n options: readonly RecordGridSelectOption[]\n}\n\n/** A checkbox. */\nexport interface RecordGridBooleanColumn extends RecordGridColumnBase {\n kind: 'boolean'\n /** Label for `true`. Defaults to `Yes`. */\n trueLabel?: string\n /** Label for `false`. Defaults to `No`. */\n falseLabel?: string\n}\n\n/** Every column shape the grid renders. */\nexport type RecordGridColumn =\n | RecordGridTextColumn\n | RecordGridNumberColumn\n | RecordGridCurrencyColumn\n | RecordGridDateColumn\n | RecordGridSelectColumn\n | RecordGridBooleanColumn\n\n/** One row: an id, a flat value bag keyed by column id, and optional per-cell\n * provenance. A record-backed product maps its fold output straight onto\n * this — one entry per cell, its quote and link in `sources`. */\nexport interface RecordGridRow {\n id: string\n values: Readonly<Record<string, RecordGridValue>>\n /** Per-cell provenance, keyed by column id. */\n sources?: Readonly<Record<string, RecordGridCellSource>>\n /** No cell in this row may be edited or deleted. */\n readOnly?: boolean\n /** Accessible name for the row's own controls. Falls back to the first text\n * or select column's value, then the row id. */\n label?: string\n}\n\n/** True when the column's dependency (if any) is satisfied by the row's other\n * values. An inapplicable cell is never required, never validated, and never\n * editable. */\nexport function isRecordGridCellApplicable(\n column: RecordGridColumn,\n values: Readonly<Record<string, RecordGridValue>>,\n): boolean {\n const dependency = column.dependsOn\n if (!dependency) return true\n const held = values[dependency.column] ?? null\n return sameRecordGridValue(held, dependency.equals)\n}\n\n/** Value equality across the grid's value union, treating `undefined` as\n * `null` so an absent key and an explicit null never read as a change. */\nexport function sameRecordGridValue(a: RecordGridValue | undefined, b: RecordGridValue | undefined): boolean {\n return Object.is(a ?? null, b ?? null)\n}\n\n// ── parsing ───────────────────────────────────────────────────────────────\n\nconst NUMERIC = /^[+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+)$/\nconst ISO_DATE = /^\\d{4}-\\d{2}-\\d{2}$/\n\n/**\n * A number as a person types it: grouping separators, a leading currency\n * symbol, and accounting parentheses for a negative are all accepted. Anything\n * else is rejected rather than coerced — `12abc` is a typo to correct, not the\n * number 12.\n */\nfunction parseNumericText(raw: string): { empty: true } | { value: number } | { invalid: true } {\n const trimmed = raw.trim()\n if (trimmed === '') return { empty: true }\n const parenthesized = /^\\(.+\\)$/.test(trimmed)\n const body = (parenthesized ? trimmed.slice(1, -1).trim() : trimmed)\n .replace(/[\\s,]/g, '')\n .replace(/^([+-]?)\\p{Sc}/u, '$1')\n if (!NUMERIC.test(body)) return { invalid: true }\n const parsed = Number(body)\n if (!Number.isFinite(parsed)) return { invalid: true }\n return { value: parenthesized ? -parsed : parsed }\n}\n\n/** True when `text` is a real calendar date in `YYYY-MM-DD`. */\nfunction isCalendarDate(text: string): boolean {\n if (!ISO_DATE.test(text)) return false\n const [year, month, day] = text.split('-').map((part) => Number(part))\n if (month === undefined || day === undefined || year === undefined) return false\n if (month < 1 || month > 12 || day < 1) return false\n const stamp = Date.UTC(year, month - 1, day)\n const date = new Date(stamp)\n return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day\n}\n\n/**\n * Turn what an editor control produced into a typed value. Syntax only —\n * range, length, and membership are {@link validateRecordGridCell}'s job.\n */\nexport function parseRecordGridInput(column: RecordGridColumn, raw: string): RecordGridCellOutcome {\n switch (column.kind) {\n case 'text': {\n const trimmed = raw.trim()\n return recordGridOk(trimmed === '' ? null : trimmed)\n }\n case 'select': {\n const trimmed = raw.trim()\n return recordGridOk(trimmed === '' ? null : trimmed)\n }\n case 'boolean': {\n const trimmed = raw.trim().toLowerCase()\n if (trimmed === '') return recordGridOk(null)\n if (trimmed === 'true') return recordGridOk(true)\n if (trimmed === 'false') return recordGridOk(false)\n return recordGridFail(`${column.header} must be true or false — got “${raw}”.`)\n }\n case 'date': {\n const trimmed = raw.trim()\n if (trimmed === '') return recordGridOk(null)\n if (!isCalendarDate(trimmed)) {\n return recordGridFail(`${column.header} must be a date in YYYY-MM-DD form — got “${raw}”.`)\n }\n return recordGridOk(trimmed)\n }\n case 'number':\n case 'currency': {\n const parsed = parseNumericText(raw)\n if ('empty' in parsed) return recordGridOk(null)\n if ('invalid' in parsed) return recordGridFail(`${column.header} must be a number — got “${raw}”.`)\n return recordGridOk(parsed.value)\n }\n }\n}\n\n// ── validation ────────────────────────────────────────────────────────────\n\nfunction describeOptions(column: RecordGridSelectColumn): string {\n return column.options.map((option) => option.label).join(', ')\n}\n\n/**\n * Check one already-typed value against its column. Returns the value the grid\n * should store (empty text normalizes to `null`) or the message a person can\n * act on.\n */\nexport function validateRecordGridCell(column: RecordGridColumn, value: RecordGridValue): RecordGridCellOutcome {\n const normalized = value === '' ? null : value\n if (normalized === null) {\n if (column.required) return recordGridFail(`${column.header} is required.`)\n const custom = column.validate?.(null)\n return custom === undefined || custom === null ? recordGridOk(null) : recordGridFail(custom)\n }\n\n switch (column.kind) {\n case 'text': {\n if (typeof normalized !== 'string') return recordGridFail(`${column.header} must be text.`)\n if (column.minLength !== undefined && normalized.length < column.minLength) {\n return recordGridFail(`${column.header} must be at least ${column.minLength} characters — got ${normalized.length}.`)\n }\n if (column.maxLength !== undefined && normalized.length > column.maxLength) {\n return recordGridFail(`${column.header} must be at most ${column.maxLength} characters — got ${normalized.length}.`)\n }\n if (column.pattern && !column.pattern.test(normalized)) {\n return recordGridFail(column.patternMessage ?? `${column.header} does not match ${column.pattern.source}.`)\n }\n break\n }\n case 'number':\n case 'currency': {\n if (typeof normalized !== 'number' || !Number.isFinite(normalized)) {\n return recordGridFail(`${column.header} must be a number.`)\n }\n if (column.kind === 'number' && column.integer === true && !Number.isInteger(normalized)) {\n return recordGridFail(`${column.header} must be a whole number — got ${normalized}.`)\n }\n if (column.min !== undefined && normalized < column.min) {\n return recordGridFail(`${column.header} must be at least ${column.min} — got ${normalized}.`)\n }\n if (column.max !== undefined && normalized > column.max) {\n return recordGridFail(`${column.header} must be at most ${column.max} — got ${normalized}.`)\n }\n break\n }\n case 'date': {\n if (typeof normalized !== 'string' || !isCalendarDate(normalized)) {\n return recordGridFail(`${column.header} must be a date in YYYY-MM-DD form.`)\n }\n if (column.min !== undefined && normalized < column.min) {\n return recordGridFail(`${column.header} must be on or after ${column.min} — got ${normalized}.`)\n }\n if (column.max !== undefined && normalized > column.max) {\n return recordGridFail(`${column.header} must be on or before ${column.max} — got ${normalized}.`)\n }\n break\n }\n case 'select': {\n if (typeof normalized !== 'string') return recordGridFail(`${column.header} must be one of: ${describeOptions(column)}.`)\n if (!column.options.some((option) => option.value === normalized)) {\n return recordGridFail(`${column.header} must be one of: ${describeOptions(column)} — got “${normalized}”.`)\n }\n break\n }\n case 'boolean': {\n if (typeof normalized !== 'boolean') return recordGridFail(`${column.header} must be true or false.`)\n break\n }\n }\n\n const custom = column.validate?.(normalized)\n if (custom !== undefined && custom !== null) return recordGridFail(custom)\n return recordGridOk(normalized)\n}\n\n/** Parse editor text and validate it in one step — what a committing cell\n * editor calls. */\nexport function readRecordGridCell(column: RecordGridColumn, raw: string): RecordGridCellOutcome {\n const parsed = parseRecordGridInput(column, raw)\n if (!parsed.succeeded) return parsed\n return validateRecordGridCell(column, parsed.value)\n}\n\n/**\n * Validate a whole value bag against the columns. Inapplicable cells (an\n * unsatisfied `dependsOn`) are forced to `null` rather than carried, so a\n * sub-form the user turned off cannot smuggle stale values into a write.\n */\nexport function validateRecordGridRow(\n columns: readonly RecordGridColumn[],\n values: Readonly<Record<string, RecordGridValue>>,\n): RecordGridRowOutcome {\n const accepted: Record<string, RecordGridValue> = {}\n const cellErrors: Record<string, string> = {}\n let firstError: string | null = null\n\n for (const column of columns) {\n if (!isRecordGridCellApplicable(column, values)) {\n accepted[column.id] = null\n continue\n }\n const outcome = validateRecordGridCell(column, values[column.id] ?? null)\n if (outcome.succeeded) {\n accepted[column.id] = outcome.value\n continue\n }\n cellErrors[column.id] = outcome.error\n if (firstError === null) firstError = outcome.error\n }\n\n if (firstError !== null) {\n const count = Object.keys(cellErrors).length\n const error = count === 1 ? firstError : `${count} fields need attention. ${firstError}`\n return { succeeded: false, error, cellErrors }\n }\n return { succeeded: true, value: accepted }\n}\n\n// ── formatting ────────────────────────────────────────────────────────────\n\n/** Display text for a cell. `null` renders as the empty string; the component\n * decides what a missing value looks like. */\nexport function formatRecordGridValue(\n column: RecordGridColumn,\n value: RecordGridValue,\n locale?: string,\n): string {\n if (value === null || value === '') return ''\n switch (column.kind) {\n case 'currency': {\n if (typeof value !== 'number') return String(value)\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: column.currency,\n ...(column.fractionDigits === undefined\n ? {}\n : { minimumFractionDigits: column.fractionDigits, maximumFractionDigits: column.fractionDigits }),\n }).format(value)\n }\n case 'number': {\n if (typeof value !== 'number') return String(value)\n return new Intl.NumberFormat(locale).format(value)\n }\n case 'date': {\n if (typeof value !== 'string' || !isCalendarDate(value)) return String(value)\n return new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeZone: 'UTC' }).format(\n new Date(`${value}T00:00:00Z`),\n )\n }\n case 'select': {\n const option = column.options.find((candidate) => candidate.value === value)\n return option ? option.label : String(value)\n }\n case 'boolean': {\n if (typeof value !== 'boolean') return String(value)\n return value ? (column.trueLabel ?? 'Yes') : (column.falseLabel ?? 'No')\n }\n case 'text':\n return String(value)\n }\n}\n\n/** The text an editor control starts with — the raw value, never the formatted\n * one, so committing an untouched cell is a no-op. */\nexport function recordGridEditorText(column: RecordGridColumn, value: RecordGridValue): string {\n if (value === null) return ''\n if (column.kind === 'boolean') return value === true ? 'true' : 'false'\n return String(value)\n}\n\n/** Accessible name for a row's own controls. */\nexport function recordGridRowLabel(columns: readonly RecordGridColumn[], row: RecordGridRow): string {\n if (row.label !== undefined && row.label !== '') return row.label\n for (const column of columns) {\n if (column.kind !== 'text' && column.kind !== 'select') continue\n const value = row.values[column.id]\n if (typeof value === 'string' && value !== '') return formatRecordGridValue(column, value)\n }\n return row.id\n}\n\n/** Sum a numeric column over the rows that hold a number. Rows with no value\n * are absent from the sum, not zero — a total over three of five filled cells\n * is the total of what is on file. */\nexport function sumRecordGridColumn(rows: readonly RecordGridRow[], columnId: string): number {\n let total = 0\n for (const row of rows) {\n const value = row.values[columnId]\n if (typeof value === 'number' && Number.isFinite(value)) total += value\n }\n return total\n}\n\n// ── optimistic overlay ────────────────────────────────────────────────────\n\n/**\n * Edits the grid has applied locally but the caller's `rows` prop has not yet\n * caught up with. Every field is what rollback removes: drop the entry and the\n * caller's own data shows through again.\n */\nexport interface RecordGridOverlay {\n /** rowId → columnId → optimistic value. */\n updates: Readonly<Record<string, Readonly<Record<string, RecordGridValue>>>>\n /** Rows created locally, in insertion order. */\n created: readonly RecordGridRow[]\n /** Row ids removed locally. */\n removed: readonly string[]\n}\n\n/** An overlay holding nothing. */\nexport const EMPTY_RECORD_GRID_OVERLAY: RecordGridOverlay = { updates: {}, created: [], removed: [] }\n\n/** The rows to render: caller rows minus local deletes, with local cell edits\n * applied, then locally-created rows. */\nexport function projectRecordGridRows(\n rows: readonly RecordGridRow[],\n overlay: RecordGridOverlay,\n): RecordGridRow[] {\n const removed = new Set(overlay.removed)\n const projected: RecordGridRow[] = []\n for (const row of rows) {\n if (removed.has(row.id)) continue\n const patch = overlay.updates[row.id]\n projected.push(patch === undefined ? row : { ...row, values: { ...row.values, ...patch } })\n }\n for (const row of overlay.created) {\n if (removed.has(row.id)) continue\n // Same treatment as a caller row: a draft the user edited before the\n // server adopted it must render what they typed, not the value the create\n // went out with.\n const patch = overlay.updates[row.id]\n projected.push(patch === undefined ? row : { ...row, values: { ...row.values, ...patch } })\n }\n return projected\n}\n\n/** Record one optimistic cell edit. */\nexport function withRecordGridUpdate(\n overlay: RecordGridOverlay,\n rowId: string,\n columnId: string,\n value: RecordGridValue,\n): RecordGridOverlay {\n const rowPatch = { ...(overlay.updates[rowId] ?? {}), [columnId]: value }\n return { ...overlay, updates: { ...overlay.updates, [rowId]: rowPatch } }\n}\n\n/** Take back one optimistic cell edit — the rollback path. */\nexport function withoutRecordGridUpdate(\n overlay: RecordGridOverlay,\n rowId: string,\n columnId: string,\n): RecordGridOverlay {\n const rowPatch = overlay.updates[rowId]\n if (rowPatch === undefined || !(columnId in rowPatch)) return overlay\n const nextPatch: Record<string, RecordGridValue> = {}\n for (const [key, value] of Object.entries(rowPatch)) {\n if (key !== columnId) nextPatch[key] = value\n }\n const updates: Record<string, Readonly<Record<string, RecordGridValue>>> = { ...overlay.updates }\n if (Object.keys(nextPatch).length === 0) delete updates[rowId]\n else updates[rowId] = nextPatch\n return { ...overlay, updates }\n}\n\n/** Adopt a row the writer returned as canonical: for a locally-created row it\n * replaces the draft; for an existing row it replaces the optimistic cells.\n * Either way the draft's pending cell edits go with it — the canonical row IS\n * the answer, and leaving an edit layered over it is how a grid keeps showing\n * a value the server normalized away. */\nexport function withRecordGridServerRow(\n overlay: RecordGridOverlay,\n draftId: string,\n row: RecordGridRow,\n): RecordGridOverlay {\n const createdIndex = overlay.created.findIndex((candidate) => candidate.id === draftId)\n if (createdIndex >= 0) {\n const created = [...overlay.created]\n created[createdIndex] = row\n return { ...overlay, created, updates: withoutRowUpdates(overlay.updates, draftId, row.id) }\n }\n return { ...overlay, updates: { ...overlay.updates, [row.id]: { ...row.values } } }\n}\n\n/** Drop every pending cell edit recorded against these row ids. */\nfunction withoutRowUpdates(\n updates: RecordGridOverlay['updates'],\n ...rowIds: readonly string[]\n): RecordGridOverlay['updates'] {\n const drop = new Set(rowIds)\n const next: Record<string, Readonly<Record<string, RecordGridValue>>> = {}\n let changed = false\n for (const [rowId, patch] of Object.entries(updates)) {\n if (drop.has(rowId)) changed = true\n else next[rowId] = patch\n }\n return changed ? next : updates\n}\n\n/** Record an optimistic create. */\nexport function withRecordGridCreated(overlay: RecordGridOverlay, row: RecordGridRow): RecordGridOverlay {\n return { ...overlay, created: [...overlay.created, row] }\n}\n\n/** Take back an optimistic create — the rollback path. Cell edits made against\n * the draft go with it; the row they applied to no longer exists anywhere. */\nexport function withoutRecordGridCreated(overlay: RecordGridOverlay, rowId: string): RecordGridOverlay {\n const created = overlay.created.filter((row) => row.id !== rowId)\n if (created.length === overlay.created.length) return overlay\n return { ...overlay, created, updates: withoutRowUpdates(overlay.updates, rowId) }\n}\n\n/** Record an optimistic delete. */\nexport function withRecordGridRemoved(overlay: RecordGridOverlay, rowId: string): RecordGridOverlay {\n if (overlay.removed.includes(rowId)) return overlay\n return { ...overlay, removed: [...overlay.removed, rowId] }\n}\n\n/** Take back an optimistic delete — the rollback path. */\nexport function withoutRecordGridRemoved(overlay: RecordGridOverlay, rowId: string): RecordGridOverlay {\n if (!overlay.removed.includes(rowId)) return overlay\n return { ...overlay, removed: overlay.removed.filter((candidate) => candidate !== rowId) }\n}\n\n/**\n * Drop the overlay entries the caller's own rows have caught up with: a cell\n * whose value now matches, a created row now present, a removed row now gone.\n * Without this an overlay would mask every later refresh of the same cell.\n *\n * Returns the SAME overlay object when nothing settled, so a caller can prune\n * on every render without looping.\n */\nexport function pruneRecordGridOverlay(\n rows: readonly RecordGridRow[],\n overlay: RecordGridOverlay,\n): RecordGridOverlay {\n const byId = new Map(rows.map((row) => [row.id, row]))\n const createdIds = new Set(overlay.created.map((row) => row.id))\n let changed = false\n\n const updates: Record<string, Readonly<Record<string, RecordGridValue>>> = {}\n for (const [rowId, patch] of Object.entries(overlay.updates)) {\n const row = byId.get(rowId)\n if (row === undefined) {\n // A draft the caller's rows have not adopted yet is still on screen, so\n // its edits still have a row to apply to. Anything else left the\n // caller's data entirely and the edit has nothing to apply to.\n if (createdIds.has(rowId)) {\n updates[rowId] = patch\n continue\n }\n changed = true\n continue\n }\n const kept: Record<string, RecordGridValue> = {}\n for (const [columnId, value] of Object.entries(patch)) {\n if (sameRecordGridValue(row.values[columnId], value)) changed = true\n else kept[columnId] = value\n }\n if (Object.keys(kept).length > 0) updates[rowId] = kept\n }\n\n const created = overlay.created.filter((row) => {\n const settled = byId.has(row.id)\n if (settled) changed = true\n return !settled\n })\n\n const removed = overlay.removed.filter((rowId) => {\n const settled = !byId.has(rowId)\n if (settled) changed = true\n return !settled\n })\n\n if (!changed) return overlay\n return { updates, created, removed }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAS,aAAAA,aAAW,WAAAC,UAAS,UAAAC,UAAQ,YAAAC,YAAU,YAA4B;AAC3E,SAAS,sBAAsB;;;AChB/B,SAAS,WAAW,QAAQ,gBAAgB;AAcrC,SAAS,gBACd,OACA,cACA,MACA,OAA4B,CAAC,GACrB;AACR,MAAI,SAAS,aAAc,QAAO;AAClC,QAAM,OAAO,KAAK,sBAAsB;AACxC,QAAM,UAAU,KAAK,kBAAkB;AACvC,QAAM,MAAM,KAAK,qBAAqB;AACtC,QAAM,UAAU,eAAe;AAC/B,QAAM,OAAO,KAAK,IAAI,KAAK,OAAO,UAAU,OAAO;AACnD,SAAO,KAAK,IAAI,cAAc,QAAS,OAAO,OAAQ,GAAI;AAC5D;AASO,SAAS,cAAc,QAAgB,SAAkB,MAAoC;AAClG,QAAM,CAAC,EAAE,KAAK,IAAI,SAAS,CAAC;AAC5B,QAAM,WAAW,OAAO,CAAC;AACzB,QAAM,gBAAgB,OAAO,EAAE;AAG/B,MAAI,CAAC,OAAO,WAAW,cAAc,QAAQ,MAAM,GAAG,KAAK,MAAM,SAAS,OAAO,CAAC,CAAC,GAAG;AACpF,aAAS,UAAU;AAAA,EACrB;AACA,gBAAc,UAAU;AACxB,MAAI,CAAC,QAAS,UAAS,UAAU,OAAO;AAExC,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,QAAI,MAAM;AACV,QAAI,OAAsB;AAC1B,UAAM,OAAO,CAAC,MAAc;AAC1B,YAAM,KAAK,QAAQ,OAAO,KAAK,KAAK,IAAI,IAAI,MAAM,GAAG;AACrD,aAAO;AACP,YAAM,YAAY,cAAc,QAAQ;AACxC,UAAI,SAAS,UAAU,WAAW;AAChC,iBAAS,UAAU,gBAAgB,SAAS,SAAS,WAAW,IAAI,IAAI;AACxE,cAAM,CAAC,MAAM,IAAI,CAAC;AAElB,cAAM,sBAAsB,IAAI;AAAA,MAClC;AAAA,IAKF;AACA,UAAM,sBAAsB,IAAI;AAChC,WAAO,MAAM,qBAAqB,GAAG;AAAA,EAEvC,GAAG,CAAC,SAAS,MAAM,CAAC;AAEpB,SAAO,OAAO,MAAM,GAAG,KAAK,MAAM,SAAS,OAAO,CAAC;AACrD;;;AC7EA,SAAS,MAAM,gBAAgB;AAUtB;AADT,SAAS,WAAW,EAAE,OAAO,IAAI,UAAU,GAAmB;AAC5D,SAAO,oBAAC,UAAK,eAAW,MAAC,OAAO,EAAE,SAAS,gBAAgB,OAAO,MAAM,QAAQ,KAAK,GAAG,WAAsB;AAChH;AAEA,IAAM,WAAW,KAAK,YAAY;AAChC,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,kBAAU;AACnC,WAAO,EAAE,SAAS,IAAI,WAA4C;AAAA,EACpE,QAAQ;AACN,WAAO,EAAE,SAAS,WAA4C;AAAA,EAChE;AACF,CAAC;AAEM,SAAS,UAAU,EAAE,OAAO,IAAI,UAAU,GAAmB;AAClE,SACE,oBAAC,YAAS,UAAU,oBAAC,cAAW,MAAY,WAAsB,GAChE,8BAAC,YAAS,MAAY,WAAsB,GAC9C;AAEJ;;;AClCA,SAAS,aAAAC,YAAW,YAAAC,iBAAgC;;;ACqBpD,SAAyB,aAAAC,YAAW,SAAS,UAAAC,SAAQ,YAAAC,iBAAgB;;;ACE9D,SAAS,wBACd,QACuC;AACvC,SAAO,EAAE,WAAW,aAAa,SAAS,WAAW,GAAG,OAAO;AACjE;AAKO,SAAS,yBACd,MACA,OACgD;AAChD,SAAO;AAAA,IACL,SAAS,QAAQ,IAAI;AAAA,IACrB,WAAW,2BAA2B,IAAI;AAAA,IAC1C,GAAG;AAAA,EACL;AACF;AAYO,SAAS,uBACd,QACA,SACa;AACb,MAAI,CAAC,QAAS,QAAO,CAAC;AACtB,QAAM,SAAsB,CAAC;AAC7B,aAAW,SAAS,QAAQ;AAC1B,UAAM,SAAS,QAAQ,MAAM,IAAI;AACjC,QAAI,WAAW,OAAW;AAC1B,QAAI,MAAM,SAAS,UAAU;AAC3B,aAAO,MAAM,IAAI,IAAI,EAAE,UAAU,MAAM,QAAQ,MAAM,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,MAAM,CAAC,EAAE;AAAA,IAC1F,WAAW,MAAM,SAAS,WAAW;AACnC,aAAO,MAAM,IAAI,IAAI,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,EAAE;AAAA,IACpD,OAAO;AACL,aAAO,MAAM,IAAI,IAAI,EAAE,MAAM,OAAO,MAAM,EAAE;AAAA,IAC9C;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,YAAY,OAA6B,QAAqD;AAC5G,QAAM,QAAQ,OAAO,MAAM,IAAI,KAAK,CAAC;AACrC,MAAI,MAAM,SAAS,UAAU;AAC3B,UAAM,SAAU,MAA0B,gBAAgB,OAAO,MAAM,QAAQ,KAAK,IAAI;AACxF,UAAM,SAAS,CAAC,GAAI,MAAM,YAAY,CAAC,GAAI,GAAI,SAAS,CAAC,MAAM,IAAI,CAAC,CAAE;AACtE,QAAI,MAAM,UAAU,QAAQ,OAAQ,QAAO,CAAC,MAAM;AAClD,WAAO,OAAO,SAAS,IAAI,SAAS;AAAA,EACtC;AACA,MAAI,MAAM,SAAS,UAAU;AAC3B,UAAM,SAAS,OAAO,MAAM,IAAI;AAChC,WAAO,MAAM,MAAM,KAAK,KAAK,OAAO,SAAS,MAAM,IAAI,SAAS;AAAA,EAClE;AACA,MAAI,MAAM,SAAS,UAAW,QAAO,MAAM,WAAW,MAAM,SAAS,CAAC,MAAM,SAAS;AACrF,QAAM,OAAO,MAAM,MAAM,KAAK;AAC9B,SAAO,OAAO,OAAO;AACvB;AAIO,SAAS,gBAAgB,QAAgC,QAA6C;AAC3G,QAAM,OAAwB,CAAC;AAC/B,aAAW,SAAS,QAAQ;AAC1B,UAAM,SAAS,YAAY,OAAO,MAAM;AACxC,QAAI,WAAW,MAAM;AACnB,UAAI,MAAM,aAAa,MAAO;AAC9B,aAAO;AAAA,IACT;AACA,SAAK,MAAM,IAAI,IAAI;AAAA,EACrB;AACA,SAAO;AACT;AAQO,SAAS,uBAAuB,QAAwC;AAC7E,SAAO,WAAW,aAAa,WAAW;AAC5C;AAIO,SAAS,eAAe,QAAyC;AACtE,SAAO,OAAO,KAAK,CAAC,UAAU,MAAM,SAAS,QAAQ;AACvD;AAEA,SAAS,YAAY,OAAwB,OAAuB;AAClE,SAAO,MAAM,QAAQ,KAAK,CAAC,WAAW,OAAO,UAAU,KAAK,GAAG,SAAS;AAC1E;AAEA,SAAS,WAAW,OAA6B,QAAyC;AACxF,MAAI,MAAM,SAAS,YAAY,MAAM,QAAQ,MAAM,GAAG;AACpD,WAAO,OAAO,IAAI,CAAC,UAAU,YAAY,OAA0B,KAAK,CAAC,EAAE,KAAK,IAAI;AAAA,EACtF;AACA,MAAI,MAAM,SAAS,UAAW,QAAO,WAAW,OAAO,QAAQ;AAC/D,MAAI,MAAM,SAAS,SAAU,QAAO;AACpC,SAAO,OAAO,MAAM;AACtB;AAIO,SAAS,kBAAkB,aAA8B,MAA+B;AAC7F,QAAM,QAAQ,YAAY,MAAM,KAAK,KAAK;AAC1C,QAAM,OAAO,YAAY,MAAM,KAAK;AACpC,QAAM,UAAU,YAAY,OACzB,IAAI,CAAC,UAAU;AACd,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI,WAAW,OAAW,QAAO;AACjC,WAAO,EAAE,OAAO,MAAM,MAAM,KAAK,GAAG,MAAM,WAAW,OAAO,MAAM,EAAE,KAAK,EAAE;AAAA,EAC7E,CAAC,EACA,OAAO,CAAC,SAAkD,CAAC,CAAC,QAAQ,KAAK,KAAK,SAAS,CAAC;AAE3F,QAAM,OAAO,QAAQ,WAAW,IAAI,QAAQ,CAAC,IAAI;AACjD,QAAM,gBAAgB,OAClB,KAAK,OACL,QAAQ,IAAI,CAAC,SAAS,GAAG,KAAK,SAAS,QAAQ,KAAK,KAAK,IAAI,EAAE,EAAE,KAAK,IAAI;AAE9E,SAAO;AAAA,IACL,qCAAqC,KAAK;AAAA,IAC1C,OAAO,YAAY,IAAI,KAAK;AAAA,IAC5B,cAAc,aAAa;AAAA,EAC7B,EAAE,OAAO,CAAC,SAAyB,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI;AACtD;AAMO,IAAM,gCAAgC;AAEtC,IAAM,qCAAqC;AAqBlD,eAAsB,qBAAqB,KAA4D;AACrG,QAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,MAAI,MAAM;AACR,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,YAAM,UAAU,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,KAAK,IAAI,OAAO,QAC7E,OAAO,OAAO,YAAY,YAAY,OAAO,QAAQ,KAAK,IAAI,OAAO,UACrE;AACJ,UAAI,QAAS,QAAO,EAAE,GAAI,OAAO,OAAO,SAAS,WAAW,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC,GAAI,QAAQ;AAAA,IACnG,QAAQ;AAAA,IAAoC;AAAA,EAC9C;AACA,SAAO,EAAE,SAAS,kBAAkB,IAAI,MAAM,IAAI;AACpD;AA6BO,SAAS,wBACd,KACA,YAAoB,+BACc;AAClC,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,QAAQ;AAAA,MACZ,MAAM,QAAQ,EAAE,IAAI,OAAO,SAAS,OAAO,SAAS,mCAAmC,CAAC;AAAA,MACxF;AAAA,IACF;AACA,UAAM,SAAS,CAAC,WAAoC;AAClD,mBAAa,KAAK;AAGlB,cAAQ,MAAM;AAAA,IAChB;AAIA,YAAQ,QAAQ,EACb,KAAK,GAAG,EACR;AAAA,MAAK;AAAA,MAAQ,CAAC,QACb,OAAO;AAAA,QACL,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,SAAS,eAAe,QAAQ,IAAI,UAAU;AAAA,MAChD,CAAC;AAAA,IACH;AAAA,EACJ,CAAC;AACH;AASO,SAAS,iCAAiC,SAAqE;AACpH,QAAM,YAAY,QAAQ,aAAa;AACvC,SAAO,OAAO,eAAe;AAC3B,UAAM,UAAU,QAAQ,aAAa;AACrC,UAAM,MAAM,OAAO,QAAQ,QAAQ,aAAa,QAAQ,IAAI,UAAU,IAAI,QAAQ;AAClF,UAAM,QAAQ,OAAO,QAAQ,SAAS,aAAa,QAAQ,KAAK,UAAU,IAAI,QAAQ,QAAQ,CAAC;AAC/F,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,kCAAkC,GAAG,SAAS;AAC9F,QAAI;AACF,YAAM,MAAM,MAAM,QAAQ,KAAK;AAAA,QAC7B,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,QAAQ,WAAW;AAAA,QACnB,MAAM,KAAK,UAAU;AAAA,UACnB,GAAG;AAAA,UACH,IAAI,WAAW;AAAA,UACf,SAAS,WAAW;AAAA,UACpB,GAAI,WAAW,OAAO,EAAE,MAAM,WAAW,KAAK,IAAI,CAAC;AAAA,QACrD,CAAC;AAAA,MACH,CAAC;AACD,UAAI,IAAI,GAAI,QAAO,EAAE,IAAI,KAAK;AAC9B,YAAM,UAAU,MAAM,qBAAqB,GAAG;AAC9C,aAAO,EAAE,IAAI,OAAO,SAAS,IAAI,WAAW,KAAK,SAAS,QAAQ,QAAQ;AAAA,IAC5E,SAAS,KAAK;AACZ,UAAI,WAAW,OAAO,SAAS;AAC7B,eAAO,EAAE,IAAI,OAAO,SAAS,OAAO,SAAS,mCAAmC;AAAA,MAClF;AACA,aAAO,EAAE,IAAI,OAAO,SAAS,OAAO,SAAS,eAAe,QAAQ,IAAI,UAAU,8BAA8B;AAAA,IAClH,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AACF;;;ADzPM,SA8EF,UA9EE,OAAAC,MAmGM,YAnGN;AAHN,SAAS,WAAW,EAAE,UAAU,GAA2B;AACzD,SACE,gBAAAA,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,KAAC,UAAK,GAAE,mBAAkB,GAC5B;AAEJ;AAIA,IAAM,wBAAiE;AAAA,EACrE,SAAS;AAAA,EACT,SAAS;AAAA,EACT,aAAa;AACf;AAEO,SAAS,iBAAiB,EAAE,SAAS,SAAS,GAA2D;AAC9G,SACE,gBAAAA,KAAC,UAAK,WAAW,8EAA8E,sBAAsB,OAAO,CAAC,IAC1H,UACH;AAEJ;AAEO,SAAS,wBAAwB;AAAA,EACtC,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,iBAAiB,YAAY,YAC/B,qEACA;AACJ,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAW,0IAA0I,cAAc;AAAA,MAElK;AAAA;AAAA,EACH;AAEJ;AAEA,IAAM,sBACJ;AAoBK,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,SACE,gBAAAA,KAAA,YACG,kBAAQ,IAAI,CAAC,QAAQ,gBAAgB;AACpC,UAAM,UAAU,GAAG,QAAQ,IAAI,WAAW;AAC1C,UAAM,UAAU,eAAe,SAAS,OAAO,KAAK;AAIpD,WACE,qBAAC,WAA6C,SAAS,SAAS,WAAU,mGACxE;AAAA,sBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAI;AAAA,UACJ,MAAM,QAAQ,aAAa;AAAA,UAC3B,MAAM;AAAA,UACN,OAAO,OAAO;AAAA,UACd;AAAA,UACA;AAAA,UACA,UAAU,MAAM,SAAS,OAAO,KAAK;AAAA,UACrC,mBAAiB,GAAG,OAAO;AAAA,UAC3B,oBAAkB,OAAO,cAAc,GAAG,OAAO,iBAAiB;AAAA,UAClE,WAAU;AAAA;AAAA,MACZ;AAAA,MACA,qBAAC,UAAK,WAAU,WACd;AAAA,wBAAAA,KAAC,UAAK,IAAI,GAAG,OAAO,UAAU,WAAU,uDAAuD,iBAAO,OAAM;AAAA,QAC3G,OAAO,eAAe,gBAAAA,KAAC,UAAK,IAAI,GAAG,OAAO,gBAAgB,WAAU,wDAAwD,iBAAO,aAAY;AAAA,SAClJ;AAAA,SAhBU,GAAG,OAAO,KAAK,IAAI,WAAW,EAiB1C;AAAA,EAEJ,CAAC,GACH;AAEJ;AAqDA,SAAS,YAAY,OAAqD;AACxE,SAAO,MAAM,SAAS,WAAY,QAA4B;AAChE;AAGA,SAAS,cAAc,OAAuD;AAC5E,SAAO,MAAM,SAAS,UAAU,MAAM,SAAS,WAAY,QAA8B;AAC3F;AAMA,SAAS,mBAAmB,OAA8C;AACxE,QAAM,MAAM,MAAM;AAClB,SAAO,OAAO,QAAQ,YAAY,OAAO,UAAU,GAAG,KAAK,MAAM,IAAI,MAAM;AAC7E;AAEA,SAAS,mBAAmB,QAAqB,OAAwB,aAAkC;AACzG,QAAM,UAAU,OAAO,MAAM,IAAI,GAAG,YAAY,CAAC;AACjD,MAAI,WAAW,CAAC,WAAW;AAC3B,MAAI,MAAM,UAAU,MAAM;AACxB,eAAW,QAAQ,SAAS,WAAW,IACnC,QAAQ,OAAO,CAAC,SAAS,SAAS,WAAW,IAC7C,CAAC,GAAG,SAAS,WAAW;AAAA,EAC9B;AACA,SAAO,EAAE,GAAG,QAAQ,CAAC,MAAM,IAAI,GAAG,EAAE,GAAG,OAAO,MAAM,IAAI,GAAG,SAAS,EAAE;AACxE;AAEA,IAAM,gBAAgB,wBAAwB;AAAA,EAC5C,SAAS;AAAA,EACT,UAAU;AAAA,EACV,UAAU;AACZ,CAAC;AAED,IAAM,iBAAiB,yBAAyB,YAAY;AAAA,EAC1D,SAAS;AAAA,EACT,WAAW;AACb,CAAC;AAEM,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAsB,MAChD,uBAAuB,YAAY,QAAQ,YAAY,OAAO,CAAC;AACjE,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAS,KAAK;AAGlD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAA2D,IAAI;AACrG,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,UAAS,KAAK;AAC1D,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AACtD,QAAM,oBAAoBC,QAAO,KAAK;AAMtC,QAAM,CAAC,OAAO,QAAQ,IAAID,UAAS,YAAY,EAAE;AAgCjD,MAAI,UAAU,YAAY,IAAI;AAC5B,aAAS,YAAY,EAAE;AACvB,cAAU,uBAAuB,YAAY,QAAQ,YAAY,OAAO,CAAC;AACzE,mBAAe,IAAI;AACnB,sBAAkB,KAAK;AACvB,aAAS,IAAI;AAAA,EACf;AAEA,EAAAE,WAAU,MAAM;AACd,QAAI,CAAC,YAAY,QAAS;AAC1B,cAAU,uBAAuB,YAAY,QAAQ,YAAY,OAAO,CAAC;AAAA,EAC3E,GAAG,CAAC,YAAY,SAAS,YAAY,MAAM,CAAC;AAE5C,QAAM,SAAgC,4BAA4B,YAAY,MAAM,IAChF,YAAY,SACZ,eAAe,YAAY;AAC/B,QAAM,WAAW,WAAW;AAC5B,QAAM,iBAAiB,uBAAuB,MAAM,KAAK,iBAAiB;AAC1E,QAAM,0BAA0B,kBAAkB,eAAe,YAAY,MAAM;AACnF,QAAM,gBAAgB,YAAY,kBAAkB,CAAC,kBAAkB,CAAC;AACxE,QAAM,WAAW,CAAC,YAAa,WAAW,aAAa,CAAC,iBAAkB;AAC1E,QAAM,aAAa,QAAQ,MAAM,gBAAgB,YAAY,QAAQ,MAAM,GAAG,CAAC,YAAY,QAAQ,MAAM,CAAC;AAE1G,QAAM,gBAAgB,CAAC,MAAc,UAA+B;AAClE,cAAU,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,IAAI,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,GAAG,MAAM,EAAE,EAAE;AAAA,EACxE;AAEA,QAAM,iBAAiB,CAAC,OAAwB,gBAAwB;AACtE,cAAU,CAAC,SAAS,mBAAmB,MAAM,OAAO,WAAW,CAAC;AAAA,EAClE;AAEA,iBAAe,mBAAmB;AAChC,QAAI,kBAAkB,WAAW,CAAC,iBAAiB,CAAC,aAAc;AAClE,UAAM,OAAO,gBAAgB,YAAY,QAAQ,MAAM;AACvD,QAAI,CAAC,KAAM;AACX,sBAAkB,UAAU;AAC5B,kBAAc,IAAI;AAClB,aAAS,IAAI;AACb,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,aAAa,kBAAkB,aAAa,IAAI,CAAC;AAAA,IACpE,QAAQ;AACN,iBAAW;AAAA,IACb,UAAE;AACA,wBAAkB,UAAU;AAC5B,oBAAc,KAAK;AAAA,IACrB;AACA,QAAI,aAAa,OAAO;AACtB,eAAS,yDAAyD;AAClE;AAAA,IACF;AACA,sBAAkB,IAAI;AAAA,EACxB;AAEA,iBAAe,SAAS;AACtB,QAAI,gBAAgB;AAClB,YAAM,iBAAiB;AACvB;AAAA,IACF;AACA,QAAI,kBAAkB,WAAW,YAAY,CAAC,WAAY;AAC1D,sBAAkB,UAAU;AAC5B,kBAAc,IAAI;AAClB,aAAS,IAAI;AACb,QAAI;AACF,YAAM,SAAS,MAAM;AAAA,QAAwB,MAC3C,aAAa,EAAE,IAAI,YAAY,IAAI,SAAS,YAAY,MAAM,WAAW,CAAC;AAAA,MAC5E;AACA,UAAI,OAAO,IAAI;AACb,uBAAe,UAAU;AACzB,qBAAa,YAAY,IAAI,YAAY,UAAU;AACnD;AAAA,MACF;AACA,UAAI,OAAO,SAAS;AAGlB,uBAAe,SAAS;AACxB,qBAAa,YAAY,IAAI,SAAS;AACtC;AAAA,MACF;AACA,eAAS,OAAO,OAAO;AAAA,IACzB,UAAE;AACA,wBAAkB,UAAU;AAC5B,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,eAAe,0BACjB,qHACA,eAAe,MAAM;AACzB,QAAM,mBAAmB,WAAW,aAAc,YAAY,kBAAkB,CAAC;AAMjF,QAAM,kBAAkB,eAAe,QAAQ,WAAW;AAC1D,MAAI,cAAc;AAClB,MAAI,gBAAgB;AAClB,kBAAc,aAAa,kBAAa;AAAA,EAC1C,WAAW,YAAY;AACrB,kBAAc;AAAA,EAChB;AAEA,SACE,qBAAC,SAAI,WAAW,kDAAkD,aAAa,EAAE,IAC/E;AAAA,yBAAC,SAAI,WAAU,0DACb;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,wBAAAH,KAAC,oBAAiB,SAAQ,WAAW,uBAAa,YAAW;AAAA,QAC7D,gBAAAA,KAAC,oBAAiB,SAAS,WAAW,YAAY,WAAW,aAAa,WAAW,aAAa,gBAAgB,WAC/G,wBAAc,MAAM,GACvB;AAAA,SACF;AAAA,MACA,gBAAAA,KAAC,UAAK,WAAU,iCAAiC,wBAAc,6BAA4B;AAAA,OAC7F;AAAA,IAEC,YAAY,MAAM,KAAK,KAAK,YAAY,OAAO,MAAM,CAAC,UAAU,MAAM,UAAU,YAAY,KAAK,KAChG,gBAAAA,KAAC,OAAE,WAAU,sDAAsD,sBAAY,OAAM;AAAA,IAEtF,YAAY,SAAS,iBAClB,gBAAAA,KAAC,SAAI,WAAU,gDAAgD,yBAAe,YAAY,IAAI,GAAE,IAChG,gBAAAA,KAAC,OAAE,WAAU,gDAAgD,sBAAY,MAAK;AAAA,IAElF,gBAAAA,KAAC,SAAI,WAAU,aACZ,sBAAY,OAAO,IAAI,CAAC,UAAU;AACjC,YAAM,QAAQ,OAAO,MAAM,IAAI,KAAK,CAAC;AACrC,YAAM,SAAS,YAAY,KAAK;AAChC,YAAM,WAAW,cAAc,KAAK;AACpC,aACE,qBAAC,cAA0B,WAAU,aACnC;AAAA,wBAAAA,KAAC,OAAE,WAAU,iDAAiD,gBAAM,OAAM;AAAA,QACzE,SACC,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,GAAG,YAAY,EAAE,IAAI,MAAM,IAAI;AAAA,cAC1C,UAAU,GAAG,YAAY,EAAE,IAAI,MAAM,IAAI;AAAA,cACzC,SAAS,OAAO;AAAA,cAChB,OAAO,OAAO,UAAU;AAAA,cACxB,gBAAgB,MAAM,YAAY,CAAC;AAAA,cACnC;AAAA,cACA,UAAU,CAAC,gBAAgB,eAAe,QAAQ,WAAW;AAAA;AAAA,UAC/D;AAAA,UACC,OAAO,gBAAgB,QACtB,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,OAAO,MAAM,UAAU;AAAA,cACvB;AAAA,cACA,UAAU,CAAC,UAAU,cAAc,MAAM,MAAM,EAAE,QAAQ,MAAM,OAAO,MAAM,CAAC;AAAA,cAC7E,aAAY;AAAA,cACZ,cAAY,qBAAqB,MAAM,KAAK;AAAA,cAC5C,WAAW;AAAA;AAAA,UACb;AAAA,WAEJ,IACE,MAAM,SAAS,YACjB,gBAAAA,KAAC,SAAI,WAAU,cACX,WAAC,QAAQ,OAAO,EAAY,IAAI,CAAC,cACjC,qBAAC,WAAsB,WAAU,kEAC/B;AAAA,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,MAAM,GAAG,YAAY,EAAE,IAAI,MAAM,IAAI;AAAA,cACrC,OAAO;AAAA,cACP,UAAU,MAAM,YAAY,CAAC,GAAG,CAAC,MAAM;AAAA,cACvC;AAAA,cACA,UAAU,MAAM,cAAc,MAAM,MAAM,EAAE,UAAU,CAAC,SAAS,EAAE,CAAC;AAAA,cACnE,WAAU;AAAA;AAAA,UACZ;AAAA,UACC,cAAc,SAAS,QAAQ;AAAA,aAVtB,SAWZ,CACD,GACH,IACE,MAAM,SAAS,WACjB,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO,MAAM,QAAQ;AAAA,YACrB;AAAA,YACA,cAAY,MAAM;AAAA,YAClB,UAAU,CAAC,UAAU,cAAc,MAAM,MAAM,EAAE,MAAM,MAAM,OAAO,MAAM,CAAC;AAAA,YAC3E,WAAW;AAAA;AAAA,QACb,IACE,MAAM,SAAS,WACjB,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO,MAAM,QAAQ;AAAA,YACrB;AAAA,YACA,cAAY,MAAM;AAAA,YAClB,UAAU,CAAC,UAAU,cAAc,MAAM,MAAM,EAAE,MAAM,MAAM,OAAO,MAAM,CAAC;AAAA,YAC3E,aAAa,MAAM;AAAA,YACnB,WAAW,WAAW,mBAAmB,QAAQ,IAAI;AAAA,YACrD,WAAW;AAAA;AAAA,QACb,IAEA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,MAAM,QAAQ;AAAA,YACrB;AAAA,YACA,cAAY,MAAM;AAAA,YAClB,UAAU,CAAC,UAAU,cAAc,MAAM,MAAM,EAAE,MAAM,MAAM,OAAO,MAAM,CAAC;AAAA,YAC3E,MAAM;AAAA,YACN,WAAW,WAAW,mBAAmB,QAAQ,IAAI;AAAA,YACrD,aAAa,MAAM,SAAS,SAAS,MAAM,cAAc;AAAA,YACzD,WAAW;AAAA;AAAA,QACb;AAAA,WAxEW,MAAM,IA0ErB;AAAA,IAEJ,CAAC,GACH;AAAA,IAIC,SAAS,gBAAAA,KAAC,OAAE,MAAK,SAAQ,WAAU,iCAAiC,iBAAM;AAAA,IAC1E,gBAAgB,gBAAAA,KAAC,OAAE,WAAU,sCAAsC,wBAAa;AAAA,KAE/E,oBAAoB,oBACpB,qBAAC,SAAI,WAAU,sDACZ;AAAA,yBACC,gBAAAA,KAAC,SAAI,WAAU,yCAAyC,uBAAY;AAAA,MAErE,oBACC,gBAAAA,KAAC,2BAAwB,SAAS,MAAM,KAAK,OAAO,GAAG,UAAU,YAAY,CAAC,YAC3E,uBACH;AAAA,OAEJ;AAAA,IAED,YACC,gBAAAA,KAAC,SAAI,WAAU,sCACb,+BAAC,UAAK,WAAU,gEAA+D;AAAA,sBAAAA,KAAC,cAAW,WAAU,WAAU;AAAA,MAAE;AAAA,OAAQ,GAC3H;AAAA,IAED,kBACC,gBAAAA,KAAC,SAAI,WAAU,sCACb,+BAAC,UAAK,WAAU,gEAA+D;AAAA,sBAAAA,KAAC,cAAW,WAAU,WAAU;AAAA,MAAE;AAAA,OAAmB,GACtI;AAAA,KAEJ;AAEJ;;;ADpeQ,SACE,OAAAI,MADF,QAAAC,aAAA;AAzCR,SAAS,YAAY,MAAwB;AAC3C,UAAQ,KAAK,QAAQ;AAAA,IACnB,KAAK;AAAW,aAAO;AAAA,IACvB,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAc,aAAO;AAAA,IAC1B,KAAK;AAAa,aAAO;AAAA,IACzB;AAAS,aAAO;AAAA,EAClB;AACF;AAEO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAS,EAAE;AAC3C,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,KAAK;AAC9C,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAwB,IAAI;AAChE,EAAAC,WAAU,MAAM,cAAc,IAAI,GAAG,CAAC,KAAK,QAAQ,KAAK,UAAU,KAAK,MAAM,CAAC;AAE9E,QAAM,aAAa,KAAK,WAAW;AACnC,QAAM,WAAW,CAAC,YAAY,CAAC,cAAc,aAAa;AAE1D,iBAAe,OAAO,UAA+B;AACnD,UAAM,UAAU,SAAS,KAAK;AAC9B,QAAI,aAAa,cAAc,CAAC,SAAS;AACvC,oBAAc,8DAA8D;AAC5E;AAAA,IACF;AACA,kBAAc,IAAI;AAClB,UAAM,OAAO,UAAU,aAAa,aAAa,UAAU,MAAS;AAAA,EACtE;AAEA,SACE,gBAAAF,MAAC,SAAI,WAAW,mDAAmD,aAAa,EAAE,IAChF;AAAA,oBAAAA,MAAC,SAAI,WAAU,0DACb;AAAA,sBAAAA,MAAC,SAAI,WAAU,qCACb;AAAA,wBAAAD,KAAC,oBAAiB,SAAQ,WAAU,2BAAa;AAAA,QACjD,gBAAAA,KAAC,oBAAiB,SAAS,KAAK,WAAW,aAAa,YAAY,KAAK,WAAW,cAAc,KAAK,WAAW,cAAc,gBAAgB,WAC7I,sBAAY,IAAI,GACnB;AAAA,SACF;AAAA,MACA,gBAAAC,MAAC,UAAK,WAAU,iCAAgC;AAAA;AAAA,QAAU,KAAK;AAAA,SAAS;AAAA,OAC1E;AAAA,IACC,KAAK,SAAS,gBAAAD,KAAC,OAAE,WAAU,sDAAsD,eAAK,OAAM;AAAA,IAC7F,gBAAAC,MAAC,SAAI,WAAU,YACb;AAAA,sBAAAD,KAAC,SAAI,WAAU,2BAA0B,OAAO,WAAW,SAAY,EAAE,WAAW,IAAI,GACrF,2BAAiB,eAAe,KAAK,IAAI,IAAI,gBAAAA,KAAC,OAAE,WAAU,iCAAiC,eAAK,MAAK,GACxG;AAAA,MACC,CAAC,YAAY,gBAAAA,KAAC,SAAI,WAAU,kGAAiG;AAAA,MAC9H,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,YAAY,CAAC,UAAU,CAAC,KAAK;AAAA,UAC5C,WAAU;AAAA,UAET,qBAAW,kBAAkB;AAAA;AAAA,MAChC;AAAA,OACF;AAAA,IACC,cACC,gBAAAC,MAAC,SAAI,WAAU,kBACb;AAAA,sBAAAD,KAAC,WAAM,WAAU,uDAAsD,SAAS,yBAAyB,KAAK,MAAM,IAAI,KAAK,QAAQ,IAAI,4CAEzI;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAI,yBAAyB,KAAK,MAAM,IAAI,KAAK,QAAQ;AAAA,UACzD,OAAO;AAAA,UACP;AAAA,UACA,UAAU,CAAC,UAAU,YAAY,MAAM,OAAO,KAAK;AAAA,UACnD,MAAM;AAAA,UACN,aAAY;AAAA,UACZ,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,KAEA,cAAc,UAAU,gBAAAA,KAAC,OAAE,WAAU,iCAAiC,wBAAc,OAAM;AAAA,IAC3F,cACC,gBAAAC,MAAC,SAAI,WAAU,4CACb;AAAA,sBAAAD,KAAC,2BAAwB,SAAQ,WAAU,SAAS,MAAM,KAAK,OAAO,UAAU,GAAG,UAChF,uBAAa,aAAa,kBAAa,mBAC1C;AAAA,MACA,gBAAAA,KAAC,2BAAwB,SAAS,MAAM,KAAK,OAAO,UAAU,GAAG,UAC9D,uBAAa,aAAa,oBAAe,gBAC5C;AAAA,OACF;AAAA,KAEJ;AAEJ;;;AGjGA,SAAS,WAAAI,UAAS,UAAAC,SAAQ,YAAAC,iBAAgC;AAiBpD,gBAAAC,MAoJE,QAAAC,aApJF;AAHN,SAASC,YAAW,EAAE,UAAU,GAA2B;AACzD,SACE,gBAAAF,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,KAAC,UAAK,GAAE,mBAAkB,GAC5B;AAEJ;AAEA,SAAS,iBAAiB,EAAE,UAAU,GAA2B;AAC/D,SACE,gBAAAA,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,KAAC,UAAK,GAAE,gBAAe,GACzB;AAEJ;AA0BA,IAAMG,iBAAgB,wBAAwB;AAAA,EAC5C,SAAS;AAAA,EACT,UAAU;AAAA,EACV,UAAU;AACZ,CAAC;AAED,IAAMC,kBAAiB,yBAAyB,QAAQ;AAAA,EACtD,UAAU;AACZ,CAAC;AAED,IAAM,2BAA2B;AAIjC,IAAM,uBAAuB;AAEtB,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA6B;AAC3B,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAsB,CAAC,CAAC;AACpD,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,KAAK;AAC9C,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAqD,IAAI;AAG7F,QAAM,CAAC,aAAa,cAAc,IAAIA,UAA2D,IAAI;AACrG,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,KAAK;AACpD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AACtD,QAAM,oBAAoBC,QAAO,KAAK;AAEtC,QAAM,SAAgC,4BAA4B,YAAY,MAAM,IAChF,YAAY,SACZ,eAAe,YAAY;AAC/B,QAAM,gBAAgB,uBAAuB,MAAM,KAAK,gBAAgB;AACxE,QAAM,eAAe,YAAY,iBAAiB,CAAC;AACnD,QAAM,WAAW,CAAC,YAAY,WAAW,aAAa,eAAe;AAKrE,QAAM,cAAcC,SAAQ,MAAM,gBAAgB,YAAY,QAAQ,MAAM,GAAG,CAAC,YAAY,QAAQ,MAAM,CAAC;AAG3G,QAAM,aAAaA,SAAQ,MAAM;AAC/B,UAAM,OAAwB,CAAC;AAC/B,eAAW,SAAS,YAAY,QAAQ;AACtC,YAAM,SAAS,YAAY,OAAO,MAAM;AACxC,UAAI,WAAW,KAAM,MAAK,MAAM,IAAI,IAAI;AAAA,IAC1C;AACA,WAAO;AAAA,EACT,GAAG,CAAC,YAAY,QAAQ,MAAM,CAAC;AAE/B,iBAAe,OAAO,SAAkC;AACtD,UAAM,OAAO,YAAY,aAAa,cAAc;AACpD,QAAI,kBAAkB,WAAW,YAAY,SAAS,KAAM;AAC5D,sBAAkB,UAAU;AAC5B,kBAAc,YAAY,aAAa,YAAY,QAAQ;AAC3D,aAAS,IAAI;AACb,QAAI;AACF,YAAM,SAAS,MAAM,aAAa,EAAE,IAAI,YAAY,IAAI,SAAS,KAAK,CAAC;AACvE,UAAI,OAAO,IAAI;AACb,cAAM,WAAW,YAAY,aAAa,aAAa;AACvD,uBAAe,QAAQ;AACvB,qBAAa,YAAY,IAAI,QAAQ;AACrC;AAAA,MACF;AACA,UAAI,OAAO,SAAS;AAClB,uBAAe,SAAS;AACxB,qBAAa,YAAY,IAAI,SAAS;AACtC;AAAA,MACF;AACA,eAAS,OAAO,OAAO;AAAA,IACzB,UAAE;AACA,wBAAkB,UAAU;AAC5B,oBAAc,IAAI;AAAA,IACpB;AAAA,EACF;AAEA,iBAAe,sBAAsB;AACnC,QAAI,kBAAkB,WAAW,CAAC,gBAAgB,CAAC,YAAa;AAChE,sBAAkB,UAAU;AAC5B,kBAAc,YAAY;AAC1B,aAAS,IAAI;AACb,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,YAAY,WAAW;AAAA,IAC1C,QAAQ;AACN,iBAAW;AAAA,IACb,UAAE;AACA,wBAAkB,UAAU;AAC5B,oBAAc,IAAI;AAAA,IACpB;AACA,QAAI,aAAa,OAAO;AACtB,eAAS,yCAAyC;AAClD;AAAA,IACF;AACA,mBAAe,IAAI;AAAA,EACrB;AAEA,QAAM,eAAeH,gBAAe,MAAM;AAC1C,QAAM,WAAW,WAAW;AAE5B,SACE,gBAAAH,MAAC,SAAI,WAAW,kDAAkD,aAAa,EAAE,IAC/E;AAAA,oBAAAA,MAAC,SAAI,WAAU,0DACb;AAAA,sBAAAA,MAAC,SAAI,WAAU,qCACb;AAAA,wBAAAD,KAAC,oBAAiB,SAAQ,WAAU,kBAAI;AAAA,QACxC,gBAAAA,KAAC,oBAAiB,SAAS,WAAW,YAAY,WAAW,aAAa,WAAW,aAAa,gBAAgB,WAC/G,UAAAG,eAAc,MAAM,GACvB;AAAA,SACF;AAAA,MACA,gBAAAH,KAAC,UAAK,WAAU,iCAAgC,uCAAyB;AAAA,OAC3E;AAAA,IAEC,YAAY,MAAM,KAAK,KACtB,gBAAAA,KAAC,OAAE,WAAU,sDAAsD,sBAAY,OAAM;AAAA,IAGtF,YAAY,QACX,gBAAAC,MAAC,SAAI,WAAU,YACb;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,WAAW,SAAY,EAAE,WAAW,qBAAqB;AAAA,UAE/D,2BACG,eAAe,YAAY,IAAI,IAC/B,gBAAAA,KAAC,OAAE,WAAU,iCAAiC,sBAAY,MAAK;AAAA;AAAA,MACrE;AAAA,MACC,CAAC,YACA,gBAAAA,KAAC,SAAI,WAAU,kGAAiG;AAAA,MAElH,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,YAAY,CAAC,SAAS,CAAC,IAAI;AAAA,UAC1C,WAAU;AAAA,UAEV;AAAA,4BAAAD,KAAC,oBAAiB,WAAW,gCAAgC,WAAW,eAAe,EAAE,IAAI;AAAA,YAC5F,WAAW,kBAAkB;AAAA;AAAA;AAAA,MAChC;AAAA,OACF;AAAA,IAGD,YAAY,OAAO,SAAS,KAC3B,gBAAAA,KAAC,SAAI,WAAU,kBACZ,sBAAY,OAAO,IAAI,CAAC,UACvB,gBAAAC,MAAC,cAA0B,WAAU,aACnC;AAAA,sBAAAD,KAAC,OAAE,WAAU,iDAAiD,gBAAM,OAAM;AAAA,MACzE,qBAAqB,KAAK,IACzB,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,OAAO,MAAM,IAAI,GAAG,QAAQ;AAAA,UACnC;AAAA,UACA,cAAY,MAAM;AAAA,UAClB,UAAU,CAAC,UACT,UAAU,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,GAAG,KAAK,MAAM,IAAI,GAAG,MAAM,MAAM,OAAO,MAAM,EAAE,EAAE;AAAA,UACpG,MAAM;AAAA,UACN,aAAa,MAAM,SAAS,SAAS,MAAM,eAAe,oCAAoC;AAAA,UAC9F,WAAU;AAAA;AAAA,MACZ,IAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,OAAO,OAAO,MAAM,IAAI,GAAG,QAAQ;AAAA,UACnC;AAAA,UACA,cAAY,MAAM;AAAA,UAClB,UAAU,CAAC,UACT,UAAU,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,GAAG,KAAK,MAAM,IAAI,GAAG,MAAM,MAAM,OAAO,MAAM,EAAE,EAAE;AAAA,UACpG,WAAU;AAAA;AAAA,MACZ;AAAA,SAtBW,MAAM,IAwBrB,CACD,GACH;AAAA,IAGD,SAAS,gBAAAA,KAAC,OAAE,WAAU,iCAAiC,iBAAM;AAAA,IAC7D,gBAAgB,gBAAAA,KAAC,OAAE,WAAU,sCAAsC,wBAAa;AAAA,IAEhF,gBACC,gBAAAA,KAAC,SAAI,WAAU,sCACb,0BAAAA,KAAC,2BAAwB,SAAQ,WAAU,SAAS,MAAM,KAAK,oBAAoB,GAAG,UAAU,eAAe,MAC5G,yBAAe,eAAe,iBAAY,kBAAkB,0BAC/D,GACF;AAAA,IAED,eACC,gBAAAA,KAAC,SAAI,WAAU,sCACb,0BAAAC,MAAC,UAAK,WAAU,gEAA+D;AAAA,sBAAAD,KAACE,aAAA,EAAW,WAAU,WAAU;AAAA,MAAE;AAAA,OAAuB,GAC1I;AAAA,IAGD,WAAW,aACV,gBAAAD,MAAC,SAAI,WAAU,4CACb;AAAA,sBAAAD,KAAC,2BAAwB,SAAQ,WAAU,SAAS,MAAM,KAAK,OAAO,UAAU,GAAG,UAChF,yBAAe,WAAW,kBAAa,mBAC1C;AAAA,MACA,gBAAAA,KAAC,2BAAwB,SAAS,MAAM,KAAK,OAAO,UAAU,GAAG,UAAU,YAAY,gBAAgB,MACpG,yBAAe,YAAY,oBAAe,gBAC7C;AAAA,OACF;AAAA,IAED,YACC,gBAAAA,KAAC,SAAI,WAAU,sCACb,0BAAAC,MAAC,UAAK,WAAU,gEAA+D;AAAA,sBAAAD,KAACE,aAAA,EAAW,WAAU,WAAU;AAAA,MAAE;AAAA,OAAQ,GAC3H;AAAA,KAEJ;AAEJ;;;AClMY,gBAAAM,YAAA;AAzEZ,SAAS,aAAa,QAAgB,UAA0B;AAC9D,SAAO,GAAG,MAAM,IAAI,QAAQ;AAC9B;AAKO,SAAS,0BAA0B,OAA0D;AAClG,QAAM,eAAe,oBAAI,IAAY;AACrC,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,oBAAoB,IAAI;AACrC,QAAI,KAAM,cAAa,IAAI,aAAa,KAAK,QAAQ,KAAK,QAAQ,CAAC;AAAA,EACrE;AACA,QAAM,QAA2B,CAAC;AAClC,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,oBAAoB,IAAI;AACrC,QAAI,MAAM;AACR,YAAM,KAAK,EAAE,MAAM,QAAQ,KAAK,QAAQ,aAAa,KAAK,QAAQ,KAAK,QAAQ,CAAC,IAAI,KAAK,CAAC;AAC1F;AAAA,IACF;AACA,UAAM,cAAc,2BAA2B,IAAI;AACnD,QAAI,CAAC,YAAa;AAClB,UAAM,iBAAiB,YAAY,SAAS,UAAU,OAAO,KAAK,WAAW,YAC3E,OAAO,KAAK,aAAa,YAAY,aAAa,IAAI,aAAa,KAAK,QAAQ,KAAK,QAAQ,CAAC;AAChG,QAAI,eAAgB;AACpB,UAAM,KAAK,EAAE,MAAM,eAAe,KAAK,eAAe,YAAY,EAAE,IAAI,YAAY,CAAC;AAAA,EACvF;AACA,SAAO;AACT;AAwBO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,QAAQ,0BAA0B,KAAK;AAC7C,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SACE,gBAAAA,KAAC,SAAI,WAAW,aAAa,aAAa,EAAE,IACzC,gBAAM,IAAI,CAAC,SAAS;AACnB,QAAI,KAAK,SAAS,QAAQ;AACxB,aACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAEC,MAAM,KAAK;AAAA,UACX;AAAA,UACA,QAAQ,CAAC,UAAU,aAAa,WAAW,KAAK,MAAM,UAAU,QAAQ;AAAA,UACxE,UAAU,eAAe,KAAK,IAAI;AAAA,UAClC,OAAO,YAAY,KAAK,IAAI;AAAA,UAC5B;AAAA;AAAA,QANK,KAAK;AAAA,MAOZ;AAAA,IAEJ;AACA,QAAI,KAAK,YAAY,SAAS,QAAQ;AACpC,aACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAEC,aAAa,KAAK;AAAA,UAClB;AAAA,UACA,cAAc;AAAA,UACd,YAAY;AAAA,UACZ;AAAA,UACA;AAAA,UACA;AAAA;AAAA,QAPK,KAAK;AAAA,MAQZ;AAAA,IAEJ;AACA,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEC,aAAa,KAAK;AAAA,QAClB;AAAA,QACA,cAAc;AAAA,QACd,YAAY;AAAA,QACZ;AAAA;AAAA,MALK,KAAK;AAAA,IAMZ;AAAA,EAEJ,CAAC,GACH;AAEJ;;;AC9GA,SAAS,aAAa,aAAAC,YAAW,YAAAC,iBAAgC;AAQ7D,SACE,OAAAC,MADF,QAAAC,aAAA;AAFJ,SAAS,UAAU,EAAE,UAAU,GAA2B;AACxD,SACE,gBAAAA,MAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,8DAA6D;AAAA,IACrE,gBAAAA,KAAC,UAAK,GAAE,aAAY;AAAA,KACtB;AAEJ;AAEA,SAAS,WAAW,EAAE,UAAU,GAA2B;AACzD,SACE,gBAAAC,MAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,IAChD,gBAAAA,KAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,KAAI;AAAA,IAC5B,gBAAAA,KAAC,UAAK,GAAE,mBAAkB;AAAA,KAC5B;AAEJ;AAEA,SAAS,aAAa,EAAE,UAAU,GAA2B;AAC3D,SACE,gBAAAA,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,KAAC,UAAK,GAAE,2GAA0G,GACpH;AAEJ;AAEA,SAAS,iBAAiB,WAA6E;AACrG,SAAO,WAAW,WAAW,QAAQ,IAAI,aAAa;AACxD;AAWA,SAAS,sBAAsB,MAAyC;AACtE,MAAI,OAAO,KAAK,SAAS,YAAY,KAAK,KAAK,KAAK,EAAE,SAAS,EAAG,QAAO,KAAK;AAC9E,QAAM,OAAO,KAAK,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK;AAC3C,QAAM,UAAU,KAAK,KAAK;AAC1B,SAAO,QAAQ,SAAS,IAAI,UAAU;AACxC;AAaA,IAAM,sBAAsB,oBAAI,IAA2C;AAEpE,SAAS,qCAA2C;AACzD,sBAAoB,MAAM;AAC5B;AAEA,eAAe,iBAAiB,KAAgC;AAC9D,SAAO,MAAM,KAAK,EAAE,aAAa,cAAc,CAAC;AAClD;AAEA,eAAe,oBACb,KACA,WAC+B;AAC/B,MAAI;AACF,UAAM,MAAM,MAAM,UAAU,GAAG;AAC/B,QAAI,CAAC,IAAI,GAAI,QAAO,EAAE,IAAI,OAAO,SAAS,8BAA8B,IAAI,MAAM,IAAI;AACtF,WAAO,EAAE,IAAI,MAAM,MAAM,MAAM,IAAI,KAAK,EAAE;AAAA,EAC5C,SAAS,KAAK;AACZ,WAAO,EAAE,IAAI,OAAO,SAAS,eAAe,SAAS,IAAI,UAAU,IAAI,UAAU,mCAAmC;AAAA,EACtH;AACF;AAMO,SAAS,mBACd,KACA,YAAgD,kBACjB;AAC/B,QAAM,SAAS,oBAAoB,IAAI,GAAG;AAC1C,MAAI,OAAQ,QAAO;AACnB,QAAM,UAAU,oBAAoB,KAAK,SAAS;AAClD,sBAAoB,IAAI,KAAK,OAAO;AACpC,OAAK,QAAQ,KAAK,CAAC,WAAW;AAC5B,QAAI,CAAC,OAAO,MAAM,oBAAoB,IAAI,GAAG,MAAM,QAAS,qBAAoB,OAAO,GAAG;AAAA,EAC5F,CAAC;AACD,SAAO;AACT;AAKO,SAAS,0BAA0B,MAAc,MAA2D;AACjH,MAAI;AACF,UAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,OAAO;AACZ,SAAK,WAAW;AAChB,aAAS,KAAK,YAAY,IAAI;AAC9B,SAAK,MAAM;AACX,SAAK,OAAO;AACZ,QAAI,gBAAgB,GAAG;AACvB,WAAO,EAAE,IAAI,KAAK;AAAA,EACpB,SAAS,KAAK;AACZ,WAAO,EAAE,IAAI,OAAO,SAAS,eAAe,SAAS,IAAI,UAAU,IAAI,UAAU,gCAAgC;AAAA,EACnH;AACF;AAIA,SAAS,uBAAuB,MAAuC;AACrE,QAAM,CAAC,KAAK,MAAM,IAAIE,UAAwB,IAAI;AAClD,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,MAAM;AACT,aAAO,IAAI;AACX;AAAA,IACF;AACA,UAAM,YAAY,IAAI,gBAAgB,IAAI;AAC1C,WAAO,SAAS;AAChB,WAAO,MAAM,IAAI,gBAAgB,SAAS;AAAA,EAC5C,GAAG,CAAC,IAAI,CAAC;AACT,SAAO;AACT;AAIA,SAAS,yBAAyB,EAAE,KAAK,GAAqB;AAC5D,SACE,gBAAAF,MAAC,UAAK,WAAU,yKACd;AAAA,oBAAAD,KAAC,gBAAa,WAAU,oBAAmB;AAAA,IAC3C,gBAAAA,KAAC,UAAK,WAAU,0CAA0C,gBAAK;AAAA,KACjE;AAEJ;AAKA,SAAS,sBAAsB,EAAE,MAAM,GAAoC;AACzE,MAAI,UAAU,aAAa;AACzB,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,iBAAc;AAAA,QACd,WAAU;AAAA,QAEV;AAAA,0BAAAD,KAAC,gBAAa,WAAU,oBAAmB;AAAA,UAC3C,gBAAAA,KAAC,UAAK,WAAU,0CAAyC,oCAAsB;AAAA;AAAA;AAAA,IACjF;AAAA,EAEJ;AACA,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,iBAAc;AAAA,MACd,WAAU;AAAA,MAEV;AAAA,wBAAAD,KAAC,gBAAa,WAAU,oBAAmB;AAAA,QAAE;AAAA;AAAA;AAAA,EAE/C;AAEJ;AAQA,SAAS,oBAAoB,EAAE,MAAM,gBAAgB,UAAU,GAAwB;AACrF,QAAM,MAAM,eAAe,IAAI;AAC/B,QAAM,cAAc,sBAAsB,IAAI;AAC9C,QAAM,CAAC,QAAQ,SAAS,IAAIE,UAAsC,IAAI;AAMtE,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,YAAa;AAClB,QAAI,YAAY;AAChB,cAAU,IAAI;AACd,uBAAmB,KAAK,SAAS,EAAE,KAAK,CAAC,SAAS;AAChD,UAAI,CAAC,UAAW,WAAU,IAAI;AAAA,IAChC,CAAC;AACD,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,KAAK,WAAW,WAAW,CAAC;AAEhC,QAAM,YAAY,uBAAuB,QAAQ,KAAK,OAAO,OAAO,MAAS;AAE7E,QAAM,cAAc,YAAY,MAAM;AACpC,QAAI,CAAC,UAAW;AAChB,WAAO,KAAK,WAAW,UAAU,UAAU;AAAA,EAC7C,GAAG,CAAC,SAAS,CAAC;AAEd,MAAI,CAAC,aAAa;AAChB,WAAO,gBAAAH,KAAC,yBAAsB,OAAM,aAAY;AAAA,EAClD;AACA,MAAI,CAAC,QAAQ;AAKX,WAAO,gBAAAA,KAAC,UAAK,eAAY,QAAO,WAAU,qEAAoE;AAAA,EAChH;AACA,MAAI,CAAC,OAAO,MAAM,CAAC,WAAW;AAC5B,WAAO,gBAAAA,KAAC,4BAAyB,MAAM,aAAa;AAAA,EACtD;AAEA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS;AAAA,MACT,cAAY,QAAQ,WAAW;AAAA,MAC/B,WAAU;AAAA,MAEV,0BAAAA,KAAC,SAAI,KAAK,WAAW,KAAK,aAAa,WAAU,0BAAyB;AAAA;AAAA,EAC5E;AAEJ;AAIA,SAAS,eAAe,EAAE,MAAM,gBAAgB,UAAU,GAAwB;AAChF,QAAM,cAAc,sBAAsB,IAAI;AAC9C,QAAM,CAAC,QAAQ,SAAS,IAAIE,UAAuC,MAAM;AACzE,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAwB,IAAI;AAIpE,QAAM,cAAc,YAAY,MAAM;AACpC,QAAI,CAAC,eAAe,WAAW,UAAW;AAC1C,cAAU,SAAS;AACnB,oBAAgB,IAAI;AACpB,UAAM,MAAM,eAAe,IAAI;AAC/B,SAAK,mBAAmB,KAAK,SAAS,EAAE,KAAK,CAAC,WAAW;AACvD,UAAI,CAAC,OAAO,IAAI;AACd,kBAAU,OAAO;AACjB,wBAAgB,OAAO,OAAO;AAC9B;AAAA,MACF;AACA,YAAM,WAAW,0BAA0B,aAAa,OAAO,IAAI;AACnE,UAAI,CAAC,SAAS,IAAI;AAChB,kBAAU,OAAO;AACjB,wBAAgB,SAAS,OAAO;AAChC;AAAA,MACF;AACA,gBAAU,MAAM;AAAA,IAClB,CAAC;AAAA,EACH,GAAG,CAAC,aAAa,QAAQ,gBAAgB,MAAM,SAAS,CAAC;AAEzD,MAAI,CAAC,aAAa;AAChB,WAAO,gBAAAF,KAAC,yBAAsB,OAAM,QAAO;AAAA,EAC7C;AAEA,QAAM,OAAO,WAAW,UAAU,eAAe,iBAAiB,KAAK,SAAS;AAChF,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,WAAW,UACP,6DACA;AAAA,EACN,EAAE,KAAK,GAAG;AAEV,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS;AAAA,MACT,OAAO,WAAW,UAAU,gBAAgB,SAAY;AAAA,MACxD;AAAA,MAEA;AAAA,wBAAAD,KAAC,QAAK,WAAU,oBAAmB;AAAA,QAClC;AAAA,QACA,OAAO,KAAK,SAAS,YAAY,gBAAAC,MAAC,UAAK,WAAU,4BAA2B;AAAA;AAAA,UAAG,YAAY,KAAK,IAAI;AAAA,WAAE;AAAA;AAAA;AAAA,EACzG;AAEJ;AAoBO,SAAS,mBAAmB,EAAE,OAAO,gBAAgB,UAAU,OAAO,UAAU,GAAuC;AAC5H,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SACE,gBAAAD,KAAC,SAAI,WAAW,0BAA0B,YAAY,UAAU,kBAAkB,aAAa,IAC5F,gBAAM;AAAA,IAAI,CAAC,SACV,KAAK,SAAS,UACZ,gBAAAA,KAAC,uBAAsD,MAAY,gBAAgC,aAAzE,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,EAAsE,IAEzH,gBAAAA,KAAC,kBAAiD,MAAY,gBAAgC,aAAzE,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,EAAsE;AAAA,EAExH,GACF;AAEJ;;;ACzNO,SAAS,uBAAuB,MAAc,IAGnD;AACA,MAAI,kBAAkB;AACtB,MAAI;AACJ,MAAI,CAAC,KAAK,KAAK,EAAG,QAAO,EAAE,gBAAgB;AAC3C,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,IAAI;AAAA,EAC1B,QAAQ;AACN,WAAO,EAAE,gBAAgB;AAAA,EAC3B;AAEA,MAAI,OAAO,SAAS,eAAe;AACjC,OAAG,eAAe;AAAA,MAChB,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO;AAAA,MACjB,OAAO,OAAO;AAAA,MACd,SAAU,OAAO,WAAW,OAAO;AAAA,IACrC,CAAC;AACD,WAAO,EAAE,iBAAiB,KAAK;AAAA,EACjC;AAEA,QAAM,MAAO,OAAO,SAAS,UAAU,OAAO,QAAQ;AACtD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO,EAAE,gBAAgB;AAE9D,UAAQ,IAAI,MAAM;AAAA,IAChB,KAAK;AACH,UAAI,OAAO,IAAI,WAAW,SAAU,UAAS,IAAI;AACjD;AAAA,IACF,KAAK;AACH,UAAI,OAAO,IAAI,SAAS,UAAU;AAChC,WAAG,SAAS,IAAI,IAAI;AACpB,0BAAkB;AAAA,MACpB;AACA;AAAA,IACF,KAAK;AACH,UAAI,OAAO,IAAI,SAAS,UAAU;AAChC,WAAG,cAAc,IAAI,IAAI;AACzB,0BAAkB;AAAA,MACpB;AACA;AAAA,IACF,KAAK,aAAa;AAChB,YAAM,OAAQ,IAAI,QAAQ;AAC1B,SAAG,aAAa;AAAA,QACd,YAAa,KAAK,cAAc,KAAK;AAAA,QACrC,UAAU,OAAO,KAAK,YAAY,KAAK,QAAQ,SAAS;AAAA,QACxD,MAAO,KAAK,QAAQ,CAAC;AAAA,MACvB,CAAC;AACD,wBAAkB;AAClB;AAAA,IACF;AAAA,IACA,KAAK;AACH,SAAG,eAAe;AAAA,QAChB,YAAY,IAAI;AAAA,QAChB,UAAU,IAAI;AAAA,QACd,OAAO,IAAI;AAAA,QACX,SAAU,IAAI,WAAW,IAAI;AAAA,MAC/B,CAAC;AACD,wBAAkB;AAClB;AAAA,IACF,KAAK,SAAS;AACZ,YAAM,IAAI,IAAI;AACd,UAAI,EAAG,IAAG,UAAU,EAAE,cAAc,EAAE,gBAAgB,GAAG,kBAAkB,EAAE,oBAAoB,EAAE,CAAC;AACpG;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,UACE,OAAO,IAAI,OAAO,aACjB,IAAI,eAAe,aAAa,IAAI,eAAe,oBACpD,OAAO,IAAI,SAAS,UACpB;AACA,WAAG,WAAW,EAAE,IAAI,IAAI,IAAI,YAAY,IAAI,YAAY,MAAM,IAAI,KAAK,CAAC;AACxE,0BAAkB;AAAA,MACpB;AACA;AAAA,IACF;AAAA,IACA,KAAK;AACH,SAAG,aAAc,IAAI,QAAQ,CAAC,CAA6B;AAC3D;AAAA,IACF,KAAK,eAAe;AAKlB,YAAMI,UAAS,wBAAwB,IAAI,IAA2C;AACtF,UAAIA,QAAO,WAAW;AACpB,WAAG,gBAAgB,2BAA2BA,QAAO,KAAK,CAAC;AAC3D,0BAAkB;AAAA,MACpB,OAAO;AACL,gBAAQ,MAAM,sDAAsDA,QAAO,KAAK;AAAA,MAClF;AACA;AAAA,IACF;AAAA,IACA,KAAK,sBAAsB;AACzB,YAAM,YAAY,uBAAuB,IAAI,IAA2C;AACxF,UAAI,UAAU,WAAW;AACvB,WAAG,sBAAsB,UAAU,KAAK;AACxC,0BAAkB;AAAA,MACpB,OAAO;AACL,gBAAQ,MAAM,6DAA6D,UAAU,KAAK;AAAA,MAC5F;AACA;AAAA,IACF;AAAA,IACA,KAAK,SAAS;AAKZ,YAAM,OAAO,IAAI;AAKjB,YAAM,UAAU,OAAO,MAAM,WAAW,IAAI,WAAW,IAAI,SAAS,sBAAsB;AAC1F,SAAG,qBAAqB;AAAA,QACtB;AAAA,QACA,GAAI,OAAO,MAAM,SAAS,WAAW,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,QAC5D,GAAI,MAAM,WAAW,OAAO,KAAK,YAAY,WAAW,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;AAAA,MACvF,CAAC;AACD,UAAI,GAAG,cAAc;AACnB,WAAG,aAAa,OAAO;AAAA,MACzB,OAAO;AAML,gBAAQ,MAAM,+CAA+C,OAAO;AACpE,WAAG,SAAS;AAAA;AAAA,gDAAqD,OAAO,EAAE;AAC1E,0BAAkB;AAAA,MACpB;AACA;AAAA,IACF;AAAA,IACA,SAAS;AACP,UAAI,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,WAAW,OAAO,GAAG;AAChE,cAAM,YAAY,wBAAwB,GAAG;AAC7C,cAAM,aACH,IAAI,MAA8C,QAClD,IAAI,YAAoD;AAE3D,cAAM,OAAO,UAAU,YACnB,UAAU,QACV,aAAa,oBAAoB,EAAE,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI;AACxE,YAAI,MAAM;AACR,aAAG,SAAS,IAAI;AAChB,4BAAkB;AAAA,QACpB,OAAO;AACL,kBAAQ,MAAM,uDAAuD,IAAI,IAAI;AAAA,QAC/E;AAAA,MACF;AACA;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,QAAQ,gBAAgB;AACnC;AAIA,eAAsB,kBACpB,MACA,IACkC;AAClC,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AACb,MAAI,SAAwB;AAC5B,MAAI,kBAAkB;AAEtB,QAAM,SAAS,CAAC,SAAiB;AAC/B,UAAM,IAAI,uBAAuB,MAAM,EAAE;AACzC,QAAI,EAAE,QAAQ;AACZ,eAAS,EAAE;AACX,SAAG,WAAW,EAAE,MAAM;AAAA,IACxB;AACA,QAAI,EAAE,gBAAiB,mBAAkB;AAAA,EAC3C;AAEA,aAAS;AACP,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,MAAM;AACR,UAAI,OAAO,KAAK,EAAG,QAAO,MAAM;AAChC;AAAA,IACF;AACA,cAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,UAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,aAAS,MAAM,IAAI,KAAK;AACxB,eAAW,QAAQ,MAAO,QAAO,IAAI;AAAA,EACvC;AACA,SAAO,EAAE,QAAQ,gBAAgB;AACnC;AAmBA,eAAsB,eAAe,MAA2D;AAC9F,QAAM,MAAM,MAAM,KAAK,MAAM;AAC7B,MAAI,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM;AACxB,UAAM,MAAM,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,EAAE,OAAO,QAAQ,IAAI,MAAM,GAAG,EAAE;AAC1E,UAAM,IAAI,MAAM,IAAI,SAAS,QAAQ,IAAI,MAAM,EAAE;AAAA,EACnD;AACA,MAAI,SAAwB;AAC5B,QAAM,KAA0B;AAAA,IAC9B,GAAG,KAAK;AAAA,IACR,UAAU,CAAC,OAAO;AAChB,eAAS;AACT,WAAK,UAAU,WAAW,EAAE;AAAA,IAC9B;AAAA,EACF;AACA,MAAI;AACF,WAAO,MAAM,kBAAkB,IAAI,MAAM,EAAE;AAAA,EAC7C,SAAS,cAAc;AACrB,QAAI,CAAC,UAAU,CAAC,KAAK,OAAQ,OAAM;AACnC,SAAK,mBAAmB;AACxB,UAAM,UAAU,MAAM,KAAK,OAAO,QAAQ,CAAC;AAC3C,QAAI,CAAC,QAAQ,MAAM,CAAC,QAAQ,KAAM,OAAM;AACxC,WAAO,MAAM,kBAAkB,QAAQ,MAAM,EAAE;AAAA,EACjD;AACF;;;ACvUA;AAAA,EACE,eAAAC;AAAA,EACA,aAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OAKK;AAOD,SAwpBM,YAAAC,WAxpBN,OAAAC,MAuBF,QAAAC,aAvBE;AAHN,SAAS,UAAU,EAAE,UAAU,GAA2B;AACxD,SACE,gBAAAD,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,KAAC,UAAK,GAAE,wCAAuC,GACjD;AAEJ;AAEA,SAAS,UAAU,EAAE,UAAU,GAA2B;AACxD,SACE,gBAAAA,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,gBAAe,eAAW,MAC5E,0BAAAA,KAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,GAClD;AAEJ;AAEA,SAAS,eAAe,EAAE,UAAU,GAA2B;AAC7D,SACE,gBAAAA,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,KAAC,UAAK,GAAE,oHAAmH,GAC7H;AAEJ;AAEA,SAAS,YAAY,EAAE,UAAU,GAA2B;AAC1D,SACE,gBAAAC,MAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,8HAA6H;AAAA,IACrI,gBAAAA,KAAC,UAAK,GAAE,mBAAkB;AAAA,KAC5B;AAEJ;AAEA,SAAS,WAAW,EAAE,UAAU,GAA2B;AACzD,SACE,gBAAAA,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,eAAW,MAChI,0BAAAA,KAAC,UAAK,GAAE,wBAAuB,GACjC;AAEJ;AAEA,SAAS,YAAY,EAAE,UAAU,GAA2B;AAC1D,SACE,gBAAAA,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,KAAC,UAAK,GAAE,mEAAkE,GAC5E;AAEJ;AAqKA,IAAM,aAAa;AAEnB,IAAM,uBAAuB;AAG7B,SAAS,kBAAkB,SAA+D;AACxF,SAAO,OAAO,YAAY,YAAY,YAAY,QAAQ,QAAQ,OAAO;AAC3E;AAEA,SAAS,UAAU,OAAkE;AACnF,SAAO,OAAQ,OAAoD,SAAS;AAC9E;AAIA,SAAS,gBAAgB,OAAgB,UAA0B;AACjE,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,QAAQ,OAAO;AAChE,UAAM,QAAS,MAA+B;AAC9C,QAAI,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,GAAI,QAAO;AAC7D,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,GAAI,QAAO;AAC7D,MAAI,iBAAiB,SAAS,MAAM,QAAQ,KAAK,MAAM,GAAI,QAAO,MAAM;AACxE,SAAO;AACT;AAaO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB;AAAA,EACA,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB;AAAA,EACA;AAAA,EACA,eAAe,CAAC;AAAA,EAChB;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,YAAY;AAAA,EACZ;AACF,GAAsB;AACpB,QAAM,eAAe,UAAU;AAC/B,QAAM,CAAC,UAAU,WAAW,IAAIF,UAAS,gBAAgB,EAAE;AAC3D,QAAM,OAAO,eAAe,QAAQ;AAGpC,QAAM,UAAUD,QAAO,IAAI;AAC3B,UAAQ,UAAU;AAElB,QAAM,cAAcA,QAA4B,IAAI;AACpD,QAAM,eAAeA,QAAyB,IAAI;AAClD,QAAM,iBAAiBA,QAAyB,IAAI;AACpD,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAS,KAAK;AAC9C,QAAM,YAAYD,QAAO,CAAC;AAE1B,QAAM,UAAUF;AAAA,IACd,CAAC,SAAiB;AAChB,UAAI,CAAC,aAAc,aAAY,IAAI;AACnC,sBAAgB,IAAI;AAAA,IACtB;AAAA,IACA,CAAC,cAAc,aAAa;AAAA,EAC9B;AAIA,EAAAC,WAAU,MAAM;AACd,UAAM,KAAK,YAAY;AACvB,QAAI,CAAC,GAAI;AACT,OAAG,MAAM,SAAS;AAClB,OAAG,MAAM,SAAS,GAAG,KAAK,IAAI,GAAG,cAAc,UAAU,CAAC;AAAA,EAC5D,GAAG,CAAC,IAAI,CAAC;AAST,QAAM,cAAcC,QAAsB,IAAI;AAC9C,QAAM,kBAAkBA,QAAsB,IAAI;AAClD,EAAAD,WAAU,MAAM;AACd,UAAM,OAAO,YAAY;AACzB,gBAAY,UAAU,QAAQ;AAC9B,QAAI,QAAQ,QAAQ,SAAS,QAAQ,aAAc;AACnD,YAAQ,IAAI;AACZ,oBAAgB;AAChB,UAAM,KAAK,YAAY;AACvB,QAAI,MAAM,GAAG,UAAU,MAAM;AAK3B,SAAG,MAAM;AACT,SAAG,kBAAkB,KAAK,QAAQ,KAAK,MAAM;AAAA,IAC/C,OAAO;AAEL,sBAAgB,UAAU;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,MAAM,SAAS,eAAe,YAAY,CAAC;AAK/C,EAAAA,WAAU,MAAM;AACd,QAAI,gBAAgB,WAAW,QAAQ,gBAAgB,YAAY;AACjE;AACF,oBAAgB,UAAU;AAC1B,UAAM,KAAK,YAAY;AACvB,QAAI,CAAC,GAAI;AACT,OAAG,MAAM;AACT,OAAG,kBAAkB,KAAK,QAAQ,KAAK,MAAM;AAAA,EAC/C,GAAG,CAAC,IAAI,CAAC;AAKT,QAAM,kBAAkBC,QAA4D,IAAI;AACxF,EAAAD,WAAU,MAAM;AACd,UAAM,UAAU,gBAAgB;AAChC,QAAI,CAAC,WAAW,QAAQ,SAAS,KAAM;AACvC,oBAAgB,UAAU;AAC1B,UAAM,KAAK,YAAY;AACvB,QAAI,CAAC,GAAI;AACT,OAAG,MAAM;AACT,UAAM,QAAQ,KAAK,IAAI,QAAQ,OAAO,KAAK,MAAM;AACjD,UAAM,MAAM,KAAK,IAAI,QAAQ,KAAK,KAAK,MAAM;AAC7C,OAAG,kBAAkB,OAAO,GAAG;AAAA,EACjC,GAAG,CAAC,IAAI,CAAC;AAIT,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,iBAAiB,SAAU;AAChC,aAAS,UAAU,GAA6B;AAC9C,WAAK,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,YAAY,MAAM,KAAK;AAC3D,UAAE,eAAe;AACjB,oBAAY,SAAS,MAAM;AAAA,MAC7B;AAAA,IACF;AACA,aAAS,iBAAiB,WAAW,SAAS;AAC9C,WAAO,MAAM,SAAS,oBAAoB,WAAW,SAAS;AAAA,EAChE,GAAG,CAAC,eAAe,QAAQ,CAAC;AAM5B,QAAM,iBAAiB,aAAa,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,EAAE;AACxE,QAAM,cAAc,KAAK,KAAK,EAAE,SAAS,KAAK,iBAAiB;AAC/D,QAAM,UAAU,eAAe,CAAC,eAAe,CAAC;AAEhD,QAAM,CAAC,YAAY,aAAa,IAAIE,UAA4B,IAAI;AAMpE,QAAM,WAAWH;AAAA,IACf,CAAC,OAAgB,OAAe,SAAiB,OAA2B,UAA0C;AACpH,YAAM,UAAU,gBAAgB,OAAO,kBAAkB;AACzD,YAAM,WAAW,QAAQ,YAAY;AACrC,UAAI,UAAU;AACZ,cAAM,KAAK,YAAY;AACvB,gBAAQ,KAAK;AACb,YAAI,MAAM,GAAG,UAAU,OAAO;AAK5B,aAAG,MAAM;AACT,aAAG,kBAAkB,KAAK,IAAI,MAAM,OAAO,MAAM,MAAM,GAAG,KAAK,IAAI,MAAM,KAAK,MAAM,MAAM,CAAC;AAAA,QAC7F,OAAO;AACL,0BAAgB,UAAU,EAAE,MAAM,OAAO,OAAO,MAAM,OAAO,KAAK,MAAM,IAAI;AAAA,QAC9E;AAAA,MACF;AACA,oBAAc,EAAE,SAAS,MAAM,OAAO,SAAS,OAAO,SAAS,CAAC;AAChE,qBAAe,EAAE,SAAS,MAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AAAA,IACjE;AAAA,IACA,CAAC,cAAc,oBAAoB,OAAO;AAAA,EAC5C;AAIA,QAAM,eAAeA;AAAA,IACnB,CAAC,OAAe,SAAiB,OAA2B,UAA0C;AACpG,UAAI;AACJ,UAAI;AACF,kBAAU,cAAc,YAAY,SAAS,KAAK,IAAI,SAAS,OAAO;AAAA,MACxE,SAAS,OAAO;AACd,iBAAS,OAAO,OAAO,SAAS,OAAO,KAAK;AAC5C;AAAA,MACF;AACA,UAAI,UAAU,OAAO,GAAG;AACtB,aAAK,QAAQ;AAAA,UACX,CAAC,YAAY;AACX,gBAAI,kBAAkB,OAAO,EAAG,UAAS,SAAS,OAAO,SAAS,OAAO,KAAK;AAAA,UAChF;AAAA,UACA,CAAC,UAAmB,SAAS,OAAO,OAAO,SAAS,OAAO,KAAK;AAAA,QAClE;AACA;AAAA,MACF;AACA,UAAI,kBAAkB,OAAO,EAAG,UAAS,SAAS,OAAO,SAAS,OAAO,KAAK;AAAA,IAChF;AAAA,IACA,CAAC,QAAQ,aAAa,QAAQ;AAAA,EAChC;AAEA,QAAM,OAAOA,aAAY,MAAM;AAC7B,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,eAAe,SAAU;AAC7B,UAAM,aAAa,aAAa,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO;AAClE,QAAI,CAAC,WAAW,WAAW,WAAW,EAAG;AAGzC,UAAM,QAAQ,cACV,WAAW,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAwB,IACtE,CAAC;AACL,UAAM,KAAK,YAAY;AACvB,UAAM,QAAQ,EAAE,OAAO,IAAI,kBAAkB,KAAK,QAAQ,KAAK,IAAI,gBAAgB,KAAK,OAAO;AAC/F,kBAAc,IAAI;AAClB,YAAQ,EAAE;AACV,YAAQ,UAAU;AAClB,iBAAa,MAAM,SAAS,OAAO,KAAK;AAAA,EAC1C,GAAG,CAAC,MAAM,aAAa,UAAU,aAAa,cAAc,SAAS,YAAY,CAAC;AAKlF,QAAM,kBAAkBA,aAAY,MAAM;AACxC,UAAM,UAAU;AAChB,QAAI,CAAC,WAAW,eAAe,SAAU;AACzC,kBAAc,IAAI;AAClB,UAAM,QAAQ,EAAE,OAAO,QAAQ,KAAK,QAAQ,KAAK,QAAQ,KAAK,OAAO;AACrE,iBAAa,QAAQ,MAAM,QAAQ,SAAS,QAAQ,OAAO,KAAK;AAAA,EAClE,GAAG,CAAC,YAAY,aAAa,UAAU,YAAY,CAAC;AAEpD,QAAM,gBAAgB,CAAC,MAA0C;AAE/D,QAAI,EAAE,YAAY,YAAa;AAC/B,QAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,UAAU;AACpC,QAAE,eAAe;AACjB,WAAK;AAAA,IACP;AAAA,EACF;AAEA,QAAM,mBAAmB,CAAC,MAAqC;AAC7D,QAAI,EAAE,OAAO,OAAO,OAAQ,YAAW,EAAE,OAAO,KAAK;AACrD,MAAE,OAAO,QAAQ;AAAA,EACnB;AAEA,QAAM,qBAAqB,CAAC,MAAqC;AAC/D,QAAI,EAAE,OAAO,OAAO,OAAQ,EAAC,kBAAkB,YAAY,EAAE,OAAO,KAAK;AACzE,MAAE,OAAO,QAAQ;AAAA,EACnB;AAEA,QAAM,kBAAkBA,aAAY,CAAC,MAAiB;AACpD,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,cAAU;AACV,QAAI,EAAE,cAAc,MAAM,SAAS,OAAO,EAAG,aAAY,IAAI;AAAA,EAC/D,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkBA,aAAY,CAAC,MAAiB;AACpD,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,cAAU;AACV,QAAI,UAAU,WAAW,GAAG;AAC1B,gBAAU,UAAU;AACpB,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,iBAAiBA,aAAY,CAAC,MAAiB;AACnD,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,QAAI,EAAE,aAAc,GAAE,aAAa,aAAa;AAAA,EAClD,GAAG,CAAC,CAAC;AAEL,QAAM,aAAaA;AAAA,IACjB,CAAC,MAAiB;AAChB,QAAE,eAAe;AACjB,QAAE,gBAAgB;AAClB,gBAAU,UAAU;AACpB,kBAAY,KAAK;AACjB,YAAM,QAAQ,EAAE,cAAc;AAC9B,UAAI,OAAO,OAAQ,YAAW,KAAK;AAAA,IACrC;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,QAAM,cAAc,aAAa,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ;AAClE,QAAM,YAAY,aAAa,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ;AAMhE,QAAM,YAAY,YAAY,QAAQ,sBAAsB;AAC5D,QAAM,aAAa,YAAY,QAAQ,CAAC;AAExC,SACE,gBAAAM;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,YAAY,aAAa,EAAE;AAAA,MACtC,aAAa,WAAW,kBAAkB;AAAA,MAC1C,aAAa,WAAW,kBAAkB;AAAA,MAC1C,YAAY,WAAW,iBAAiB;AAAA,MACxC,QAAQ,WAAW,aAAa;AAAA,MAE/B;AAAA,oBACC,gBAAAD,KAAC,SAAI,WAAU,2IACb,0BAAAC,MAAC,SAAI,WAAU,eACb;AAAA,0BAAAD,KAAC,UAAK,WAAU,iGACd,0BAAAA,KAAC,eAAY,WAAU,WAAU,GACnC;AAAA,UACA,gBAAAA,KAAC,OAAE,WAAU,yCAAyC,qBAAU;AAAA,UAChE,gBAAAA,KAAC,OAAE,WAAU,wCAAwC,2BAAgB;AAAA,WACvE,GACF;AAAA,QAGD,aAAa,gBAAAA,KAAC,SAAI,WAAU,mDAAmD,oBAAS;AAAA,QAExF,cACC,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,eAAY;AAAA,YACZ,WAAU;AAAA,YAEV;AAAA,8BAAAA,MAAC,SAAI,WAAU,0BACb;AAAA,gCAAAD,KAAC,UAAK,WAAU,kBAAkB,qBAAW,SAAQ;AAAA,gBACrD,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,cAAW;AAAA,oBACX,SAAS,MAAM,cAAc,IAAI;AAAA,oBACjC,WAAU;AAAA,oBACX;AAAA;AAAA,gBAED;AAAA,iBACF;AAAA,cAIC,CAAC,WAAW,YACX,gBAAAC,MAAC,SAAI,WAAU,UACb;AAAA,gCAAAD;AAAA,kBAAC;AAAA;AAAA,oBACC,eAAY;AAAA,oBACZ,WAAU;AAAA,oBAET,qBAAW;AAAA;AAAA,gBACd;AAAA,gBACA,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,cAAW;AAAA,oBACX,SAAS;AAAA,oBACT,UAAU,eAAe;AAAA,oBACzB,WAAU;AAAA,oBACX;AAAA;AAAA,gBAED;AAAA,iBACF;AAAA;AAAA;AAAA,QAEJ;AAAA,QAGD,aAAa,SAAS,KACrB,gBAAAA,KAAC,SAAI,WAAU,+BACZ,WAAC,GAAG,aAAa,GAAG,SAAS,EAAE,IAAI,CAAC,MACnC,gBAAAC;AAAA,UAAC;AAAA;AAAA,YAEC,WAAW,4EACT,EAAE,WAAW,UACT,2CACA,4CACN;AAAA,YAEC;AAAA,gBAAE,SAAS,WAAW,gBAAAD,KAAC,eAAY,WAAU,oBAAmB,IAAK,gBAAAA,KAAC,kBAAe,WAAU,oBAAmB;AAAA,cACnH,gBAAAA,KAAC,UAAK,WAAU,0BAA0B,YAAE,MAAK;AAAA,cAChD,EAAE,cAAc,UAAa,gBAAAC,MAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,gBAAE,EAAE;AAAA,gBAAU;AAAA,iBAAC;AAAA,cACpF,EAAE,WAAW,eACZ,gBAAAD,KAAC,UAAK,WAAU,kFAAiF;AAAA,cAElG,gBACC,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,cAAY,UAAU,EAAE,IAAI;AAAA,kBAC5B,SAAS,MAAM,aAAa,EAAE,EAAE;AAAA,kBAChC,WAAU;AAAA,kBAEV,0BAAAA,KAAC,cAAW,WAAU,WAAU;AAAA;AAAA,cAClC;AAAA;AAAA;AAAA,UArBG,EAAE;AAAA,QAuBT,CACD,GACH;AAAA,QAQF,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,WAAW,4KACT,WAAW,kBAAkB,EAC/B;AAAA,YAEA;AAAA,8BAAAD;AAAA,gBAAC;AAAA;AAAA,kBACC,KAAK;AAAA,kBACL,OAAO;AAAA,kBACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,kBACvC,WAAW;AAAA,kBACX;AAAA,kBACA;AAAA,kBAWA,MAAM;AAAA,kBACN,cAAW;AAAA,kBACX,WAAU;AAAA;AAAA,cACZ;AAAA,cAEA,gBAAAC,MAAC,SAAI,WAAU,wBACZ;AAAA,4BACC,gBAAAA,MAAAF,WAAA,EACE;AAAA,kCAAAC;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,SAAS,MAAM,aAAa,SAAS,MAAM;AAAA,sBAC3C;AAAA,sBACA,cAAW;AAAA,sBACX,OAAM;AAAA,sBACN,WAAU;AAAA,sBAEV,0BAAAA,KAAC,kBAAe,WAAU,WAAU;AAAA;AAAA,kBACtC;AAAA,kBACA,gBAAAA,KAAC,WAAM,KAAK,cAAc,MAAK,QAAO,UAAQ,MAAC,WAAU,UAAS,QAAgB,UAAU,kBAAkB;AAAA,mBAChH;AAAA,gBAED,kBACC,gBAAAC,MAAAF,WAAA,EACE;AAAA,kCAAAC;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,SAAS,MAAM,eAAe,SAAS,MAAM;AAAA,sBAC7C;AAAA,sBACA,cAAW;AAAA,sBACX,OAAM;AAAA,sBACN,WAAU;AAAA,sBAEV,0BAAAA,KAAC,eAAY,WAAU,WAAU;AAAA;AAAA,kBACnC;AAAA,kBAEA,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,KAAK;AAAA,sBACL,MAAK;AAAA,sBACL,UAAQ;AAAA,sBACR,WAAU;AAAA,sBACV,UAAU;AAAA,sBACT,GAAI,EAAE,iBAAiB,GAAG;AAAA;AAAA,kBAC7B;AAAA,mBACF;AAAA,gBAWF,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,eAAY;AAAA,oBACZ,WAAU;AAAA,oBAET,wBAAc;AAAA;AAAA,gBACjB;AAAA,gBAEC,cACC,gBAAAC;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS;AAAA,oBACT,cAAW;AAAA,oBACX,WAAU;AAAA,oBAEV;AAAA,sCAAAD,KAAC,aAAU,WAAU,eAAc;AAAA,sBACnC,gBAAAA,KAAC,UAAK,kBAAI;AAAA;AAAA;AAAA,gBACZ,IAEA,gBAAAC;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS;AAAA,oBACT,UAAU,CAAC;AAAA,oBACX,cAAY;AAAA,oBACZ,WAAU;AAAA,oBAEV;AAAA,sCAAAD,KAAC,aAAU,WAAU,eAAc;AAAA,sBACnC,gBAAAA,KAAC,UAAM,qBAAU;AAAA;AAAA;AAAA,gBACnB;AAAA,iBAEJ;AAAA;AAAA;AAAA,QACF;AAAA,QAEC,iBACC,gBAAAA,KAAC,SAAI,WAAU,gCACb,0BAAAC,MAAC,UAAK,WAAU,iCACd;AAAA,0BAAAD,KAAC,SAAI,WAAU,sEAAqE,iBAAG;AAAA,UACvF,gBAAAA,KAAC,SAAI,WAAU,6EAA4E,eAAC;AAAA,UAC5F,gBAAAA,KAAC,UAAK,WAAU,QAAO,sBAAQ;AAAA,WACjC,GACF;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AC5xBA,SAAS,eAAAE,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AA+ClD,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAChD,YACE,SACS,QACA,MACA,aACT;AACA,UAAM,OAAO;AAJJ;AACA;AACA;AAGT,SAAK,OAAO;AAAA,EACd;AAAA,EANW;AAAA,EACA;AAAA,EACA;AAKb;AASA,SAAS,SAAS,OAAgD;AAChE,SAAO,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IAC7D,QACA;AACN;AAEA,SAAS,SAAS,OAAiC;AACjD,QAAM,OAAO,SAAS,KAAK;AAC3B,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,SAAS,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AACvG,MAAI,CAAC,UAAU,OAAO,KAAK,aAAa,YAAY,OAAO,KAAK,SAAS,YACrE,OAAO,KAAK,gBAAgB,YAAY,OAAO,KAAK,WAAW,SAAU,QAAO;AACpF,SAAO,EAAE,GAAG,MAAM,OAAO;AAC3B;AAEA,SAAS,gBAAgB,MAAgB,UAA2C;AAClF,MAAI,OAAO,SAAS,cAAc,YAAY,SAAS,UAAW,QAAO,SAAS;AAClF,QAAM,SAAS,OAAO,SAAS,WAAW,WAAW,SAAS,SAAS;AACvE,SAAO,GAAG,KAAK,MAAM,IAAI,KAAK,QAAQ,IAAI,MAAM;AAClD;AAEA,SAAS,oBAAoB,OAAkD;AAC7E,QAAM,OAAO,SAAS,KAAK;AAC3B,QAAM,OAAO,SAAS,MAAM,IAAI;AAChC,MAAI,CAAC,QAAQ,CAAC,KAAM,QAAO;AAC3B,QAAM,cAAc,SAAS,KAAK,QAAQ,KAAK,SAAS,KAAK,OAAO;AACpE,QAAM,WAAW,eAAe,OAAO,YAAY,WAAW,WAC1D;AAAA,IACE,WAAW,gBAAgB,MAAM,WAAW;AAAA,IAC5C,QAAQ,KAAK;AAAA,IACb,UAAU,KAAK;AAAA,IACf,QAAQ,YAAY;AAAA,IACpB,OAAO,OAAO,YAAY,UAAU,WAAW,YAAY,QAAQ;AAAA,EACrE,IACA;AACJ,SAAO;AAAA,IACL;AAAA,IACA,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,IAC/B,YAAY,KAAK,eAAe,QAAQ,KAAK,aAAa;AAAA,IAC1D,GAAI,KAAK,sBAAsB,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAAA,IACrE,GAAI,KAAK,kBAAkB,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;AAAA,EAC/D;AACF;AAEA,eAAe,aAAa,UAAsD;AAChF,SAAO,SAAS,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,IAAI,CAAC,KAAK,CAAC;AAC/D;AAKO,SAAS,gCACd,SAC2B;AAC3B,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,SAAS,CAAC,UACd,OAAO,QAAQ,QAAQ,aAAa,QAAQ,IAAI,KAAK,IAAI,QAAQ;AAEnE,QAAM,OAAO,OAAO,aAA2D;AAC7E,UAAM,OAAO,MAAM,aAAa,QAAQ;AACxC,UAAM,SAAS,oBAAoB,IAAI;AACvC,QAAI,SAAS,MAAM,OAAQ,QAAO;AAClC,UAAM,cAAc,SAAS,KAAK,IAAI,KAAK;AAC3C,UAAM,UAAU,OAAO,KAAK,UAAU,WAClC,KAAK,QACL,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU,wBAAwB,SAAS,MAAM;AAC7F,UAAM,IAAI;AAAA,MACR;AAAA,MACA,SAAS;AAAA,MACT,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,QAAQ,OAAO;AACnB,YAAM,SAAS,OAAO,KAAK;AAC3B,YAAM,MAAM,IAAI,IAAI,QAAQ,WAAW,UAAU,UAAU,kBAAkB;AAC7E,UAAI,aAAa,IAAI,UAAU,MAAM,MAAM;AAC3C,UAAI,MAAM,aAAa,OAAW,KAAI,aAAa,IAAI,YAAY,OAAO,MAAM,QAAQ,CAAC;AACzF,YAAM,SAAS,WAAW,KAAK,MAAM,IACjC,IAAI,SAAS,IACb,GAAG,IAAI,QAAQ,GAAG,IAAI,MAAM;AAChC,aAAO,KAAK,MAAM,UAAU,QAAQ,EAAE,QAAQ,MAAM,CAAC,CAAC;AAAA,IACxD;AAAA,IACA,MAAM,OAAO,OAAO;AAClB,YAAM,QAAQ,OAAO,QAAQ,SAAS,aAAa,QAAQ,KAAK,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC1F,aAAO,KAAK,MAAM,UAAU,OAAO,KAAK,GAAG;AAAA,QACzC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,GAAG,OAAO,GAAG,MAAM,CAAC;AAAA,MAC7C,CAAC,CAAC;AAAA,IACJ;AAAA,EACF;AACF;AAyBO,SAAS,mBAAmB,SAA8D;AAC/F,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAS,QAAQ,IAAI;AAC7C,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAqC,IAAI;AACzE,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AACtD,QAAM,cAAcD,QAAO,oBAAI,IAA2B,CAAC;AAC3D,QAAM,mBAAmBA,QAAO,KAAK;AAErC,EAAAD,WAAU,MAAM,QAAQ,QAAQ,IAAI,GAAG,CAAC,QAAQ,IAAI,CAAC;AAErD,QAAM,QAAQD,aAAY,OAAO,WAAsC;AACrE,YAAQ,OAAO,IAAI;AACnB,YAAQ,YAAY,OAAO,IAAI;AAC/B,UAAM,UAAU,OAAO;AACvB,QAAI,CAAC,WAAW,CAAC,QAAQ,eAAgB;AACzC,QAAI,UAAU,YAAY,QAAQ,IAAI,QAAQ,SAAS;AACvD,QAAI,CAAC,SAAS;AACZ,gBAAU,QAAQ,QAAQ,QAAQ,eAAe,OAAO,CAAC;AACzD,kBAAY,QAAQ,IAAI,QAAQ,WAAW,OAAO;AAClD,WAAK,QAAQ,QAAQ,MAAM,YAAY,QAAQ,OAAO,QAAQ,SAAS,CAAC;AAAA,IAC1E;AACA,UAAM;AAAA,EACR,GAAG,CAAC,QAAQ,gBAAgB,QAAQ,SAAS,CAAC;AAE9C,QAAM,SAASA,aAAY,OAAO,UAA+B,aAAsB;AACrF,QAAI,iBAAiB,QAAS,QAAO;AACrC,qBAAiB,UAAU;AAC3B,gBAAY,QAAQ;AACpB,aAAS,IAAI;AACb,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,OAAO,OAAO;AAAA,QACzC,QAAQ,KAAK;AAAA,QACb,UAAU,KAAK;AAAA,QACf;AAAA,QACA,GAAI,UAAU,KAAK,IAAI,EAAE,UAAU,SAAS,KAAK,EAAE,IAAI,CAAC;AAAA,MAC1D,CAAC;AACD,YAAM,MAAM,MAAM;AAClB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,iBAAiB,0BAA0B,MAAM,aAAa;AAChE,gBAAQ,MAAM,WAAW;AACzB,gBAAQ,YAAY,MAAM,WAAW;AAAA,MACvC;AACA,eAAS,iBAAiB,QAAQ,MAAM,UAAU,4BAA4B;AAC9E,aAAO;AAAA,IACT,UAAE;AACA,uBAAiB,UAAU;AAC3B,kBAAY,IAAI;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,QAAQ,QAAQ,WAAW,KAAK,QAAQ,KAAK,QAAQ,CAAC;AAEzE,QAAM,UAAUA,aAAY,YAAY;AACtC,iBAAa,IAAI;AACjB,aAAS,IAAI;AACb,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,OAAO,QAAQ,EAAE,QAAQ,KAAK,QAAQ,UAAU,KAAK,SAAS,CAAC;AAC5F,YAAM,MAAM,MAAM;AAClB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,eAAS,iBAAiB,QAAQ,MAAM,UAAU,6BAA6B;AAC/E,aAAO;AAAA,IACT,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,QAAQ,KAAK,QAAQ,KAAK,QAAQ,CAAC;AAEtD,SAAO,EAAE,MAAM,UAAU,WAAW,OAAO,QAAQ,SAAS,YAAY,MAAM,SAAS,IAAI,EAAE;AAC/F;;;AC5OA,SAAS,kBAAkB,WAAmB,eAA+B;AAC3E,SAAO,GAAG,SAAS,IAAI,mBAAmB,aAAa,CAAC;AAC1D;AAEA,SAAS,eAAe,SAAmC,KAAqC;AAC9F,MAAI;AACF,UAAM,QAAQ,KAAK,MAAM,QAAQ,QAAQ,GAAG,KAAK,IAAI;AACrD,WAAO,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IAC7D,QACA,CAAC;AAAA,EACP,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGO,SAAS,qCACd,SACA,YAAY,iCACa;AACzB,SAAO;AAAA,IACL,IAAI,IAAI,WAAW;AACjB,aAAO,eAAe,SAAS,kBAAkB,WAAW,EAAE,CAAC,EAAE,SAAS,KAAK;AAAA,IACjF;AAAA,IACA,IAAI,IAAI,WAAW,YAAY;AAC7B,YAAM,MAAM,kBAAkB,WAAW,EAAE;AAC3C,cAAQ,QAAQ,KAAK,KAAK,UAAU,EAAE,GAAG,eAAe,SAAS,GAAG,GAAG,CAAC,SAAS,GAAG,WAAW,CAAC,CAAC;AAAA,IACnG;AAAA,IACA,OAAO,IAAI,WAAW;AACpB,YAAM,MAAM,kBAAkB,WAAW,EAAE;AAC3C,YAAM,WAAW,eAAe,SAAS,GAAG;AAC5C,aAAO,SAAS,SAAS;AACzB,UAAI,OAAO,KAAK,QAAQ,EAAE,WAAW,EAAG,SAAQ,WAAW,GAAG;AAAA,UACzD,SAAQ,QAAQ,KAAK,KAAK,UAAU,QAAQ,CAAC;AAAA,IACpD;AAAA,EACF;AACF;AAGO,SAAS,sCAA+D;AAC7E,QAAM,WAAW,oBAAI,IAAoB;AACzC,QAAM,MAAM,CAAC,IAAY,cAAsB,GAAG,EAAE,KAAS,SAAS;AACtE,SAAO;AAAA,IACL,KAAK,CAAC,IAAI,cAAc,SAAS,IAAI,IAAI,IAAI,SAAS,CAAC,KAAK;AAAA,IAC5D,KAAK,CAAC,IAAI,WAAW,eAAe,SAAS,IAAI,IAAI,IAAI,SAAS,GAAG,UAAU;AAAA,IAC/E,QAAQ,CAAC,IAAI,cAAc;AAAE,eAAS,OAAO,IAAI,IAAI,SAAS,CAAC;AAAA,IAAE;AAAA,EACnE;AACF;AAEA,SAAS,YAAY,OAAyB;AAC5C,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,WAAW;AACtD,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,SAAO,OAAO,YAAY,OAAO,QAAQ,KAAgC,EACtE,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,MAAM,KAAK,cAAc,KAAK,CAAC,EACnD,IAAI,CAAC,CAAC,KAAK,MAAM,MAAM,CAAC,KAAK,YAAY,MAAM,CAAC,CAAC,CAAC;AACvD;AAGO,SAAS,+BAA+B,YAAiD;AAC9F,SAAO,KAAK,UAAU,YAAY,UAAU,CAAC;AAC/C;AAQA,SAAS,oBAA4B;AACnC,MAAI,WAAW,QAAQ,WAAY,QAAO,WAAW,OAAO,WAAW;AACvE,SAAO,WAAW,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AACrE;AAKO,SAAS,wCACd,SACyB;AACzB,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,YAAY,QAAQ,aAAa;AACvC,SAAO,OAAO,eAAe;AAC3B,UAAM,YAAY,+BAA+B,UAAU;AAC3D,QAAI;AACJ,QAAI;AACF,mBAAa,QAAQ,SAAS,IAAI,WAAW,IAAI,SAAS,KAAK;AAC/D,UAAI,CAAC,YAAY;AACf,sBAAc,QAAQ,oBAAoB,mBAAmB;AAC7D,gBAAQ,SAAS,IAAI,WAAW,IAAI,WAAW,UAAU;AAAA,MAC3D;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MACpD;AAAA,IACF;AACA,UAAM,MAAM,OAAO,QAAQ,QAAQ,aAAa,QAAQ,IAAI,UAAU,IAAI,QAAQ;AAClF,UAAM,QAAQ,OAAO,QAAQ,SAAS,aAAa,QAAQ,KAAK,UAAU,IAAI,QAAQ,QAAQ,CAAC;AAC/F,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,kCAAkC,GAAG,SAAS;AAC9F,QAAI;AACF,YAAM,WAAW,MAAM,UAAU,KAAK;AAAA,QACpC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,QAAQ,WAAW;AAAA,QACnB,MAAM,KAAK,UAAU;AAAA,UACnB,GAAG;AAAA,UACH,IAAI,WAAW;AAAA,UACf,SAAS,WAAW;AAAA,UACpB;AAAA,UACA,GAAI,WAAW,OAAO,EAAE,MAAM,WAAW,KAAK,IAAI,CAAC;AAAA,QACrD,CAAC;AAAA,MACH,CAAC;AACD,UAAI,SAAS,IAAI;AACf,gBAAQ,SAAS,OAAO,WAAW,IAAI,SAAS;AAChD,eAAO,EAAE,IAAI,KAAK;AAAA,MACpB;AACA,YAAM,UAAU,MAAM,qBAAqB,QAAQ;AACnD,UAAI,SAAS,SAAS,IAAK,SAAQ,SAAS,OAAO,WAAW,IAAI,SAAS;AAC3E,aAAO,EAAE,IAAI,OAAO,SAAS,SAAS,WAAW,KAAK,SAAS,QAAQ,QAAQ;AAAA,IACjF,SAAS,OAAO;AACd,UAAI,WAAW,OAAO,SAAS;AAC7B,eAAO,EAAE,IAAI,OAAO,SAAS,OAAO,SAAS,mCAAmC;AAAA,MAClF;AACA,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MACpD;AAAA,IACF,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AACF;;;ACjIA,SAAS,eAAAI,cAAa,WAAAC,UAAS,YAAAC,iBAAgB;AAa/C,SAAS,2BAA2B,MAAyB,aAAuC;AAClG,MAAI,YAAY,WAAW,UAAW,QAAO;AAC7C,QAAM,YAAY,oCAAoC,WAAW;AACjE,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO,KAAK,KAAK,CAAC,SAChB,KAAK,OAAO,YAAY,MACxB,KAAK,WAAW,aAChB,oCAAoC,IAAI,MAAM,SAAS;AAC3D;AAKO,SAAS,sBAAsB,MAAyB,aAAiD;AAC9G,QAAM,QAAQ,KAAK,UAAU,CAAC,SAAS,KAAK,OAAO,YAAY,EAAE;AACjE,MAAI,UAAU,IAAI;AAChB,QAAI,2BAA2B,MAAM,WAAW,EAAG,QAAO;AAC1D,WAAO,CAAC,GAAG,MAAM,WAAW;AAAA,EAC9B;AACA,QAAM,WAAW,KAAK,KAAK;AAC3B,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,4BAA4B,SAAS,MAAM,GAAG;AAChD,QACE,SAAS,WAAW,YAAY,WAC/B,CAAC,SAAS,WAAW,YAAY,WAAW,CAAC,SAAS,gBAAgB,YAAY,eACnF;AACA,YAAMC,QAAO,CAAC,GAAG,IAAI;AACrB,MAAAA,MAAK,KAAK,IAAI,EAAE,GAAG,UAAU,GAAG,YAAY;AAC5C,aAAOA;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,CAAC,GAAG,IAAI;AACrB,OAAK,KAAK,IAAI;AACd,SAAO;AACT;AAIO,SAAS,sBAAsB,MAAyB,QAAkD;AAC/G,QAAM,QAAQ,KAAK,UAAU,CAAC,SAAS,KAAK,OAAO,OAAO,EAAE;AAC5D,QAAM,WAAW,KAAK,KAAK;AAC3B,MAAI,CAAC,YAAY,SAAS,WAAW,UAAW,QAAO;AACvD,QAAM,OAAO,CAAC,GAAG,IAAI;AACrB,OAAK,KAAK,IAAI;AAAA,IACZ,GAAG;AAAA,IACH,QAAQ,gBAAgB,OAAO,MAAM;AAAA,IACrC,GAAI,OAAO,SAAS,EAAE,cAAc,OAAO,OAAO,IAAI,CAAC;AAAA,EACzD;AACA,SAAO;AACT;AAGO,SAAS,uBACd,MACA,IACA,QACA,SACmB;AACnB,QAAM,QAAQ,KAAK,UAAU,CAAC,SAAS,KAAK,OAAO,EAAE;AACrD,QAAM,WAAW,KAAK,KAAK;AAC3B,MAAI,CAAC,YAAY,SAAS,WAAW,UAAW,QAAO;AACvD,QAAM,OAAO,CAAC,GAAG,IAAI;AACrB,OAAK,KAAK,IAAI,EAAE,GAAG,UAAU,QAAQ,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC,EAAG;AACrE,SAAO;AACT;AAIO,SAAS,mCACd,MACA,QACmB;AACnB,MAAI,CAAC,KAAK,KAAK,CAAC,SAAS,KAAK,WAAW,SAAS,EAAG,QAAO;AAC5D,SAAO,KAAK,IAAI,CAAC,SAAU,KAAK,WAAW,YAAY,EAAE,GAAG,MAAM,OAAO,IAAI,IAAK;AACpF;AAmBO,SAAS,wBACd,MACA,aACA,UAA0C,CAAC,GACxB;AACnB,MAAI,OAAO;AACX,aAAW,WAAW,aAAa;AACjC,UAAM,cAAc,2BAA2B,OAAO;AACtD,UAAM,QAAQ,KAAK,UAAU,CAAC,SAAS,KAAK,OAAO,YAAY,EAAE;AACjE,QAAI,UAAU,IAAI;AAChB,aAAO,sBAAsB,MAAM,WAAW;AAC9C;AAAA,IACF;AACA,UAAM,YAAY,oCAAoC,WAAW;AACjE,UAAM,WAAW,YACb,KAAK,UAAU,CAAC,SAAS,KAAK,WAAW,aAAa,oCAAoC,IAAI,MAAM,SAAS,IAC7G;AACJ,QAAI,aAAa,IAAI;AACnB,aAAO,CAAC,GAAG,MAAM,WAAW;AAC5B;AAAA,IACF;AACA,WAAO,CAAC,GAAG,IAAI;AACf,SAAK,QAAQ,IAAI;AAAA,EACnB;AACA,MAAI,QAAQ,SAAS,WAAW;AAC9B,UAAM,iBAAiB,IAAI,IAAI,YAAY,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;AACvE,WAAO,KAAK,IAAI,CAAC,SACf,KAAK,WAAW,aAAa,CAAC,eAAe,IAAI,KAAK,EAAE,IACpD,EAAE,GAAG,MAAM,QAAQ,WAAoB,IACvC,IAAI;AAAA,EACZ;AACA,SAAO;AACT;AAKO,SAAS,wBACd,MACA,WACmB;AACnB,SAAO,UAAU,OAAO,uBAAuB,IAAI;AACrD;AA4BO,SAAS,oBAAoB,UAAsC,CAAC,GAA8B;AACvG,QAAM,CAAC,cAAc,eAAe,IAAIC,UAA4B,CAAC,CAAC;AAEtE,QAAM,SAASC,aAAY,CAAC,gBAAiC;AAC3D,oBAAgB,CAAC,SAAS,sBAAsB,MAAM,WAAW,CAAC;AAAA,EACpE,GAAG,CAAC,CAAC;AACL,QAAM,cAAcA,aAAY,CAAC,WAAkC;AACjE,oBAAgB,CAAC,SAAS,sBAAsB,MAAM,MAAM,CAAC;AAAA,EAC/D,GAAG,CAAC,CAAC;AACL,QAAM,eAAeA,aAAY,CAAC,IAAY,QAAmD,YAAiC;AAChI,oBAAgB,CAAC,SAAS,uBAAuB,MAAM,IAAI,QAAQ,OAAO,CAAC;AAAA,EAC7E,GAAG,CAAC,CAAC;AACL,QAAM,UAAUA,aAAY,CAAC,aAAuC,mBAAoD;AACtH,oBAAgB,CAAC,SAAS,wBAAwB,MAAM,aAAa;AAAA,MACnE,MAAM,gBAAgB,QAAQ,QAAQ;AAAA,IACxC,CAAC,CAAC;AAAA,EACJ,GAAG,CAAC,QAAQ,IAAI,CAAC;AACjB,QAAM,UAAUA,aAAY,CAAC,cAAiC;AAC5D,oBAAgB,CAAC,SAAS,wBAAwB,MAAM,SAAS,CAAC;AAAA,EACpE,GAAG,CAAC,CAAC;AACL,QAAM,qBAAqBA,aAAY,CAAC,WAAmE;AACzG,oBAAgB,CAAC,SAAS,mCAAmC,MAAM,MAAM,CAAC;AAAA,EAC5E,GAAG,CAAC,CAAC;AACL,QAAM,QAAQA,aAAY,MAAM,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC;AAEvD,QAAM,UAAUC,SAAQ,MAAM,aAAa,OAAO,CAAC,SAAS,KAAK,WAAW,SAAS,GAAG,CAAC,YAAY,CAAC;AAEtG,SAAO,EAAE,cAAc,SAAS,QAAQ,aAAa,cAAc,SAAS,SAAS,oBAAoB,MAAM;AACjH;;;ACjNA,SAAS,eAAAC,cAAa,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,iBAAgB;AA2BvD,IAAM,oBAAoB;AAE1B,SAAS,cAAc,MAAgC;AACrD,SAAO,EAAE,IAAI,KAAK,MAAM,OAAO,KAAK,MAAM,QAAQ,KAAK,MAAM,MAAM,kBAAkB;AACvF;AAEA,SAAS,cAAc,MAAgC;AACrD,SAAO,EAAE,MAAM,KAAK,IAAI,MAAM,KAAK,MAAM;AAC3C;AAWO,SAAS,iBACd,OACA,OACA,OACe;AACf,QAAM,IAAI,MAAM,KAAK,EAAE,YAAY;AACnC,MAAI,CAAC,EAAG,QAAO,MAAM,MAAM,GAAG,KAAK;AACnC,QAAM,SAAwD,CAAC;AAC/D,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,KAAK,KAAK,YAAY;AACnC,QAAI,KAAK,WAAW,CAAC,GAAG;AACtB,aAAO,KAAK,EAAE,MAAM,MAAM,EAAE,CAAC;AAC7B;AAAA,IACF;AACA,QAAI,KAAK,SAAS,CAAC,GAAG;AACpB,aAAO,KAAK,EAAE,MAAM,MAAM,EAAE,CAAC;AAC7B;AAAA,IACF;AACA,QAAI,KAAK,KAAK,YAAY,EAAE,SAAS,CAAC,GAAG;AACvC,aAAO,KAAK,EAAE,MAAM,MAAM,EAAE,CAAC;AAAA,IAC/B;AAAA,EACF;AACA,SAAO,KAAK,CAAC,GAAG,MAAM;AACpB,QAAI,EAAE,SAAS,EAAE,KAAM,QAAO,EAAE,OAAO,EAAE;AACzC,QAAI,EAAE,KAAK,KAAK,WAAW,EAAE,KAAK,KAAK,OAAQ,QAAO,EAAE,KAAK,KAAK,SAAS,EAAE,KAAK,KAAK;AACvF,WAAO,EAAE,KAAK,KAAK,cAAc,EAAE,KAAK,IAAI;AAAA,EAC9C,CAAC;AACD,SAAO,OAAO,MAAM,GAAG,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AACjD;AAYA,IAAM,iBAAiB;AAKhB,IAAM,wBAAwB;AAQ9B,IAAM,yBAAyB,IAAI,KAAK;AAIxC,IAAM,6BAA6B;AAqC1C,SAAS,aAAa,OAAmB,UAA0B;AACjE,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,wBAAwB,MAAM,OAAO;AAAA,IAC9C,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAGO,SAAS,gBAAgB,SAAwD;AACtF,QAAM;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,YAAY;AAAA,EACd,IAAI;AACJ,QAAM,YAAY,QAAQ,aAAa;AAEvC,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAqB,EAAE,MAAM,OAAO,CAAC;AAS/D,QAAM,WAAWD,QAAO,KAAK;AAC7B,WAAS,UAAU;AACnB,QAAM,cAAcA,QAAmC,IAAI;AAC3D,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAwB,CAAC,CAAC;AAE1D,QAAM,OAAOH,aAAY,MAA2B;AAClD,QAAI,YAAY,QAAS,QAAO,YAAY;AAC5C,QAAI,SAAS,QAAQ,SAAS,QAAQ;AACpC,eAAS,UAAU,EAAE,MAAM,UAAU;AACrC,eAAS,SAAS,OAAO;AAAA,IAC3B;AACA,UAAM,WAAW,YAAiC;AAChD,UAAI;AACJ,UAAI;AACF,cAAM,MAAM,MAAM,UAAU,QAAQ;AACpC,YAAI,CAAC,IAAI,IAAI;AACX,iBAAO,EAAE,MAAM,SAAS,SAAS,QAAQ,IAAI,MAAM,IAAI,aAAa,KAAK,IAAI,EAAE;AAAA,QACjF,OAAO;AACL,gBAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,iBACE,KAAK,WAAW,YACZ,EAAE,MAAM,WAAW,aAAa,KAAK,IAAI,EAAE,IAC3C;AAAA,YACE,MAAM;AAAA,YACN,OAAQ,KAAgC;AAAA,YACxC,WAAY,KAAgC;AAAA,YAC5C,WAAW,KAAK,IAAI;AAAA,UACtB;AAAA,QACR;AAAA,MACF,SAAS,KAAK;AACZ,eAAO,EAAE,MAAM,SAAS,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG,aAAa,KAAK,IAAI,EAAE;AAAA,MAC7G;AACA,eAAS,UAAU;AACnB,eAAS,IAAI;AACb,kBAAY,UAAU;AACtB,aAAO;AAAA,IACT,GAAG;AACH,gBAAY,UAAU;AACtB,WAAO;AAAA,EACT,GAAG,CAAC,WAAW,QAAQ,CAAC;AAMxB,QAAM,UAAUA,aAAY,YAA2B;AACrD,UAAM,KAAK;AAAA,EACb,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,aAAaA;AAAA,IACjB,OAAO,UAA0C;AAC/C,UAAI,UAAU,SAAS;AAKvB,UAAI,QAAQ,SAAS,UAAU,QAAQ,SAAS,WAAW;AACzD,kBAAU,MAAM,KAAK;AAAA,MACvB,WAAW,QAAQ,SAAS,SAAS;AACnC,YAAI,KAAK,IAAI,IAAI,QAAQ,YAAY,eAAgB,MAAK,KAAK;AAAA,MACjE,WAAW,KAAK,IAAI,IAAI,QAAQ,cAAc,gBAAgB;AAC5D,aAAK,KAAK;AAAA,MACZ;AACA,UAAI,QAAQ,SAAS,QAAS,QAAO,CAAC;AACtC,aAAO,iBAAiB,QAAQ,OAAO,OAAO,KAAK,EAAE,IAAI,aAAa;AAAA,IACxE;AAAA,IACA,CAAC,MAAM,OAAO,cAAc;AAAA,EAC9B;AAEA,QAAM,mBAAmBA,aAAY,CAAC,UAAyB;AAC7D,gBAAY,MAAM,OAAO,CAAC,SAAS,KAAK,SAAS,UAAa,KAAK,SAAS,iBAAiB,EAAE,IAAI,aAAa,CAAC;AAAA,EACnH,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgBA,aAAY,MAAM,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC;AAE3D,QAAM,UAAUC;AAAA,IACd,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAW,aAAa,OAAO,SAAS;AAAA,IAC1C;AAAA,IACA,CAAC,YAAY,kBAAkB,OAAO,SAAS;AAAA,EACjD;AAEA,SAAO,EAAE,SAAS,UAAU,eAAe,QAAQ;AACrD;;;AC3OA,IAAM,yBAAyB;AAI/B,IAAM,YAAY;AAiBX,SAAS,sBACd,SACA,OACmE;AACnE,QAAM,UAAU,oBAAI,IAAqB;AACzC,MAAI,CAAC,QAAS,QAAO,EAAE,UAAU,CAAC,GAAG,QAAQ;AAC7C,MAAI,MAAM,WAAW,EAAG,QAAO,EAAE,UAAU,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,CAAC,GAAG,QAAQ;AAEtF,QAAM,aAAa,MAChB,IAAI,CAAC,UAAU,EAAE,MAAM,OAAO,IAAI,KAAK,IAAI,GAAG,EAAE,EAChD,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,SAAS,EAAE,MAAM,MAAM;AAEjD,QAAM,WAAiC,CAAC;AACxC,MAAI,SAAS;AACb,MAAI,YAAY;AAChB,SAAO,SAAS,QAAQ,QAAQ;AAC9B,QAAI,QAAQ,MAAM,MAAM,KAAK;AAC3B,gBAAU;AACV;AAAA,IACF;AACA,UAAM,WAAW,SAAS,IAAI,QAAQ,SAAS,CAAC,IAAI;AACpD,QAAI,YAAY,UAAU,KAAK,QAAQ,GAAG;AACxC,gBAAU;AACV;AAAA,IACF;AACA,UAAM,YAAY,WAAW,KAAK,CAAC,EAAE,MAAM,MAAM,QAAQ,WAAW,OAAO,MAAM,CAAC;AAClF,QAAI,CAAC,WAAW;AACd,gBAAU;AACV;AAAA,IACF;AACA,UAAM,SAAS,SAAS,UAAU,MAAM;AACxC,UAAM,WAAW,SAAS,QAAQ,SAAS,QAAQ,MAAM,IAAI;AAC7D,QAAI,YAAY,uBAAuB,KAAK,QAAQ,GAAG;AACrD,gBAAU;AACV;AAAA,IACF;AAEA,QAAI,SAAS,UAAW,UAAS,KAAK,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,WAAW,MAAM,EAAE,CAAC;AAC9F,aAAS,KAAK,EAAE,MAAM,WAAW,MAAM,UAAU,OAAO,MAAM,UAAU,KAAK,CAAC;AAC9E,YAAQ,IAAI,UAAU,IAAI;AAC1B,aAAS;AACT,gBAAY;AAAA,EACd;AACA,MAAI,YAAY,QAAQ,OAAQ,UAAS,KAAK,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,SAAS,EAAE,CAAC;AAE9F,SAAO,EAAE,UAAU,QAAQ;AAC7B;;;ACzFA,SAAS,eAAAG,cAAa,aAAAC,YAAW,YAAAC,kBAAgC;AAyG3D,SAoPQ,YAAAC,WApPR,OAAAC,MAeF,QAAAC,aAfE;AA/FN,IAAM,gBAAgB,oBAAI,IAAI,CAAC,WAAW,SAAS,CAAC;AACpD,IAAM,cAAc,oBAAI,IAAI,CAAC,aAAa,QAAQ,WAAW,CAAC;AAC9D,IAAM,iBAAiB,oBAAI,IAAI,CAAC,UAAU,SAAS,aAAa,SAAS,CAAC;AAGnE,SAAS,aAAa,QAA8B;AACzD,QAAM,IAAI,OAAO,YAAY;AAC7B,MAAI,cAAc,IAAI,CAAC,EAAG,QAAO;AACjC,MAAI,YAAY,IAAI,CAAC,EAAG,QAAO;AAC/B,MAAI,eAAe,IAAI,CAAC,EAAG,QAAO;AAClC,SAAO;AACT;AAGO,SAAS,mBAAmB,SAAiC;AAClE,MAAI,YAAY,UAAa,CAAC,SAAS,OAAO,KAAK,WAAW,EAAG,QAAO;AACxE,SAAO,UAAU,OAAO,IAAI,QAAQ,QAAQ,CAAC,CAAC,KAAK,IAAI,QAAQ,QAAQ,CAAC,CAAC;AAC3E;AAGO,SAAS,uBAAuB,YAAoC;AACzE,MAAI,eAAe,UAAa,CAAC,SAAS,UAAU,KAAK,aAAa,EAAG,QAAO;AAChF,QAAM,eAAe,KAAK,MAAM,aAAa,GAAI;AACjD,MAAI,eAAe,GAAI,QAAO,GAAG,YAAY;AAC7C,QAAM,UAAU,KAAK,MAAM,eAAe,EAAE;AAC5C,QAAM,UAAU,eAAe;AAC/B,MAAI,UAAU,GAAI,QAAO,GAAG,OAAO,KAAK,OAAO,OAAO,EAAE,SAAS,GAAG,GAAG,CAAC;AACxE,SAAO,GAAG,KAAK,MAAM,UAAU,EAAE,CAAC,KAAK,OAAO,UAAU,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AAC9E;AAmBO,SAAS,mBACd,UACA,UACuB;AACvB,QAAM,SAAS,oBAAI,IAAiC;AACpD,aAAW,OAAO,SAAU,QAAO,IAAI,IAAI,QAAQ,GAAG;AACtD,aAAW,OAAO,SAAU,QAAO,IAAI,IAAI,QAAQ,GAAG;AACtD,SAAO,CAAC,GAAG,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,KAAK,MAAM,EAAE,SAAS,IAAI,KAAK,MAAM,EAAE,SAAS,CAAC;AAC9F;AAeO,SAAS,gBAAgB,OAAkC;AAChE,QAAM,QAAQ,MAAM,UAAU,IAAI,MAAM,UAAU;AAClD,SAAO,CAAC,GAAG,MAAM,KAAK,EACnB,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO,EACpC,IAAI,CAAC,SAAS;AACb,UAAM,OAAO,KAAK,QAAQ,CAAC;AAC3B,UAAM,SACJ,KAAK,OAAO,SAAU,OAAO,KAAK,WAAW,YAAY,aAAa,KAAK,MAAM,MAAM;AACzF,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,KAAM,KAAK,UAAU,QAAS,GAAG,CAAC;AAAA,MAClE,UAAU,KAAK,IAAI,KAAK,KAAK,IAAI,MAAO,KAAK,QAAQ,KAAK,WAAW,QAAS,GAAG,CAAC;AAAA,MAClF,eAAe,KAAK,KAAK,QAAQ,KAAK,WAAW,KAAM,QAAQ,CAAC,CAAC,IAAI,KAAK,SAAS,MAAM,EAAE;AAAA,MAC3F,QAAQ,KAAK,WAAW;AAAA,MACxB,IAAI,CAAC;AAAA,IACP;AAAA,EACF,CAAC;AACL;AAIA,SAAS,aAAa,EAAE,UAAU,GAA2B;AAC3D,SACE,gBAAAD,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,KAAC,UAAK,GAAE,gBAAe,GACzB;AAEJ;AAEA,SAAS,aAAa,EAAE,UAAU,GAA2B;AAC3D,SACE,gBAAAA,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,KAAC,UAAK,GAAE,wCAAuC,GACjD;AAEJ;AAEA,SAAS,UAAU,EAAE,UAAU,GAA2B;AACxD,SACE,gBAAAC,MAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,IAChD,gBAAAA,KAAC,UAAK,GAAE,2DAA0D;AAAA,KACpE;AAEJ;AAKA,SAAS,YAAY,EAAE,QAAQ,GAAwB;AACrD,QAAM,CAAC,QAAQ,SAAS,IAAIE,WAAS,KAAK;AAC1C,QAAM,OAAOC,aAAY,MAAM;AAC7B,SAAK,UAAU,WAAW,UAAU,OAAO,EAAE;AAAA,MAC3C,MAAM;AACJ,kBAAU,IAAI;AACd,mBAAW,MAAM,UAAU,KAAK,GAAG,IAAI;AAAA,MACzC;AAAA,MACA,MAAM;AAAA,MAAC;AAAA,IACT;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AACZ,SACE,gBAAAF;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS;AAAA,MACT,OAAM;AAAA,MACN,cAAW;AAAA,MACX,WAAU;AAAA,MAEV;AAAA,wBAAAD,KAAC,UAAK,WAAU,YAAY,mBAAQ;AAAA,QACpC,gBAAAA,KAAC,aAAU,WAAU,oBAAmB;AAAA,QACvC,UAAU,gBAAAA,KAAC,UAAK,WAAU,oCAAmC,oBAAM;AAAA;AAAA;AAAA,EACtE;AAEJ;AAEA,SAAS,UAAU,EAAE,KAAK,GAA2B;AACnD,SACE,gBAAAC,MAAC,UAAK,WAAU,4BACd;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,eAAW;AAAA,QACX,WAAW,iCACT,SAAS,SAAS,6BAA6B,SAAS,OAAO,eAAe,SAAS,UAAU,mBAAmB,wBACtH;AAAA;AAAA,IACF;AAAA,IACA,gBAAAA,KAAC,UAAK,WAAU,WAAW,gBAAK;AAAA,KAClC;AAEJ;AAIA,IAAM,YAAkD;AAAA,EACtD,UAAU;AAAA,EACV,OAAO;AAAA,EACP,MAAM;AACR;AAQO,SAAS,cAAc,EAAE,MAAM,GAAuB;AAC3D,QAAM,OAAO,gBAAgB,KAAK;AAClC,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,QAAM,OAAO,mBAAmB,MAAM,OAAO;AAC7C,SACE,gBAAAC,MAAC,SAAI,WAAU,aACZ;AAAA,SAAK,IAAI,CAAC,KAAK,MACd,gBAAAA,MAAC,SAAY,WAAU,wEACrB;AAAA,sBAAAD,KAAC,UAAK,WAAU,wDAAuD,OAAO,IAAI,MAC/E,cAAI,MACP;AAAA,MACA,gBAAAA,KAAC,SAAI,WAAU,wCACb,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,iCAAiC,IAAI,KAAK,UAAU,IAAI,IAAI,IAAI,mBAAmB,IAAI,IAAI,SAAS,eAAe,EAAE;AAAA,UAChI,OAAO,EAAE,MAAM,GAAG,IAAI,SAAS,KAAK,OAAO,GAAG,IAAI,QAAQ,IAAI;AAAA;AAAA,MAChE,GACF;AAAA,MACA,gBAAAA,KAAC,UAAK,WAAU,wEAAwE,cAAI,eAAc;AAAA,SAVlG,CAWV,CACD;AAAA,IACD,gBAAAC,MAAC,OAAE,WAAU,iFACT;AAAA,aAAM,UAAU,KAAM,QAAQ,CAAC;AAAA,MAAE;AAAA,MAAE,OAAO,SAAM,IAAI,KAAK;AAAA,OAC7D;AAAA,KACF;AAEJ;AAiBO,SAAS,oBAAoB,EAAE,UAAU,WAAW,MAAM,GAA6B;AAC5F,QAAM,CAAC,UAAU,WAAW,IAAIC,WAAS,KAAK;AAC9C,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,SACE,gBAAAD,MAAC,SAAI,WAAU,oCACZ;AAAA,aAAS,IAAI,CAAC,QAAQ;AACrB,YAAM,OAAO,aAAa,IAAI,MAAM;AACpC,YAAM,OAAO,mBAAmB,IAAI,OAAO;AAC3C,YAAM,WAAW,uBAAuB,IAAI,UAAU;AACtD,aACE,gBAAAA,MAAC,SAAqB,WAAU,wCAC9B;AAAA,wBAAAD,KAAC,aAAU,MAAY;AAAA,QACvB,gBAAAC,MAAC,UAAK,WAAU,2BACd;AAAA,0BAAAD,KAAC,UAAK,WAAU,eAAe,cAAI,MAAK;AAAA,UACxC,gBAAAC,MAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,YAAI,IAAI;AAAA,aAAO;AAAA,WACzD;AAAA,QACC,SAAS,WAAW,IAAI,cAAc,UAAa,IAAI,UAAU,WAChE,gBAAAD,KAAC,UAAK,WAAU,wFACb,WAAC,IAAI,cAAc,SAAY,QAAQ,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,IAAI,EAC9E,OAAO,OAAO,EACd,KAAK,QAAK,GACf;AAAA,QAEF,gBAAAC,MAAC,UAAK,WAAU,kGACb;AAAA,mBAAS,UAAU,SAAS,QAAQ,gBAAAD,KAAC,UAAM,cAAI,QAAO;AAAA,UACtD,QAAQ,gBAAAA,KAAC,UAAM,gBAAK;AAAA,UACpB,YAAY,gBAAAA,KAAC,UAAM,oBAAS;AAAA,WAC/B;AAAA,WAjBQ,IAAI,MAkBd;AAAA,IAEJ,CAAC;AAAA,IACD,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;AAAA,QACpC,WAAU;AAAA,QAEV;AAAA,0BAAAD,KAAC,gBAAa,WAAW,gCAAgC,WAAW,eAAe,EAAE,IAAI;AAAA,UAAE;AAAA;AAAA;AAAA,IAE7F;AAAA,IACC,YACC,gBAAAA,KAAC,SAAI,WAAU,oDACb,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,sBAAsB,UAAU;AAAA,UACrC,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,UAC/C,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,QACzC,CAAC;AAAA;AAAA,IACH,GACF;AAAA,KAEJ;AAEJ;AAeA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,MAAM,OAAO,IAAIE,WAAS,KAAK;AACtC,QAAM,OAAO,aAAa,OAAO,MAAM;AACvC,QAAM,OAAO,mBAAmB,OAAO,OAAO;AAC9C,QAAM,WAAW,uBAAuB,OAAO,UAAU;AAEzD,SACE,gBAAAD,MAAC,SAAI,WAAU,8CACb;AAAA,oBAAAA,MAAC,YAAO,MAAK,UAAS,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,WAAU,gEACjE;AAAA,sBAAAD,KAAC,aAAU,MAAY;AAAA,MACvB,gBAAAC,MAAC,UAAK,WAAU,2BACd;AAAA,wBAAAD,KAAC,UAAK,WAAU,eAAe,iBAAO,MAAK;AAAA,QAC3C,gBAAAC,MAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,UAAI,OAAO;AAAA,WAAO;AAAA,SAC5D;AAAA,MACC,SAAS,WAAW,OAAO,cAAc,UAAa,OAAO,UAAU,WACtE,gBAAAD,KAAC,UAAK,WAAU,sFACb,WAAC,OAAO,cAAc,SAAY,QAAQ,OAAO,SAAS,KAAK,MAAM,OAAO,SAAS,IAAI,EACvF,OAAO,OAAO,EACd,KAAK,QAAK,GACf;AAAA,MAEF,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,6DACT,SAAS,OACL,+BACA,SAAS,UACP,uCACA,SAAS,SACP,+BACA,oCACV;AAAA,UAEC,iBAAO;AAAA;AAAA,MACV;AAAA,MACC,QAAQ,gBAAAA,KAAC,UAAK,WAAU,qEAAqE,gBAAK;AAAA,MACnG,gBAAAA,KAAC,gBAAa,WAAW,+DAA+D,OAAO,eAAe,EAAE,IAAI;AAAA,OACtH;AAAA,IACC,QACC,gBAAAC,MAAC,SAAI,WAAU,kDACZ;AAAA,aAAO,eAAe,UACrB,gBAAAD,KAAC,SAAI,WAAU,oDACb,0BAAAA,KAAC,iBAAc,OAAO,sBAAsB,CAAC,MAAM,CAAC,GAAG,GACzD;AAAA,MAEF,gBAAAC,MAAC,QAAG,WAAU,mEACZ;AAAA,wBAAAD,KAAC,QAAG,WAAU,4BAA2B,kBAAI;AAAA,QAC7C,gBAAAA,KAAC,QAAG,WAAU,kCAAkC,iBAAO,QAAO;AAAA,QAC9D,gBAAAA,KAAC,QAAG,WAAU,4BAA2B,qBAAO;AAAA,QAChD,gBAAAA,KAAC,QAAG,WAAU,yBAAyB,cAAI,KAAK,OAAO,SAAS,EAAE,eAAe,GAAE;AAAA,QAClF,YACC,gBAAAC,MAAAF,WAAA,EACE;AAAA,0BAAAC,KAAC,QAAG,WAAU,4BAA2B,sBAAQ;AAAA,UACjD,gBAAAA,KAAC,QAAG,WAAU,yBAAyB,oBAAS;AAAA,WAClD;AAAA,QAED,OAAO,WACN,gBAAAC,MAAAF,WAAA,EACE;AAAA,0BAAAC,KAAC,QAAG,WAAU,4BAA2B,mBAAK;AAAA,UAC9C,gBAAAA,KAAC,QAAG,WAAU,WACZ,0BAAAA,KAAC,eAAY,SAAS,OAAO,SAAS,GACxC;AAAA,WACF;AAAA,SAEJ;AAAA,MACC,OAAO,cAAc,mBAAmB,OAAO,YAAY,MAAM;AAAA,OACpE;AAAA,KAEJ;AAEJ;AAkBO,SAAS,mBAAmB,EAAE,eAAe,kBAAkB,QAAQ,kBAAkB,aAAa,qBAAqB,GAA4B;AAC5J,QAAM,CAAC,MAAM,OAAO,IAAIE,WAAgC,CAAC,CAAC;AAC1D,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAA6B,MAAS;AAClE,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAA8B,SAAS;AACnE,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAwB,IAAI;AAEtD,QAAM,OAAOC;AAAA,IACX,OAAO,SAAkB;AACvB,gBAAU,SAAS;AACnB,eAAS,IAAI;AACb,UAAI;AACF,cAAM,OAAO,MAAM,cAAc,IAAI;AACrC,gBAAQ,CAAC,SAAS,mBAAmB,SAAS,SAAY,CAAC,IAAI,MAAM,KAAK,KAAK,CAAC;AAChF,kBAAU,KAAK,UAAU;AACzB,kBAAU,OAAO;AAAA,MACnB,SAAS,GAAG;AACV,iBAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AACnD,kBAAU,OAAO;AAAA,MACnB;AAAA,IACF;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,EAAAC,WAAU,MAAM;AACd,SAAK,KAAK;AAAA,EACZ,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,UAAU,WAAW;AAE3B,SACE,gBAAAH,MAAC,SAAI,WAAU,aACb;AAAA,oBAAAA,MAAC,SAAI,WAAU,2BACb;AAAA,sBAAAD,KAAC,QAAG,WAAU,gCAAgC,iBAAM;AAAA,MACpD,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,KAAK;AAAA,UACzB,UAAU;AAAA,UACV,cAAW;AAAA,UACX,WAAU;AAAA,UAEV,0BAAAA,KAAC,gBAAa,WAAW,eAAe,UAAU,iBAAiB,EAAE,IAAI;AAAA;AAAA,MAC3E;AAAA,OACF;AAAA,IACC,WAAW,WACV,gBAAAA,KAAC,OAAE,MAAK,SAAQ,WAAU,+FACvB,iBACH;AAAA,IAED,WAAW,WAAW,KAAK,WAAW,KAAK,gBAAAA,KAAC,OAAE,WAAU,sCAAsC,sBAAW;AAAA,IAO1G,gBAAAA,KAAC,UAAK,MAAK,UAAS,aAAU,UAAS,aAAW,SAAS,WAAU,WAClE,oBAAU,2BAAsB,IACnC;AAAA,IACA,gBAAAA,KAAC,SAAI,WAAU,eAAc,aAAW,SACrC,eAAK,IAAI,CAAC,WACT,gBAAAA,KAAC,eAAgC,QAAgB,oBAA/B,OAAO,MAA4D,CACtF,GACH;AAAA,IACC,UACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,KAAK,KAAK,MAAM;AAAA,QAC/B,UAAU;AAAA,QACV,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KAEJ;AAEJ;;;ACjcA,SAAS,eAAAK,cAAa,aAAAC,YAAW,OAAO,UAAAC,SAAQ,YAAAC,kBAAoD;;;ACA7F,IAAM,mBAA+C,CAAC,aAAa,WAAW,YAAY,UAAU;AAc3G,IAAM,aAA2D;AAAA,EAC/D,WAAW;AAAA,IACT,OAAO;AAAA,IACP,SAAS;AAAA,IACT,kBAAkB;AAAA,EACpB;AAAA,EACA,SAAS;AAAA,IACP,OAAO;AAAA,IACP,SAAS;AAAA,IACT,kBAAkB;AAAA,EACpB;AAAA,EACA,UAAU;AAAA,IACR,OAAO;AAAA,IACP,SAAS;AAAA,IACT,kBAAkB;AAAA,EACpB;AAAA,EACA,UAAU;AAAA,IACR,OAAO;AAAA,IACP,SAAS;AAAA,IACT,kBAAkB;AAAA,EACpB;AACF;AAGO,SAAS,oBAAoB,OAA6C;AAC/E,SAAO,WAAW,KAAK;AACzB;AA2CA,IAAM,gBAAoE;AAAA,EACxE,SAAS,EAAE,OAAO,UAAU,QAAQ,0EAAqE;AAAA,EACzG,OAAO,EAAE,OAAO,oBAAoB,QAAQ,gEAAgE;AAAA,EAC5G,SAAS,EAAE,OAAO,kBAAkB,QAAQ,uDAAuD;AACrG;AAGO,SAAS,uBAAuB,UAAsD;AAC3F,SAAO,cAAc,QAAQ;AAC/B;AAEA,IAAM,oBAAwD,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,EAAE;AAG1F,SAAS,yBAAyB,GAAuB,GAA2C;AACzG,SAAO,kBAAkB,CAAC,KAAK,kBAAkB,CAAC,IAAI,IAAI;AAC5D;AAgBO,IAAM,uCAAmE;AAAA,EAC9E,kBAAkB;AAAA,EAClB,gBAAgB;AAClB;AA+BO,SAAS,uBACd,YACA,SAAqC,sCACjB;AACpB,MAAI,cAAc,OAAO,iBAAkB,QAAO;AAClD,MAAI,cAAc,OAAO,eAAgB,QAAO;AAChD,SAAO;AACT;AAGA,SAAS,kBAAkB,OAA4C;AAGrE,SAAO,UAAU,aAAa,UAAU;AAC1C;AAgBO,SAAS,+BAA+B,QAAyC;AACtF,MAAI,OAAO,WAAW,UAAW,QAAO,cAAc,OAAO,KAAK;AAClE,MAAI,OAAO,WAAW,eAAe;AACnC,WAAO,OAAO,oBACV,GAAG,OAAO,KAAK,+BAA0B,OAAO,iBAAiB,KACjE,GAAG,OAAO,KAAK;AAAA,EACrB;AACA,SAAO;AACT;AAOO,SAAS,eAAe,QAA2C;AACxE,QAAM,OAAwB,CAAC;AAC/B,QAAM,UAAU,OAAO,WAAW,CAAC;AACnC,MAAI,OAAO,UAAU,eAAe,QAAQ,WAAW,GAAG;AACxD,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,MAAI,OAAO,UAAU,eAAe,OAAO,UAAU,CAAC,GAAG,WAAW,GAAG;AACrE,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,aAAW,UAAU,SAAS;AAC5B,QAAI,OAAO,WAAW,cAAe;AACrC,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,SAAS,+BAA+B,MAAM,KAAK,GAAG,OAAO,KAAK;AAAA,MAClE;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAIO,SAAS,yBAAyB,QAA8C;AACrF,UAAQ,OAAO,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,OAAO,WAAW,SAAS;AAC9E;AAgBO,SAAS,0BACd,QACA,SAAqC,sCACjB;AACpB,MAAI,WACF,OAAO,aACN,OAAO,eAAe,SAAY,kBAAkB,OAAO,KAAK,IAAI,uBAAuB,OAAO,YAAY,MAAM;AAEvH,MAAI,OAAO,UAAU,WAAY,YAAW,yBAAyB,UAAU,OAAO;AACtF,aAAW,OAAO,eAAe,MAAM,GAAG;AACxC,eAAW,yBAAyB,UAAU,IAAI,SAAS,uBAAuB,UAAU,SAAS;AAAA,EACvG;AACA,SAAO;AACT;AAYO,SAAS,yBACd,QACA,SAAqC,sCACrC,OAA8B,oBAAI,IAAI,GAClB;AACpB,MAAI,KAAK,IAAI,MAAM,EAAG,QAAO;AAC7B,OAAK,IAAI,MAAM;AACf,MAAI,WAAW,0BAA0B,QAAQ,MAAM;AACvD,aAAW,SAAS,OAAO,UAAU,CAAC,GAAG;AACvC,eAAW,yBAAyB,UAAU,yBAAyB,OAAO,QAAQ,IAAI,CAAC;AAAA,EAC7F;AACA,SAAO;AACT;AAEA,SAAS,aAAa,QAAkC;AACtD,SAAO,OAAO,UAAU,GAAG,OAAO,KAAK,KAAK,OAAO,OAAO,KAAK,OAAO;AACxE;AAEA,SAAS,YAAY,OAAiC;AACpD,SAAO,MAAM,SAAS,MAAM;AAC9B;AAOO,SAAS,mBAAmB,QAAkC;AACnE,QAAM,UAAU,OAAO,WAAW,CAAC;AACnC,QAAM,QAAQ,QAAQ,CAAC;AACvB,QAAM,OAAO,QAAQ,SAAS,IAAI,QAAQ,QAAQ,SAAS,CAAC,eAAe,QAAQ,SAAS,IAAI,MAAM,EAAE,KAAK;AAE7G,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AACH,aAAO,QAAQ,aAAa,aAAa,KAAK,CAAC,GAAG,IAAI,MAAM;AAAA,IAC9D,KAAK;AACH,aAAO,QAAQ,cAAc,aAAa,KAAK,CAAC,MAAM;AAAA,IACxD,KAAK,YAAY;AACf,YAAM,SAAS,OAAO,UAAU,CAAC;AACjC,UAAI,OAAO,WAAY,QAAO,iBAAiB,OAAO,UAAU;AAChE,UAAI,OAAO,WAAW,EAAG,QAAO;AAChC,aAAO,iBAAiB,OAAO,IAAI,WAAW,EAAE,KAAK,IAAI,CAAC;AAAA,IAC5D;AAAA,IACA,KAAK;AACH,aAAO,QACH,oCAAoC,aAAa,KAAK,CAAC,qCACvD;AAAA,EACR;AACF;AAUO,SAAS,mBACd,QACA,UACA,SAAqC,sCAC7B;AACR,QAAM,UAAU,uBAAuB,QAAQ,EAAE;AACjD,MAAI,aAAa,UAAW,QAAO;AAEnC,QAAM,OAAO,eAAe,MAAM;AAClC,MAAI,KAAK,KAAK,CAAC,QAAQ,IAAI,SAAS,WAAW,GAAG;AAChD,WAAO;AAAA,EACT;AACA,MAAI,KAAK,KAAK,CAAC,QAAQ,IAAI,SAAS,WAAW,GAAG;AAChD,WAAO;AAAA,EACT;AACA,MAAI,KAAK,KAAK,CAAC,QAAQ,IAAI,SAAS,oBAAoB,GAAG;AACzD,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,eAAe,OAAO,WAAW,CAAC,GAAG,WAAW,GAAG;AACtE,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,UAAU,eAAe,OAAO,UAAU,CAAC,GAAG,SAAS,KAAK,0BAA0B,QAAQ,MAAM,MAAM,WAAW;AAC9H,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAOO,SAAS,uBAAuB,QAA0B,UAAsC;AACrG,QAAM,QAAQ,OAAO,QAAQ,KAAK,MAAM,KAAK,uBAAuB,SAAI,OAAO,OAAO;AACtF,QAAM,QAAQ,OAAO,QAAQ,GAAG,OAAO,KAAK,IAAI,KAAK,KAAK;AAC1D,QAAM,QAAQ,oBAAoB,OAAO,KAAK,EAAE;AAChD,QAAM,OAAO,aAAa,YAAY,KAAK,IAAI,uBAAuB,QAAQ,EAAE,KAAK;AACrF,SAAO,SAAS,KAAK,qBAAgB,KAAK,IAAI,IAAI;AACpD;;;ADtTQ,SACE,OAAAC,MADF,QAAAC,aAAA;AA3BR,IAAM,cAA+C;AAAA,EACnD,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU;AAAA,EACV,UAAU;AACZ;AAEA,IAAM,iBAAqD;AAAA,EACzD,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AACX;AAEA,SAAS,WAAW,EAAE,OAAO,UAAU,GAAmD;AACxF,QAAM,SAAS;AAAA,IACb,SAAS;AAAA,IACT,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf;AAAA,EACF;AACA,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aACE,gBAAAA,MAAC,SAAK,GAAG,QACP;AAAA,wBAAAD,KAAC,UAAK,GAAE,8DAA6D;AAAA,QACrE,gBAAAA,KAAC,cAAS,QAAO,kBAAiB;AAAA,QAClC,gBAAAA,KAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,SACvC;AAAA,IAEJ,KAAK;AACH,aACE,gBAAAC,MAAC,SAAK,GAAG,QACP;AAAA,wBAAAD,KAAC,UAAK,GAAE,6CAA4C;AAAA,QACpD,gBAAAA,KAAC,YAAO,IAAG,MAAK,IAAG,KAAI,GAAE,KAAI;AAAA,SAC/B;AAAA,IAEJ,KAAK;AACH,aACE,gBAAAC,MAAC,SAAK,GAAG,QACP;AAAA,wBAAAD,KAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,KAAI;AAAA,QACnC,gBAAAA,KAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,QACrC,gBAAAA,KAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK;AAAA,QACpC,gBAAAA,KAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,SACvC;AAAA,IAEJ,KAAK;AACH,aACE,gBAAAC,MAAC,SAAK,GAAG,QACP;AAAA,wBAAAD,KAAC,UAAK,GAAE,wGAAuG;AAAA,QAC/G,gBAAAA,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,OAAM;AAAA,SAClC;AAAA,EAEN;AACF;AAYA,IAAM,aAAa,oBAAI,IAAe;AAWtC,SAAS,mBAAmB,MAAgC;AAC1D,aAAW,SAAS,MAAM,KAAK,UAAU,GAAG;AAC1C,QAAI,SAAS,QAAQ,CAAC,MAAM,KAAK,SAAS,IAAI,EAAG,OAAM,MAAM;AAAA,EAC/D;AACF;AAsCA,IAAM,8BAA8B;AAIpC,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,aAAa,+BAA+B,MAAM;AACxD,QAAM,WAAW,WAAW,YAAY,iBAAiB,UAAa,OAAO,SAAS;AAEtF,SACE,gBAAAC,MAAC,QAAG,WAAU,0DACZ;AAAA,oBAAAA,MAAC,SAAI,WAAU,iDACb;AAAA,sBAAAD,KAAC,UAAK,WAAU,2CAA2C,iBAAO,OAAM;AAAA,MACvE,OAAO,WAAW,gBAAAA,KAAC,UAAK,WAAU,qCAAqC,iBAAO,SAAQ;AAAA,MACtF,aACE,eACC,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,aAAa,QAAQ,MAAM;AAAA,UAC1C,WAAU;AAAA,UACX;AAAA;AAAA,YACO,OAAO;AAAA;AAAA;AAAA,MACf,IAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,OAAO;AAAA,UACb,QAAO;AAAA,UACP,KAAI;AAAA,UACJ,WAAU;AAAA,UACX;AAAA;AAAA,YACO,OAAO;AAAA;AAAA;AAAA,MACf;AAAA,OAEN;AAAA,IACC,OAAO,SACN,gBAAAA,MAAC,gBAAW,WAAU,0FAAyF;AAAA;AAAA,MAC3G,OAAO;AAAA,MAAM;AAAA,OACjB;AAAA,IAED;AAAA;AAAA;AAAA;AAAA,IAKC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW,oBAAoB,WAAW,gBAAgB,qBAAqB,uBAAuB;AAAA,QAErG;AAAA;AAAA,UACA,WAAW,iBAAiB,iBAC3B,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,cAAc,QAAQ,MAAM;AAAA,cAC3C,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA;AAAA;AAAA,IAEJ;AAAA,KAEJ;AAEJ;AAUO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB;AACF,GAAyB;AACvB,QAAM,CAAC,MAAM,OAAO,IAAIE,WAAS,WAAW;AAC5C,QAAM,aAAaC,QAAiC,IAAI;AACxD,QAAM,UAAUA,QAA8B,IAAI;AAClD,QAAM,UAAU,MAAM;AAEtB,QAAM,WAAW,yBAAyB,QAAQ,gBAAgB;AAClE,QAAM,YAAY,oBAAoB,OAAO,KAAK;AAClD,QAAM,eAAe,uBAAuB,QAAQ;AACpD,QAAM,OAAO,eAAe,MAAM;AAClC,QAAM,UAAU,yBAAyB,MAAM;AAC/C,QAAM,UAAU,OAAO,WAAW,CAAC;AACnC,QAAM,SAAS,OAAO,UAAU,CAAC;AACjC,QAAM,WAAW,OAAO,QAAQ,KAAK,MAAM;AAK3C,QAAM,YAAYC;AAAA,IAChB,CAAC,UAAyC;AACxC,UAAI,MAAM,QAAQ,YAAY,CAAC,KAAM;AACrC,YAAM,gBAAgB;AACtB,cAAQ,KAAK;AACb,iBAAW,SAAS,MAAM;AAAA,IAC5B;AAAA,IACA,CAAC,IAAI;AAAA,EACP;AAIA,QAAM,WAAWA,aAAY,MAAM;AACjC,QAAI,CAAC,KAAM,oBAAmB,QAAQ,OAAO;AAC7C,YAAQ,CAAC,IAAI;AAAA,EACf,GAAG,CAAC,IAAI,CAAC;AAKT,EAAAC,WAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,QAAQ,SAAS,KAAM;AAE5B,UAAM,QAAmB,EAAE,MAAM,OAAO,MAAM,QAAQ,KAAK,EAAE;AAC7D,eAAW,IAAI,KAAK;AAEpB,UAAM,gBAAgB,CAAC,UAAiB;AACtC,YAAM,SAAS,MAAM;AACrB,UAAI,kBAAkB,QAAQ,KAAK,SAAS,MAAM,EAAG;AACrD,cAAQ,KAAK;AAAA,IACf;AACA,aAAS,iBAAiB,aAAa,eAAe,IAAI;AAC1D,aAAS,iBAAiB,cAAc,eAAe,IAAI;AAE3D,WAAO,MAAM;AACX,iBAAW,OAAO,KAAK;AACvB,eAAS,oBAAoB,aAAa,eAAe,IAAI;AAC7D,eAAS,oBAAoB,cAAc,eAAe,IAAI;AAAA,IAChE;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,UACJ,gBAAAJ,MAAC,UAAK,WAAU,kDACb;AAAA,WAAO,SAAS,gBAAAD,KAAC,UAAK,WAAU,qCAAqC,iBAAO,OAAM;AAAA,IACnF,gBAAAA,KAAC,UAAK,WAAW,WAAW,4BAA4B,wCACrD,qBAAW,OAAO,UAAU,mBAC/B;AAAA,KACF;AAMF,MAAI,YAAY,GAAG;AACjB,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,2BAA2B,aAAa,EAAE;AAAA,QACrD,yBAAuB,OAAO;AAAA,QAC9B,4BAA0B;AAAA,QAEzB;AAAA;AAAA,UACD,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,mGAAmG,YAAY,OAAO,KAAK,CAAC;AAAA,cAEvI;AAAA,gCAAAD,KAAC,cAAW,OAAO,OAAO,OAAO,WAAU,WAAU;AAAA,gBACpD,UAAU;AAAA;AAAA;AAAA,UACb;AAAA,UACA,gBAAAA,KAAC,UAAK,WAAU,kDAAkD,6BAAmB,MAAM,GAAE;AAAA;AAAA;AAAA,IAC/F;AAAA,EAEJ;AAEA,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW,2BAA2B,aAAa,EAAE;AAAA,MACrD;AAAA,MACA,yBAAuB,OAAO;AAAA,MAC9B,4BAA0B;AAAA,MAE1B;AAAA,wBAAAA,MAAC,UAAK,WAAU,gDACb;AAAA;AAAA,UACD,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,MAAK;AAAA,cACL,SAAS;AAAA,cACT,iBAAe;AAAA,cACf,iBAAe;AAAA,cACf,cAAY,uBAAuB,QAAQ,QAAQ;AAAA,cACnD,WAAW,4LAA4L,YAAY,OAAO,KAAK,CAAC;AAAA,cAEhO;AAAA,gCAAAD,KAAC,cAAW,OAAO,OAAO,OAAO,WAAU,WAAU;AAAA,gBACrD,gBAAAA,KAAC,UAAK,eAAW,MAAE,oBAAU,OAAM;AAAA;AAAA;AAAA,UACrC;AAAA,UACC,aAAa;AAAA;AAAA;AAAA,UAIZ,gBAAAA,KAAC,UAAK,eAAW,MAAC,WAAW,2BAA2B,eAAe,QAAQ,CAAC,IAC7E,uBAAa,OAChB;AAAA,WAEJ;AAAA,QAEC,QACC,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,IAAI;AAAA,YACJ,MAAK;AAAA,YACL,cAAY,uBAAuB,QAAQ,QAAQ;AAAA,YACnD,WAAU;AAAA,YAEV;AAAA,8BAAAA,MAAC,SACC;AAAA,gCAAAD,KAAC,OAAE,WAAU,4CAA4C,6BAAmB,MAAM,GAAE;AAAA,gBACpF,gBAAAC,MAAC,OAAE,WAAW,mCAAmC,eAAe,QAAQ,CAAC,IACtE;AAAA,+BAAa;AAAA,kBAAM;AAAA,kBAAI,mBAAmB,QAAQ,UAAU,gBAAgB;AAAA,mBAC/E;AAAA,gBACC,UAAU,qBAAqB,QAC9B,gBAAAA,MAAC,OAAE,WAAU,yDACV;AAAA,4BAAU;AAAA,kBAAQ;AAAA,mBACrB;AAAA,iBAEJ;AAAA,cAEC,QAAQ,SAAS,KAChB,gBAAAD,KAAC,QAAG,WAAU,eACX,kBAAQ,IAAI,CAAC,QAAQ,UACpB,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBAEC;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA;AAAA,gBAJK,GAAG,OAAO,KAAK,IAAI,OAAO,WAAW,EAAE,IAAI,KAAK;AAAA,cAKvD,CACD,GACH;AAAA,cAGD,KACE,OAAO,CAAC,QAAQ,IAAI,SAAS,oBAAoB,EACjD,IAAI,CAAC;AAAA;AAAA;AAAA,gBAGJ,gBAAAA,KAAC,OAAiB,WAAU,sFACzB,cAAI,WADC,IAAI,IAEZ;AAAA,eACD;AAAA,cAEF,QAAQ,SAAS,KAAK,QAAQ,WAAW,KACxC,gBAAAA,KAAC,OAAE,MAAK,UAAS,WAAU,qCAAoC,mDAE/D;AAAA,cAGD,OAAO,SAAS,KACf,gBAAAC,MAAC,SAAI,WAAU,+BACb;AAAA,gCAAAD,KAAC,OAAE,WAAU,yEACV,iBAAO,aAAa,iBAAiB,OAAO,UAAU,KAAK,iBAC9D;AAAA,gBACA,gBAAAA,KAAC,QAAG,WAAU,sBACX,iBAAO,IAAI,CAAC,OAAO,UAClB,gBAAAA,KAAC,QACC,0BAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,QAAQ;AAAA,oBACR;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA,UAAU,WAAW;AAAA,oBACrB;AAAA;AAAA,gBACF,KARO,GAAG,MAAM,SAAS,MAAM,OAAO,IAAI,KAAK,EASjD,CACD,GACH;AAAA,iBACF;AAAA;AAAA;AAAA,QAEJ;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAaO,SAAS,iBAAiB,EAAE,OAAO,UAAU,GAA0B;AAC5E,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SACE,gBAAAA,KAAC,QAAG,WAAW,iDAAiD,aAAa,EAAE,IAC5E,gBAAM,IAAI,CAAC,UAAU;AACpB,UAAM,OAAO,oBAAoB,KAAK;AACtC,WACE,gBAAAC,MAAC,QAAe,WAAU,+DACxB;AAAA,sBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,4FAA4F,YAAY,KAAK,CAAC;AAAA,UAEzH;AAAA,4BAAAD,KAAC,cAAW,OAAc,WAAU,WAAU;AAAA,YAC7C,KAAK;AAAA;AAAA;AAAA,MACR;AAAA,MACA,gBAAAA,KAAC,UAAM,eAAK,SAAQ;AAAA,SAPb,KAQT;AAAA,EAEJ,CAAC,GACH;AAEJ;;;AEnbM,SAkDI,YAAAM,WAlDJ,OAAAC,OAOF,QAAAC,aAPE;AArBN,SAAS,IAAI,OAAuB;AAClC,SAAO,IAAI,KAAK,aAAa,SAAS;AAAA,IACpC,OAAO;AAAA,IACP,UAAU;AAAA,IACV,uBAAuB,QAAQ,QAAQ,IAAI,IAAI;AAAA,IAC/C,uBAAuB,QAAQ,QAAQ,IAAI,IAAI;AAAA,EACjD,CAAC,EAAE,OAAO,QAAQ,GAAG;AACvB;AAEA,SAASC,cAAwB;AAC/B,SACE,gBAAAF;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAW;AAAA,MAEX,0BAAAA,MAAC,UAAK,GAAE,mBAAkB;AAAA;AAAA,EAC5B;AAEJ;AAEA,SAAS,QAAQ,EAAE,SAAS,GAAuC;AACjE,SACE,gBAAAC,MAAC,QAAG,WAAU,oDACZ;AAAA,oBAAAD,MAAC,UAAK,WAAU,UACd,0BAAAA,MAACE,aAAA,EAAW,GACd;AAAA,IACA,gBAAAF,MAAC,UAAM,UAAS;AAAA,KAClB;AAEJ;AAOO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,mBAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAgC;AAC9B,QAAM,EAAE,SAAS,IAAI,IAAI,WAAW;AACpC,QAAM,iBAAiB,QAAQ,IAAI,MAAM,UAAU,UAAU,IAAI,IAAI,QAAQ;AAC7E,QAAM,iBAAiB,QACnB,IAAI,MAAM,UAAU,oBAAoB,IACxC,IAAI,gBAAgB;AACxB,QAAM,eAAe,OAAO,gBAAgB;AAC5C,SACE,gBAAAA,MAAC,SAAI,WAAU,4DACb,0BAAAC,MAAC,SAAI,WAAU,mEACb;AAAA,oBAAAD,MAAC,OAAE,WAAU,qEACV,mBACH;AAAA,IACA,gBAAAC,MAAC,QAAG,WAAU,8DAA6D;AAAA;AAAA,MACjE;AAAA,OACV;AAAA,IACC,WAAW,gBAAAD,MAAC,OAAE,WAAU,sCAAsC,mBAAQ;AAAA,IAEtE,eACC,gBAAAC,MAAAF,WAAA,EACE;AAAA,sBAAAE,MAAC,SAAI,WAAU,oCACb;AAAA,wBAAAD,MAAC,UAAK,WAAU,0CACb,cAAI,aAAa,UAAU,GAC9B;AAAA,QACA,gBAAAA,MAAC,UAAK,WAAU,iCAAgC,yBAAW;AAAA,SAC7D;AAAA,MACA,gBAAAC,MAAC,OAAE,WAAU,sCAAqC;AAAA;AAAA,QACtC,IAAI,aAAa,oBAAoB;AAAA,QAAE;AAAA,SACnD;AAAA,MACA,gBAAAA,MAAC,OAAE,WAAU,sCAAqC;AAAA;AAAA,QAC1C;AAAA,QAAe;AAAA,QAAgB;AAAA,QAAe;AAAA,SACtD;AAAA,OACF,IAEA,gBAAAA,MAAAF,WAAA,EACE;AAAA,sBAAAE,MAAC,SAAI,WAAU,oCACb;AAAA,wBAAAD,MAAC,UAAK,WAAU,0CAA0C,0BAAe;AAAA,QACzE,gBAAAA,MAAC,UAAK,WAAU,iCAAgC,iBAAG;AAAA,SACrD;AAAA,MACA,gBAAAC,MAAC,OAAE,WAAU,sCAAqC;AAAA;AAAA,QACtC;AAAA,QAAe;AAAA,SAC3B;AAAA,OACF;AAAA,IAGF,gBAAAD,MAAC,QAAG,WAAU,oBACV,uBAAY;AAAA,MACZ,kBAAkB,OAAO;AAAA,MACzB,GAAG,cAAc;AAAA,IACnB,GAAG,IAAI,CAAC,SAAS,MACf,gBAAAA,MAAC,WAAiB,qBAAJ,CAAY,CAC3B,GACH;AAAA,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU;AAAA,QACV,SAAS,MAAM,IAAI,UAAU;AAAA,QAC7B,WAAU;AAAA,QAET,oBAAU,2BAAsB,YAAY,UAAU,OAAO;AAAA;AAAA,IAChE;AAAA,IACC,YACC,gBAAAA,MAAC,OAAE,WAAU,qDACV,oBACH;AAAA,KAEJ,GACF;AAEJ;;;ACrJA;AAAA,EAGE,eAAAG;AAAA,EACA,aAAAC;AAAA,EACA,SAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OACK;AAkZK,qBAAAC,WACE,OAAAC,OADF,QAAAC,aAAA;AAxXZ,SAAS,aAAa,OAAgB;AACpC,iBAAe,MAAM;AACnB,UAAM;AAAA,EACR,CAAC;AACH;AAWO,SAAS,kBACd,YACA,EAAE,SAAS,MAAM,aAAa,QAAQ,GACF;AACpC,QAAM,CAAC,UAAU,WAAW,IAAIC,WAA6B,IAAI;AACjE,QAAM,cAAcC,aAAY,CAAC,SAA6B,YAAY,IAAI,GAAG,CAAC,CAAC;AACnF,QAAM,gBAAgBC,QAAO,UAAU;AAEvC,EAAAC,WAAU,MAAM;AACd,kBAAc,UAAU;AAAA,EAC1B,GAAG,CAAC,UAAU,CAAC;AAEf,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,YAAY,CAAC,QAAS;AAC3B,QAAI,OAAO,yBAAyB,YAAa;AACjD,UAAM,WAAW,IAAI;AAAA,MACnB,CAAC,YAAY;AACX,YAAI,CAAC,QAAQ,KAAK,CAAC,UAAU,MAAM,cAAc,EAAG;AACpD,YAAI;AACF,wBAAc,QAAQ;AAAA,QACxB,SAAS,OAAO;AACd,uBAAa,KAAK;AAAA,QACpB;AAAA,MACF;AAAA,MACA,EAAE,MAAM,MAAM,WAAW,MAAM,WAAW;AAAA,IAC5C;AACA,aAAS,QAAQ,QAAQ;AACzB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,UAAU,SAAS,MAAM,UAAU,CAAC;AAExC,SAAO;AACT;AA8CA,SAAS,cAAc,MAA2B;AAChD,SAAO,GAAG,KAAK,cAAc,EAAE,IAAI,KAAK,MAAM,IAAI,CAAC,SAAS,KAAK,EAAE,EAAE,KAAK,GAAG,CAAC;AAChF;AAWO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAChB,GAAkD;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIH,WAA2B,YAAY,KAAK;AACtE,QAAM,CAAC,YAAY,aAAa,IAAIA,WAAwB,YAAY,cAAc,IAAI;AAC1F,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAA4D,MAAM;AAC5F,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAS,CAAC;AAE5C,QAAM,SAASE,QAAO,CAAC;AACvB,QAAM,gBAAgBA,QAA+B,IAAI;AACzD,QAAM,mBAAmBA,QAA+B,IAAI;AAC5D,QAAM,iBAAiBA,QAAO,KAAK;AACnC,QAAM,YAAYA,QAAyB,OAAO;AAGlD,QAAM,gBAAgBA,QAAO,UAAU;AACvC,gBAAc,UAAU;AACxB,QAAM,UAAUA,QAAO,EAAE,GAAG,MAAM,UAAU,CAAC;AAC7C,UAAQ,UAAU,EAAE,GAAG,MAAM,UAAU;AACvC,QAAM,UAAUA,QAAO,WAAW;AAClC,UAAQ,UAAU;AAElB,QAAM,gBAAgB,MAAM,MAAM,SAAS;AAC3C,QAAM,UAAUE,SAAQ,MAAM,cAAc,WAAW,GAAG,CAAC,WAAW,CAAC;AAMvE,EAAAD,WAAU,MAAM;AACd,kBAAc,SAAS,MAAM;AAC7B,qBAAiB,SAAS,MAAM;AAChC,mBAAe,UAAU;AACzB,UAAM,MAAM,EAAE,OAAO;AAErB,QAAI,iBAAiB,cAAc,GAAG;AACpC,eAAS,QAAQ,QAAQ,KAAK;AAC9B,oBAAc,QAAQ,QAAQ,cAAc,IAAI;AAChD,eAAS,MAAM;AACf;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,gBAAgB;AACvC,kBAAc,UAAU;AACxB,cAAU,UAAU;AACpB,aAAS,CAAC,CAAC;AACX,kBAAc,IAAI;AAClB,aAAS,cAAc;AAEvB,UAAM,YAAY;AAChB,UAAI;AACF,cAAM,OAAO,MAAM,QAAQ,QAAQ,UAAU,EAAE,GAAG,MAAM,QAAQ,MAAM,QAAQ,WAAW,OAAO,CAAC;AACjG,YAAI,QAAQ,OAAO,QAAS;AAC5B,iBAAS,KAAK,KAAK;AACnB,sBAAc,KAAK,cAAc,IAAI;AACrC,iBAAS,MAAM;AAAA,MACjB,QAAQ;AACN,YAAI,WAAW,OAAO,WAAW,QAAQ,OAAO,QAAS;AACzD,iBAAS,OAAO;AAAA,MAClB;AAAA,IACF,GAAG;AAEH,WAAO,MAAM,WAAW,MAAM;AAAA,EAChC,GAAG,CAAC,GAAG,MAAM,SAAS,eAAe,SAAS,CAAC;AAE/C,QAAM,WAAWF,aAAY,MAAM;AACjC,UAAM,SAAS,cAAc;AAC7B,QAAI,CAAC,UAAU,eAAe,QAAS;AAEvC,UAAM,EAAE,GAAG,UAAU,MAAM,aAAa,WAAW,aAAa,IAAI,QAAQ;AAC5E,UAAM,MAAM,OAAO;AACnB,mBAAe,UAAU;AACzB,cAAU,UAAU;AACpB,UAAM,aAAa,IAAI,gBAAgB;AACvC,qBAAiB,UAAU;AAC3B,aAAS,aAAa;AAEtB,UAAM,YAAY;AAChB,UAAI;AACF,cAAM,OAAO,MAAM,aAAa,EAAE,GAAG,UAAU,MAAM,aAAa,QAAQ,QAAQ,WAAW,OAAO,CAAC;AACrG,YAAI,QAAQ,OAAO,QAAS;AAC5B,iBAAS,CAAC,SAAS,kBAAkB,MAAM,KAAK,KAAK,CAAC;AACtD,sBAAc,KAAK,cAAc,IAAI;AACrC,iBAAS,MAAM;AAAA,MACjB,QAAQ;AACN,YAAI,WAAW,OAAO,WAAW,QAAQ,OAAO,QAAS;AACzD,iBAAS,OAAO;AAAA,MAClB,UAAE;AACA,YAAI,QAAQ,OAAO,QAAS,gBAAe,UAAU;AAAA,MACvD;AAAA,IACF,GAAG;AAAA,EACL,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQA,aAAY,MAAM;AAC9B,QAAI,UAAU,YAAY,OAAQ,UAAS;AAAA,QACtC,cAAa,CAAC,QAAQ,MAAM,CAAC;AAAA,EACpC,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,SAASA,aAAY,MAAM;AAC/B,iBAAa,CAAC,QAAQ,MAAM,CAAC;AAAA,EAC/B,GAAG,CAAC,CAAC;AAEL,EAAAE;AAAA,IACE,MAAM,MAAM;AACV,oBAAc,SAAS,MAAM;AAC7B,uBAAiB,SAAS,MAAM;AAAA,IAClC;AAAA,IACA,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IACA,SAAS,eAAe;AAAA,IACxB,gBAAgB,UAAU;AAAA,IAC1B,eAAe,UAAU;AAAA,IACzB,SAAS,UAAU;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAoCA,IAAM,iBAAsC;AAAA,EAC1C,aAAa;AAAA,EACb,aAAa;AAAA,EACb,cAAc;AAAA,EACd,aAAa;AAAA,EACb,YAAY,CAAC,UAAU,sCAAiC,KAAK;AAAA,EAC7D,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,cAAc;AAAA,EACd,cAAc;AAChB;AAkBO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0C;AACxC,QAAM,OAAO,EAAE,GAAG,gBAAgB,GAAG,OAAO;AAC5C,QAAM,CAAC,cAAc,eAAe,IAAIH,WAAgC,IAAI;AAC5E,QAAM,CAAC,aAAa,cAAc,IAAIA,WAAS,EAAE;AACjD,QAAM,CAAC,cAAc,eAAe,IAAIA,WAAgC,IAAI;AAC5E,QAAM,CAAC,MAAM,OAAO,IAAIA,WAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAwB,IAAI;AAEtD,QAAM,aAAaC,aAAY,CAAC,YAA4B;AAC1D,aAAS,IAAI;AACb,oBAAgB,OAAO;AACvB,mBAAe,QAAQ,SAAS,EAAE;AAAA,EACpC,GAAG,CAAC,CAAC;AAEL,QAAM,aAAaA,aAAY,CAAC,YAA4B;AAC1D,aAAS,IAAI;AACb,oBAAgB,OAAO;AAAA,EACzB,GAAG,CAAC,CAAC;AAEL,QAAM,eAAeA,aAAY,YAAY;AAC3C,QAAI,CAAC,aAAc;AACnB,UAAM,QAAQ,YAAY,KAAK;AAG/B,QAAI,CAAC,SAAS,UAAU,aAAa,OAAO;AAC1C,sBAAgB,IAAI;AACpB;AAAA,IACF;AACA,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,YAAM,cAAc,aAAa,IAAI,KAAK;AAC1C,sBAAgB,IAAI;AACpB,eAAS,WAAW,KAAK,OAAO;AAChC,kBAAY;AAAA,IACd,SAAS,GAAG;AACV,YAAM,UAAU,aAAa,QAAQ,EAAE,UAAU,KAAK;AACtD,eAAS,OAAO;AAChB,eAAS,SAAS,OAAO;AAAA,IAC3B,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF,GAAG,CAAC,cAAc,aAAa,eAAe,QAAQ,WAAW,KAAK,SAAS,KAAK,YAAY,CAAC;AAEjG,QAAM,gBAAgBA,aAAY,YAAY;AAC5C,QAAI,CAAC,aAAc;AACnB,UAAM,kBAAkB,oBAAoB,QAAQ,aAAa,OAAO;AACxE,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,YAAM,cAAc,aAAa,EAAE;AACnC,sBAAgB,IAAI;AACpB,eAAS,WAAW,KAAK,OAAO;AAChC,kBAAY;AACZ,UAAI,gBAAiB,oBAAmB;AAAA,IAC1C,SAAS,GAAG;AACV,YAAM,UAAU,aAAa,QAAQ,EAAE,UAAU,KAAK;AACtD,eAAS,OAAO;AAChB,eAAS,SAAS,OAAO;AAAA,IAC3B,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF,GAAG,CAAC,cAAc,kBAAkB,eAAe,QAAQ,WAAW,kBAAkB,KAAK,SAAS,KAAK,YAAY,CAAC;AAExH,QAAM,UACJ,gBAAAF,MAAAF,WAAA,EACG;AAAA,oBACC,gBAAAE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,KAAK;AAAA,QACZ,SAAS,MAAM,gBAAgB,IAAI;AAAA,QACnC;AAAA,QACA;AAAA,QACA,QACE,gBAAAA,MAAAF,WAAA,EACE;AAAA,0BAAAC,MAAC,gBAAa,SAAS,MAAM,gBAAgB,IAAI,GAAG,UAAU,MAAM,SAAQ,SACzE,eAAK,QACR;AAAA,UACA,gBAAAA,MAAC,gBAAa,SAAS,MAAM,KAAK,aAAa,GAAG,UAAU,QAAQ,CAAC,YAAY,KAAK,GACnF,eAAK,cACR;AAAA,WACF;AAAA,QAGF;AAAA,0BAAAA,MAAC,WAAM,SAAQ,4BAA2B,WAAU,iCACjD,eAAK,aACR;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO;AAAA,cACP,WAAS;AAAA,cACT,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,cAC9C,WAAW,CAAC,MAAM;AAChB,oBAAI,EAAE,QAAQ,WAAW,CAAC,MAAM;AAC9B,oBAAE,eAAe;AACjB,uBAAK,aAAa;AAAA,gBACpB;AAAA,cACF;AAAA,cACA,WAAU;AAAA;AAAA,UACZ;AAAA;AAAA;AAAA,IACF;AAAA,IAGD,gBACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,KAAK;AAAA,QACZ,SAAS,MAAM,gBAAgB,IAAI;AAAA,QACnC;AAAA,QACA;AAAA,QACA,QACE,gBAAAC,MAAAF,WAAA,EACE;AAAA,0BAAAC,MAAC,gBAAa,SAAS,MAAM,gBAAgB,IAAI,GAAG,UAAU,MAAM,SAAQ,SACzE,eAAK,QACR;AAAA,UACA,gBAAAA,MAAC,gBAAa,SAAS,MAAM,KAAK,cAAc,GAAG,UAAU,MAAM,SAAQ,eACxE,eAAK,cACR;AAAA,WACF;AAAA,QAGF,0BAAAA,MAAC,OAAE,WAAU,iCAAiC,eAAK,WAAW,aAAa,YAAY,CAAC,GAAE;AAAA;AAAA,IAC5F;AAAA,KAEJ;AAGF,SAAO,EAAE,YAAY,YAAY,SAAS,KAAK;AACjD;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AACZ,GAKG;AACD,QAAM,OACJ,YAAY,UACR,gEACA,YAAY,gBACV,gEACA;AACR,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAW,0EAA0E,IAAI;AAAA,MAExF;AAAA;AAAA,EACH;AAEJ;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AAGD,EAAAK,WAAU,MAAM;AACd,UAAM,QAAQ,CAAC,MAAqB;AAClC,UAAI,EAAE,QAAQ,YAAY,CAAC,KAAM,SAAQ;AAAA,IAC3C;AACA,aAAS,iBAAiB,WAAW,KAAK;AAC1C,WAAO,MAAM,SAAS,oBAAoB,WAAW,KAAK;AAAA,EAC5D,GAAG,CAAC,MAAM,OAAO,CAAC;AAElB,SACE,gBAAAJ,MAAC,SAAI,WAAU,2DACb;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS,MAAM;AACb,cAAI,CAAC,KAAM,SAAQ;AAAA,QACrB;AAAA,QACA,eAAW;AAAA;AAAA,IACb;AAAA,IACA,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,cAAY;AAAA,QACZ,WAAW,8EAA8E,cAAc;AAAA,QAEvG;AAAA,0BAAAD,MAAC,QAAG,WAAU,yCAAyC,iBAAM;AAAA,UAC7D,gBAAAA,MAAC,SAAI,WAAU,QAAQ,UAAS;AAAA,UAC/B,SACC,gBAAAA,MAAC,OAAE,MAAK,SAAQ,WAAU,wEACvB,iBACH;AAAA,UAEF,gBAAAA,MAAC,SAAI,WAAU,+BAA+B,kBAAO;AAAA;AAAA;AAAA,IACvD;AAAA,KACF;AAEJ;AAkEA,SAAS,WAAW,EAAE,IAAI,WAAW,SAAS,GAAkB;AAC9D,SACE,gBAAAA,MAAC,OAAE,MAAM,IAAI,WACV,UACH;AAEJ;AAEA,IAAM,SAAS;AACf,IAAM,OAAO,KAAK;AAClB,IAAM,MAAM,KAAK;AAIV,SAAS,uBAAuB,SAAgC;AACrE,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,KAAK,KAAK,MAAM,OAAO;AAC7B,MAAI,OAAO,MAAM,EAAE,EAAG,QAAO;AAC7B,QAAM,QAAQ,KAAK,IAAI,IAAI;AAC3B,MAAI,QAAQ,OAAQ,QAAO;AAC3B,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK,MAAM,QAAQ,MAAM,CAAC;AACtD,MAAI,QAAQ,IAAK,QAAO,GAAG,KAAK,MAAM,QAAQ,IAAI,CAAC;AACnD,MAAI,QAAQ,IAAI,IAAK,QAAO,GAAG,KAAK,MAAM,QAAQ,GAAG,CAAC;AACtD,SAAO,IAAI,KAAK,EAAE,EAAE,mBAAmB,QAAW,EAAE,OAAO,SAAS,KAAK,UAAU,CAAC;AACtF;AAEA,SAAS,eAAe;AAKtB,SACE,gBAAAC,MAAAF,WAAA,EACE;AAAA,oBAAAC,MAAC,UAAK,MAAK,UAAS,aAAU,UAAS,aAAW,MAAM,WAAU,WAAU,oCAE5E;AAAA,IACA,gBAAAA,MAAC,SAAI,WAAU,yBAAwB,eAAW,MAC/C,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,gBAAAC,MAAC,SAAY,WAAU,uCACrB;AAAA,sBAAAD,MAAC,SAAI,WAAU,0CAAyC;AAAA,MACxD,gBAAAA,MAAC,SAAI,WAAU,4CAA2C;AAAA,MAC1D,gBAAAA,MAAC,SAAI,WAAU,mDAAkD;AAAA,SAHzD,CAIV,CACD,GACH;AAAA,KACF;AAEJ;AAEA,SAAS,YAAY,EAAE,UAAU,GAA2B;AAC1D,SACE,gBAAAA,MAAC,SAAI,SAAQ,aAAY,WAAsB,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,MAAC,UAAK,GAAE,iEAAgE,GAC1E;AAEJ;AAUO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe,OAAO;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf;AACF,GAA6B;AAC3B,QAAM,YAAYI,QAA8B,IAAI;AACpD,QAAM,cAAc,kBAAkB,QAAQ,UAAU;AAAA,IACtD,SAAS,QAAQ,WAAW,CAAC,QAAQ,iBAAiB,CAAC,QAAQ;AAAA,IAC/D,MAAM;AAAA,IACN,YAAY;AAAA,EACd,CAAC;AACD,QAAM,aAAa,MAAM,KAAK;AAC9B,QAAM,cAAc,WAAW,SAAS;AACxC,QAAM,SAAS,iBAAiB,SAAS,WAAW;AACpD,QAAM,CAAC,aAAa,cAAc,IAAIF,WAAsB,oBAAI,IAAI,CAAC;AACrE,QAAM,CAAC,SAAS,UAAU,IAAIA,WAAS,IAAI;AAC3C,QAAM,CAAC,YAAY,aAAa,IAAIA,WAI1B,IAAI;AACd,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAS,KAAK;AAC9C,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAwB,IAAI;AAE9D,EAAAG,WAAU,MAAM;AACd,mBAAe,oBAAI,IAAI,CAAC;AAAA,EAC1B,GAAG,CAAC,YAAY,IAAI,CAAC;AAErB,EAAAA,WAAU,MAAM;AACd,UAAM,UAAU,IAAI,IAAI,QAAQ,MAAM,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC;AAC5D,mBAAe,CAAC,YAAY;AAC1B,YAAM,OAAO,IAAI,IAAI,CAAC,GAAG,OAAO,EAAE,OAAO,CAAC,OAAO,QAAQ,IAAI,EAAE,CAAC,CAAC;AACjE,aAAO,KAAK,SAAS,QAAQ,OAAO,UAAU;AAAA,IAChD,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,KAAK,CAAC;AAElB,QAAM,gBAAgB,YAAY;AAClC,QAAM,qBAAqB,QAAQ,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,CAAC,SAAS,YAAY,IAAI,KAAK,EAAE,CAAC;AAC7G,QAAM,gBAAgB,OAAO,OAAO;AACpC,QAAM,eAAe,OAAO,UAAU,aAAa,KAAK,iBAAiB,KAAK,iBAAiB;AAE/F,QAAM,iBAAiBF,aAAY,CAAC,WAA8B;AAChE,UAAM,OAAO,YAAY,YAAY;AACrC,QAAI,OAAO,SAAS,YAAY;AAC9B,oBAAc;AAAA,QACZ;AAAA,QACA,OAAO,GAAG,WAAW;AAAA,QACrB,MAAM,GAAG,SAAS,WAAW,6BAA6B,QAAQ,IAAI,GAAG,IAAI,OAAO,IAAI,MAAM,oBAAoB,OAAO,IAAI,WAAW,IAAI,KAAK,GAAG;AAAA,MACtJ,CAAC;AACD;AAAA,IACF;AACA,UAAM,QAAQ,OAAO,SAAS,eAAe,cAAc,OAAO,IAAI,UAAU,iBAAiB,OAAO,IAAI;AAC5G,kBAAc;AAAA,MACZ;AAAA,MACA,OAAO,GAAG,WAAW,aAAa,KAAK;AAAA,MACvC,MAAM;AAAA,IACR,CAAC;AAAA,EACH,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,oBAAoBA,aAAY,YAAY;AAChD,QAAI,CAAC,cAAc,CAAC,aAAc;AAClC,gBAAY,IAAI;AAChB,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,aAAa,WAAW,MAAM;AACpC,oBAAc,IAAI;AAClB,qBAAe,oBAAI,IAAI,CAAC;AACxB,cAAQ,OAAO;AAAA,IACjB,SAAS,OAAO;AACd,mBAAa,iBAAiB,QAAQ,MAAM,UAAU,aAAa,YAAY,YAAY,CAAC,WAAW;AAAA,IACzG,UAAE;AACA,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,YAAY,aAAa,SAAS,YAAY,CAAC;AAEnD,SACE,gBAAAF,MAAC,SAAI,WAAW,wCAAwC,aAAa,EAAE,IAErE;AAAA,oBAAAD,MAAC,YAAO,WAAU,uEAChB,0BAAAC,MAAC,SAAI,WAAW,gCAAgC,MAAM,IACtD;AAAA,sBAAAD,MAAC,QAAG,WAAU,yDAAyD,iBAAM;AAAA,MAC5E,kBACC,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,IAAI;AAAA,UACJ,WAAU;AAAA,UAEV;AAAA,4BAAAD,MAAC,UAAK,eAAW,MAAC,WAAU,wBAAuB,eAAC;AAAA,YAAO;AAAA;AAAA;AAAA,MAE7D;AAAA,OAEF,GACF;AAAA,IAEA,gBAAAC,MAAC,SAAI,KAAK,WAAW,WAAU,kCAC5B;AAAA,wBACC,gBAAAA,MAAC,SAAI,WAAU,gDACb;AAAA,wBAAAA,MAAC,SAAI,WAAW,2EAA2E,MAAM,IAC/F;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,cAAc,EAAE,OAAO,KAAK;AAAA,cAC7C,aAAY;AAAA,cACZ,cAAW;AAAA,cACX,WAAU;AAAA;AAAA,UACZ;AAAA,UACA,gBAAAC;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAoB;AAAA,cAC3D,cAAW;AAAA,cACX,WAAU;AAAA,cAEV;AAAA,gCAAAD,MAAC,YAAO,OAAM,UAAS,oBAAM;AAAA,gBAC7B,gBAAAA,MAAC,YAAO,OAAM,UAAS,oBAAM;AAAA;AAAA;AAAA,UAC/B;AAAA,WACF;AAAA,QACC,gBACC,gBAAAC,MAAC,SAAI,WAAW,wDAAwD,MAAM,IAC5E;AAAA,0BAAAA,MAAC,SAAI,WAAU,qCACb;AAAA,4BAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM,eAAe,IAAI,IAAI,QAAQ,MAAM,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;AAAA,gBAC3E,UAAU,sBAAsB,QAAQ,MAAM,WAAW;AAAA,gBACzD,WAAU;AAAA,gBACX;AAAA;AAAA,YAED;AAAA,YACA,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM,eAAe,oBAAI,IAAI,CAAC;AAAA,gBACvC,UAAU,kBAAkB;AAAA,gBAC5B,WAAU;AAAA,gBACX;AAAA;AAAA,YAED;AAAA,YACA,gBAAAC,MAAC,UAAK,WAAU,iCAAgC,aAAU,UACvD;AAAA;AAAA,cAAc;AAAA,eACjB;AAAA,YACC,gBAAgB,KACf,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM,eAAe,EAAE,MAAM,YAAY,KAAK,CAAC,GAAG,WAAW,EAAE,CAAC;AAAA,gBACzE,WAAU;AAAA,gBAET;AAAA;AAAA,kBAAY;AAAA;AAAA;AAAA,YACf;AAAA,aAEJ;AAAA,UACA,gBAAAA,MAAC,SAAI,WAAU,qCACb;AAAA,4BAAAD,MAAC,WAAM,SAAQ,yBAAwB,WAAU,iCAAgC,yBAEjF;AAAA,YACA,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,KAAK;AAAA,gBACL,KAAK;AAAA,gBACL,OAAO;AAAA,gBACP,UAAU,CAAC,UAAU,WAAW,MAAM,OAAO,KAAK;AAAA,gBAClD,gBAAc,QAAQ,SAAS,KAAK,CAAC;AAAA,gBACrC,WAAU;AAAA;AAAA,YACZ;AAAA,YACA,gBAAAA,MAAC,UAAK,WAAU,iCAAgC,kBAAI;AAAA,YACpD,gBAAAC;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM,eAAe,EAAE,MAAM,cAAc,MAAM,cAAc,CAAC;AAAA,gBACzE,UAAU,CAAC;AAAA,gBACX,WAAU;AAAA,gBAET;AAAA;AAAA,kBAAY;AAAA;AAAA;AAAA,YACf;AAAA,YACA,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM,eAAe,EAAE,MAAM,cAAc,MAAM,cAAc,CAAC;AAAA,gBACzE,UAAU,CAAC;AAAA,gBACX,WAAU;AAAA,gBAET;AAAA;AAAA,kBAAY;AAAA;AAAA;AAAA,YACf;AAAA,aACF;AAAA,WACF;AAAA,SAEJ;AAAA,MAGF,gBAAAD,MAAC,SAAI,WAAW,0BAA0B,MAAM,IAC7C,WAAC,iBACA,gBAAAC,MAAC,SAAI,WAAU,4EACb;AAAA,wBAAAD,MAAC,OAAE,WAAU,uCAAuC,sBAAW;AAAA,QAC/D,gBAAAA,MAAC,OAAE,WAAU,0CAA0C,4BAAiB;AAAA,SAC1E,IACE,QAAQ,iBACV,gBAAAA,MAAC,gBAAa,IACZ,QAAQ,MAAM,WAAW,IAC3B,QAAQ,UACN,gBAAAA,MAAC,cAAW,SAAS,QAAQ,OAAO,SAAQ,qCAA+B,IACzE,cACF,gBAAAC,MAAC,OAAE,WAAU,mDAAkD;AAAA;AAAA,QACzC;AAAA,QAAW;AAAA,SACjC,IAEA,gBAAAD,MAAC,OAAE,WAAU,mDAAkD,iCAAmB,IAGpF,gBAAAC,MAAC,SAAI,WAAU,yBACZ;AAAA,gBAAQ,MAAM,IAAI,CAAC,YAClB,gBAAAD;AAAA,UAAC;AAAA;AAAA,YAEC;AAAA,YACA,MAAM,eAAe,QAAQ,EAAE;AAAA,YAC/B;AAAA,YACA,YAAY,sBAAsB,IAAI,QAAQ,EAAE,KAAK;AAAA,YACrD;AAAA,YACA,WAAW,gBAAgB,QAAQ,SAAS;AAAA,YAC5C;AAAA,YACA;AAAA,YACA,YAAY,QAAQ,YAAY;AAAA,YAChC,UAAU,YAAY,IAAI,QAAQ,EAAE;AAAA,YACpC,kBAAkB,CAAC,aAAa;AAC9B,6BAAe,CAAC,YAAY;AAC1B,sBAAM,OAAO,IAAI,IAAI,OAAO;AAC5B,oBAAI,SAAU,MAAK,IAAI,QAAQ,EAAE;AAAA,oBAC5B,MAAK,OAAO,QAAQ,EAAE;AAC3B,uBAAO;AAAA,cACT,CAAC;AAAA,YACH;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA;AAAA,UArBK,QAAQ;AAAA,QAsBf,CACD;AAAA,QAEA,QAAQ,UACP,gBAAAA,MAAC,cAAW,SAAS,QAAQ,OAAO,SAAQ,qCAA+B,QAAM,MAAC,IAChF,QAAQ,UACV,gBAAAA,MAAC,SAAI,KAAK,aAAa,WAAU,yCAC9B,kBAAQ,iBACP,gBAAAA,MAAC,UAAK,MAAK,UAAS,aAAU,UAAS,aAAW,MAAM,WAAU,iCAAgC,2BAElG,GAEJ,IACE;AAAA,SACN,GAEJ;AAAA,OACF;AAAA,IACC,cACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,WAAW;AAAA,QAClB,SAAS,MAAM;AACb,cAAI,CAAC,UAAU;AACb,0BAAc,IAAI;AAClB,yBAAa,IAAI;AAAA,UACnB;AAAA,QACF;AAAA,QACA,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QACE,gBAAAC,MAAAF,WAAA,EACE;AAAA,0BAAAC;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM;AACb,8BAAc,IAAI;AAClB,6BAAa,IAAI;AAAA,cACnB;AAAA,cACA,UAAU;AAAA,cACV,SAAQ;AAAA,cACT;AAAA;AAAA,UAED;AAAA,UACA,gBAAAA,MAAC,gBAAa,SAAS,MAAM,KAAK,kBAAkB,GAAG,UAAU,UAAU,SAAQ,eAChF,qBAAW,kBAAa,aAC3B;AAAA,WACF;AAAA,QAGF,0BAAAA,MAAC,OAAE,WAAU,iCAAiC,qBAAW,MAAK;AAAA;AAAA,IAChE;AAAA,KAEJ;AAEJ;AAEA,SAAS,WAAW,EAAE,SAAS,SAAS,OAAO,GAA+D;AAC5G,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,WACE,SACI,8EACA;AAAA,MAGN;AAAA,wBAAAD,MAAC,UAAK,WAAU,iCAAiC,mBAAQ;AAAA,QACzD,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS;AAAA,YACT,WAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAeG;AACD,QAAM,CAAC,UAAU,WAAW,IAAIE,WAAS,KAAK;AAC9C,QAAM,UAAUK,OAAM;AACtB,QAAM,EAAE,cAAc,YAAY,UAAU,aAAa,IAAI,WAAW,UAAU,WAAW;AAC7F,QAAM,SAAS,eAAe,OAAO,KAAK,CAAC;AAC3C,QAAM,UAAU,QAAQ,QAAQ,KAAK,QAAQ,QAAQ,KAAK,OAAO,SAAS;AAG1E,QAAM,aAAa,QAAQ,QAAQ,MAAM,KAAK,CAAC;AAE/C,SACE,gBAAAN,MAAC,SAAI,WAAW,mGAAmG,WAAW,kBAAkB,EAAE,IAC/I;AAAA,kBACC,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,UAAU,CAAC,UAAU,iBAAiB,MAAM,OAAO,OAAO;AAAA,QAC1D,cAAY,UAAU,aAAa,SAAS,aAAa,CAAC;AAAA,QAC1D,WAAU;AAAA;AAAA,IACZ;AAAA,IAEF,gBAAAC,MAAC,QAAK,IAAI,MAAM,WAAU,0CACvB;AAAA,oBAAc,gBAAAD,MAAC,UAAK,WAAU,gDAA+C,eAAW,MAAC;AAAA,MAC1F,gBAAAA,MAAC,eAAY,WAAU,0CAAyC;AAAA,MAChE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,oBAAoB,aAAa,0BAA0B,iBAAiB,IAAI,aAAa,kBAAkB,EAAE;AAAA,UAC3H,GAAI,aAAa,EAAE,MAAM,UAAU,cAAc,mBAAmB,IAAI,CAAC;AAAA,UAEzE,uBAAa,SAAS,aAAa;AAAA;AAAA,MACtC;AAAA,OACF;AAAA,IACA,gBAAAA,MAAC,UAAK,WAAU,uDAAuD,qBAAU;AAAA,IAChF,WACC,gBAAAC,MAAC,SAAI,KAAK,cAAc,WAAU,qBAChC;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACJ,GAAG;AAAA,UACJ,cAAW;AAAA,UACX,iBAAe,WAAW,UAAU;AAAA,UACpC,SAAS,MAAM,YAAY,CAAC,SAAS,CAAC,IAAI;AAAA,UAI1C,WAAU;AAAA,UAEV,0BAAAA,MAAC,UAAK,eAAW,MAAC,WAAU,0BAAyB,oBAAC;AAAA;AAAA,MACxD;AAAA,MACA,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,MAAK;AAAA,UACL;AAAA,UACA;AAAA,UACA,WAAW,2EAA2E,cAAc;AAAA,UAEnG;AAAA,wBACC,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,SAAS,MAAM;AACb,8BAAY,KAAK;AACjB,2BAAS,OAAO;AAAA,gBAClB;AAAA,gBACA,WAAU;AAAA,gBAET;AAAA;AAAA,YACH;AAAA,YAED,OAAO,IAAI,CAAC,WACX,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBAEC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,SAAS,MAAM;AACb,8BAAY,KAAK;AACjB,yBAAO,SAAS;AAAA,gBAClB;AAAA,gBACA,WAAW,yDACT,OAAO,cACH,6CACA,iCACN;AAAA,gBAEC,iBAAO;AAAA;AAAA,cAbH,OAAO;AAAA,YAcd,CACD;AAAA,YACA,YACC,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,SAAS,MAAM;AACb,8BAAY,KAAK;AACjB,2BAAS,OAAO;AAAA,gBAClB;AAAA,gBACA,WAAU;AAAA,gBAET;AAAA;AAAA,YACH;AAAA;AAAA;AAAA,MAEJ;AAAA,OACF;AAAA,KAEJ;AAEJ;;;AC1lCA;AAAA,EACE,YAAAQ;AAAA,EACA;AAAA,EACA,eAAAC;AAAA,EACA,aAAAC;AAAA,EACA,SAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OAGK;;;ACdA,SAAS,aAAa,OAA+C;AAC1E,SAAO,EAAE,WAAW,MAAM,MAAM;AAClC;AAGO,SAAS,eAAe,OAAsC;AACnE,SAAO,EAAE,WAAW,OAAO,MAAM;AACnC;AA4JO,SAAS,2BACd,QACA,QACS;AACT,QAAM,aAAa,OAAO;AAC1B,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,OAAO,OAAO,WAAW,MAAM,KAAK;AAC1C,SAAO,oBAAoB,MAAM,WAAW,MAAM;AACpD;AAIO,SAAS,oBAAoB,GAAgC,GAAyC;AAC3G,SAAO,OAAO,GAAG,KAAK,MAAM,KAAK,IAAI;AACvC;AAIA,IAAM,UAAU;AAChB,IAAM,WAAW;AAQjB,SAAS,iBAAiB,KAAsE;AAC9F,QAAM,UAAU,IAAI,KAAK;AACzB,MAAI,YAAY,GAAI,QAAO,EAAE,OAAO,KAAK;AACzC,QAAM,gBAAgB,WAAW,KAAK,OAAO;AAC7C,QAAM,QAAQ,gBAAgB,QAAQ,MAAM,GAAG,EAAE,EAAE,KAAK,IAAI,SACzD,QAAQ,UAAU,EAAE,EACpB,QAAQ,mBAAmB,IAAI;AAClC,MAAI,CAAC,QAAQ,KAAK,IAAI,EAAG,QAAO,EAAE,SAAS,KAAK;AAChD,QAAM,SAAS,OAAO,IAAI;AAC1B,MAAI,CAAC,OAAO,SAAS,MAAM,EAAG,QAAO,EAAE,SAAS,KAAK;AACrD,SAAO,EAAE,OAAO,gBAAgB,CAAC,SAAS,OAAO;AACnD;AAGA,SAAS,eAAe,MAAuB;AAC7C,MAAI,CAAC,SAAS,KAAK,IAAI,EAAG,QAAO;AACjC,QAAM,CAAC,MAAM,OAAO,GAAG,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI,CAAC,SAAS,OAAO,IAAI,CAAC;AACrE,MAAI,UAAU,UAAa,QAAQ,UAAa,SAAS,OAAW,QAAO;AAC3E,MAAI,QAAQ,KAAK,QAAQ,MAAM,MAAM,EAAG,QAAO;AAC/C,QAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ,GAAG,GAAG;AAC3C,QAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,SAAO,KAAK,eAAe,MAAM,QAAQ,KAAK,YAAY,MAAM,QAAQ,KAAK,KAAK,WAAW,MAAM;AACrG;AAMO,SAAS,qBAAqB,QAA0B,KAAoC;AACjG,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK,QAAQ;AACX,YAAM,UAAU,IAAI,KAAK;AACzB,aAAO,aAAa,YAAY,KAAK,OAAO,OAAO;AAAA,IACrD;AAAA,IACA,KAAK,UAAU;AACb,YAAM,UAAU,IAAI,KAAK;AACzB,aAAO,aAAa,YAAY,KAAK,OAAO,OAAO;AAAA,IACrD;AAAA,IACA,KAAK,WAAW;AACd,YAAM,UAAU,IAAI,KAAK,EAAE,YAAY;AACvC,UAAI,YAAY,GAAI,QAAO,aAAa,IAAI;AAC5C,UAAI,YAAY,OAAQ,QAAO,aAAa,IAAI;AAChD,UAAI,YAAY,QAAS,QAAO,aAAa,KAAK;AAClD,aAAO,eAAe,GAAG,OAAO,MAAM,2CAAiC,GAAG,SAAI;AAAA,IAChF;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,UAAU,IAAI,KAAK;AACzB,UAAI,YAAY,GAAI,QAAO,aAAa,IAAI;AAC5C,UAAI,CAAC,eAAe,OAAO,GAAG;AAC5B,eAAO,eAAe,GAAG,OAAO,MAAM,uDAA6C,GAAG,SAAI;AAAA,MAC5F;AACA,aAAO,aAAa,OAAO;AAAA,IAC7B;AAAA,IACA,KAAK;AAAA,IACL,KAAK,YAAY;AACf,YAAM,SAAS,iBAAiB,GAAG;AACnC,UAAI,WAAW,OAAQ,QAAO,aAAa,IAAI;AAC/C,UAAI,aAAa,OAAQ,QAAO,eAAe,GAAG,OAAO,MAAM,sCAA4B,GAAG,SAAI;AAClG,aAAO,aAAa,OAAO,KAAK;AAAA,IAClC;AAAA,EACF;AACF;AAIA,SAAS,gBAAgB,QAAwC;AAC/D,SAAO,OAAO,QAAQ,IAAI,CAAC,WAAW,OAAO,KAAK,EAAE,KAAK,IAAI;AAC/D;AAOO,SAAS,uBAAuB,QAA0B,OAA+C;AAC9G,QAAM,aAAa,UAAU,KAAK,OAAO;AACzC,MAAI,eAAe,MAAM;AACvB,QAAI,OAAO,SAAU,QAAO,eAAe,GAAG,OAAO,MAAM,eAAe;AAC1E,UAAMC,UAAS,OAAO,WAAW,IAAI;AACrC,WAAOA,YAAW,UAAaA,YAAW,OAAO,aAAa,IAAI,IAAI,eAAeA,OAAM;AAAA,EAC7F;AAEA,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK,QAAQ;AACX,UAAI,OAAO,eAAe,SAAU,QAAO,eAAe,GAAG,OAAO,MAAM,gBAAgB;AAC1F,UAAI,OAAO,cAAc,UAAa,WAAW,SAAS,OAAO,WAAW;AAC1E,eAAO,eAAe,GAAG,OAAO,MAAM,qBAAqB,OAAO,SAAS,0BAAqB,WAAW,MAAM,GAAG;AAAA,MACtH;AACA,UAAI,OAAO,cAAc,UAAa,WAAW,SAAS,OAAO,WAAW;AAC1E,eAAO,eAAe,GAAG,OAAO,MAAM,oBAAoB,OAAO,SAAS,0BAAqB,WAAW,MAAM,GAAG;AAAA,MACrH;AACA,UAAI,OAAO,WAAW,CAAC,OAAO,QAAQ,KAAK,UAAU,GAAG;AACtD,eAAO,eAAe,OAAO,kBAAkB,GAAG,OAAO,MAAM,mBAAmB,OAAO,QAAQ,MAAM,GAAG;AAAA,MAC5G;AACA;AAAA,IACF;AAAA,IACA,KAAK;AAAA,IACL,KAAK,YAAY;AACf,UAAI,OAAO,eAAe,YAAY,CAAC,OAAO,SAAS,UAAU,GAAG;AAClE,eAAO,eAAe,GAAG,OAAO,MAAM,oBAAoB;AAAA,MAC5D;AACA,UAAI,OAAO,SAAS,YAAY,OAAO,YAAY,QAAQ,CAAC,OAAO,UAAU,UAAU,GAAG;AACxF,eAAO,eAAe,GAAG,OAAO,MAAM,sCAAiC,UAAU,GAAG;AAAA,MACtF;AACA,UAAI,OAAO,QAAQ,UAAa,aAAa,OAAO,KAAK;AACvD,eAAO,eAAe,GAAG,OAAO,MAAM,qBAAqB,OAAO,GAAG,eAAU,UAAU,GAAG;AAAA,MAC9F;AACA,UAAI,OAAO,QAAQ,UAAa,aAAa,OAAO,KAAK;AACvD,eAAO,eAAe,GAAG,OAAO,MAAM,oBAAoB,OAAO,GAAG,eAAU,UAAU,GAAG;AAAA,MAC7F;AACA;AAAA,IACF;AAAA,IACA,KAAK,QAAQ;AACX,UAAI,OAAO,eAAe,YAAY,CAAC,eAAe,UAAU,GAAG;AACjE,eAAO,eAAe,GAAG,OAAO,MAAM,qCAAqC;AAAA,MAC7E;AACA,UAAI,OAAO,QAAQ,UAAa,aAAa,OAAO,KAAK;AACvD,eAAO,eAAe,GAAG,OAAO,MAAM,wBAAwB,OAAO,GAAG,eAAU,UAAU,GAAG;AAAA,MACjG;AACA,UAAI,OAAO,QAAQ,UAAa,aAAa,OAAO,KAAK;AACvD,eAAO,eAAe,GAAG,OAAO,MAAM,yBAAyB,OAAO,GAAG,eAAU,UAAU,GAAG;AAAA,MAClG;AACA;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,UAAI,OAAO,eAAe,SAAU,QAAO,eAAe,GAAG,OAAO,MAAM,oBAAoB,gBAAgB,MAAM,CAAC,GAAG;AACxH,UAAI,CAAC,OAAO,QAAQ,KAAK,CAAC,WAAW,OAAO,UAAU,UAAU,GAAG;AACjE,eAAO,eAAe,GAAG,OAAO,MAAM,oBAAoB,gBAAgB,MAAM,CAAC,qBAAW,UAAU,SAAI;AAAA,MAC5G;AACA;AAAA,IACF;AAAA,IACA,KAAK,WAAW;AACd,UAAI,OAAO,eAAe,UAAW,QAAO,eAAe,GAAG,OAAO,MAAM,yBAAyB;AACpG;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,OAAO,WAAW,UAAU;AAC3C,MAAI,WAAW,UAAa,WAAW,KAAM,QAAO,eAAe,MAAM;AACzE,SAAO,aAAa,UAAU;AAChC;AAIO,SAAS,mBAAmB,QAA0B,KAAoC;AAC/F,QAAM,SAAS,qBAAqB,QAAQ,GAAG;AAC/C,MAAI,CAAC,OAAO,UAAW,QAAO;AAC9B,SAAO,uBAAuB,QAAQ,OAAO,KAAK;AACpD;AAOO,SAAS,sBACd,SACA,QACsB;AACtB,QAAM,WAA4C,CAAC;AACnD,QAAM,aAAqC,CAAC;AAC5C,MAAI,aAA4B;AAEhC,aAAW,UAAU,SAAS;AAC5B,QAAI,CAAC,2BAA2B,QAAQ,MAAM,GAAG;AAC/C,eAAS,OAAO,EAAE,IAAI;AACtB;AAAA,IACF;AACA,UAAM,UAAU,uBAAuB,QAAQ,OAAO,OAAO,EAAE,KAAK,IAAI;AACxE,QAAI,QAAQ,WAAW;AACrB,eAAS,OAAO,EAAE,IAAI,QAAQ;AAC9B;AAAA,IACF;AACA,eAAW,OAAO,EAAE,IAAI,QAAQ;AAChC,QAAI,eAAe,KAAM,cAAa,QAAQ;AAAA,EAChD;AAEA,MAAI,eAAe,MAAM;AACvB,UAAM,QAAQ,OAAO,KAAK,UAAU,EAAE;AACtC,UAAM,QAAQ,UAAU,IAAI,aAAa,GAAG,KAAK,2BAA2B,UAAU;AACtF,WAAO,EAAE,WAAW,OAAO,OAAO,WAAW;AAAA,EAC/C;AACA,SAAO,EAAE,WAAW,MAAM,OAAO,SAAS;AAC5C;AAMO,SAAS,sBACd,QACA,OACA,QACQ;AACR,MAAI,UAAU,QAAQ,UAAU,GAAI,QAAO;AAC3C,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK,YAAY;AACf,UAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK;AAClD,aAAO,IAAI,KAAK,aAAa,QAAQ;AAAA,QACnC,OAAO;AAAA,QACP,UAAU,OAAO;AAAA,QACjB,GAAI,OAAO,mBAAmB,SAC1B,CAAC,IACD,EAAE,uBAAuB,OAAO,gBAAgB,uBAAuB,OAAO,eAAe;AAAA,MACnG,CAAC,EAAE,OAAO,KAAK;AAAA,IACjB;AAAA,IACA,KAAK,UAAU;AACb,UAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK;AAClD,aAAO,IAAI,KAAK,aAAa,MAAM,EAAE,OAAO,KAAK;AAAA,IACnD;AAAA,IACA,KAAK,QAAQ;AACX,UAAI,OAAO,UAAU,YAAY,CAAC,eAAe,KAAK,EAAG,QAAO,OAAO,KAAK;AAC5E,aAAO,IAAI,KAAK,eAAe,QAAQ,EAAE,WAAW,UAAU,UAAU,MAAM,CAAC,EAAE;AAAA,QAC/E,oBAAI,KAAK,GAAG,KAAK,YAAY;AAAA,MAC/B;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,YAAM,SAAS,OAAO,QAAQ,KAAK,CAAC,cAAc,UAAU,UAAU,KAAK;AAC3E,aAAO,SAAS,OAAO,QAAQ,OAAO,KAAK;AAAA,IAC7C;AAAA,IACA,KAAK,WAAW;AACd,UAAI,OAAO,UAAU,UAAW,QAAO,OAAO,KAAK;AACnD,aAAO,QAAS,OAAO,aAAa,QAAU,OAAO,cAAc;AAAA,IACrE;AAAA,IACA,KAAK;AACH,aAAO,OAAO,KAAK;AAAA,EACvB;AACF;AAIO,SAAS,qBAAqB,QAA0B,OAAgC;AAC7F,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,OAAO,SAAS,UAAW,QAAO,UAAU,OAAO,SAAS;AAChE,SAAO,OAAO,KAAK;AACrB;AAGO,SAAS,mBAAmB,SAAsC,KAA4B;AACnG,MAAI,IAAI,UAAU,UAAa,IAAI,UAAU,GAAI,QAAO,IAAI;AAC5D,aAAW,UAAU,SAAS;AAC5B,QAAI,OAAO,SAAS,UAAU,OAAO,SAAS,SAAU;AACxD,UAAM,QAAQ,IAAI,OAAO,OAAO,EAAE;AAClC,QAAI,OAAO,UAAU,YAAY,UAAU,GAAI,QAAO,sBAAsB,QAAQ,KAAK;AAAA,EAC3F;AACA,SAAO,IAAI;AACb;AAKO,SAAS,oBAAoB,MAAgC,UAA0B;AAC5F,MAAI,QAAQ;AACZ,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,IAAI,OAAO,QAAQ;AACjC,QAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,UAAS;AAAA,EACpE;AACA,SAAO;AACT;AAmBO,IAAM,4BAA+C,EAAE,SAAS,CAAC,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,EAAE;AAI7F,SAAS,sBACd,MACA,SACiB;AACjB,QAAM,UAAU,IAAI,IAAI,QAAQ,OAAO;AACvC,QAAM,YAA6B,CAAC;AACpC,aAAW,OAAO,MAAM;AACtB,QAAI,QAAQ,IAAI,IAAI,EAAE,EAAG;AACzB,UAAM,QAAQ,QAAQ,QAAQ,IAAI,EAAE;AACpC,cAAU,KAAK,UAAU,SAAY,MAAM,EAAE,GAAG,KAAK,QAAQ,EAAE,GAAG,IAAI,QAAQ,GAAG,MAAM,EAAE,CAAC;AAAA,EAC5F;AACA,aAAW,OAAO,QAAQ,SAAS;AACjC,QAAI,QAAQ,IAAI,IAAI,EAAE,EAAG;AAIzB,UAAM,QAAQ,QAAQ,QAAQ,IAAI,EAAE;AACpC,cAAU,KAAK,UAAU,SAAY,MAAM,EAAE,GAAG,KAAK,QAAQ,EAAE,GAAG,IAAI,QAAQ,GAAG,MAAM,EAAE,CAAC;AAAA,EAC5F;AACA,SAAO;AACT;AAGO,SAAS,qBACd,SACA,OACA,UACA,OACmB;AACnB,QAAM,WAAW,EAAE,GAAI,QAAQ,QAAQ,KAAK,KAAK,CAAC,GAAI,CAAC,QAAQ,GAAG,MAAM;AACxE,SAAO,EAAE,GAAG,SAAS,SAAS,EAAE,GAAG,QAAQ,SAAS,CAAC,KAAK,GAAG,SAAS,EAAE;AAC1E;AAGO,SAAS,wBACd,SACA,OACA,UACmB;AACnB,QAAM,WAAW,QAAQ,QAAQ,KAAK;AACtC,MAAI,aAAa,UAAa,EAAE,YAAY,UAAW,QAAO;AAC9D,QAAM,YAA6C,CAAC;AACpD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACnD,QAAI,QAAQ,SAAU,WAAU,GAAG,IAAI;AAAA,EACzC;AACA,QAAM,UAAqE,EAAE,GAAG,QAAQ,QAAQ;AAChG,MAAI,OAAO,KAAK,SAAS,EAAE,WAAW,EAAG,QAAO,QAAQ,KAAK;AAAA,MACxD,SAAQ,KAAK,IAAI;AACtB,SAAO,EAAE,GAAG,SAAS,QAAQ;AAC/B;AAOO,SAAS,wBACd,SACA,SACA,KACmB;AACnB,QAAM,eAAe,QAAQ,QAAQ,UAAU,CAAC,cAAc,UAAU,OAAO,OAAO;AACtF,MAAI,gBAAgB,GAAG;AACrB,UAAM,UAAU,CAAC,GAAG,QAAQ,OAAO;AACnC,YAAQ,YAAY,IAAI;AACxB,WAAO,EAAE,GAAG,SAAS,SAAS,SAAS,kBAAkB,QAAQ,SAAS,SAAS,IAAI,EAAE,EAAE;AAAA,EAC7F;AACA,SAAO,EAAE,GAAG,SAAS,SAAS,EAAE,GAAG,QAAQ,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,OAAO,EAAE,EAAE;AACpF;AAGA,SAAS,kBACP,YACG,QAC2B;AAC9B,QAAM,OAAO,IAAI,IAAI,MAAM;AAC3B,QAAM,OAAkE,CAAC;AACzE,MAAI,UAAU;AACd,aAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AACpD,QAAI,KAAK,IAAI,KAAK,EAAG,WAAU;AAAA,QAC1B,MAAK,KAAK,IAAI;AAAA,EACrB;AACA,SAAO,UAAU,OAAO;AAC1B;AAGO,SAAS,sBAAsB,SAA4B,KAAuC;AACvG,SAAO,EAAE,GAAG,SAAS,SAAS,CAAC,GAAG,QAAQ,SAAS,GAAG,EAAE;AAC1D;AAIO,SAAS,yBAAyB,SAA4B,OAAkC;AACrG,QAAM,UAAU,QAAQ,QAAQ,OAAO,CAAC,QAAQ,IAAI,OAAO,KAAK;AAChE,MAAI,QAAQ,WAAW,QAAQ,QAAQ,OAAQ,QAAO;AACtD,SAAO,EAAE,GAAG,SAAS,SAAS,SAAS,kBAAkB,QAAQ,SAAS,KAAK,EAAE;AACnF;AAGO,SAAS,sBAAsB,SAA4B,OAAkC;AAClG,MAAI,QAAQ,QAAQ,SAAS,KAAK,EAAG,QAAO;AAC5C,SAAO,EAAE,GAAG,SAAS,SAAS,CAAC,GAAG,QAAQ,SAAS,KAAK,EAAE;AAC5D;AAGO,SAAS,yBAAyB,SAA4B,OAAkC;AACrG,MAAI,CAAC,QAAQ,QAAQ,SAAS,KAAK,EAAG,QAAO;AAC7C,SAAO,EAAE,GAAG,SAAS,SAAS,QAAQ,QAAQ,OAAO,CAAC,cAAc,cAAc,KAAK,EAAE;AAC3F;AAUO,SAAS,uBACd,MACA,SACmB;AACnB,QAAM,OAAO,IAAI,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;AACrD,QAAM,aAAa,IAAI,IAAI,QAAQ,QAAQ,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;AAC/D,MAAI,UAAU;AAEd,QAAM,UAAqE,CAAC;AAC5E,aAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC5D,UAAM,MAAM,KAAK,IAAI,KAAK;AAC1B,QAAI,QAAQ,QAAW;AAIrB,UAAI,WAAW,IAAI,KAAK,GAAG;AACzB,gBAAQ,KAAK,IAAI;AACjB;AAAA,MACF;AACA,gBAAU;AACV;AAAA,IACF;AACA,UAAM,OAAwC,CAAC;AAC/C,eAAW,CAAC,UAAU,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AACrD,UAAI,oBAAoB,IAAI,OAAO,QAAQ,GAAG,KAAK,EAAG,WAAU;AAAA,UAC3D,MAAK,QAAQ,IAAI;AAAA,IACxB;AACA,QAAI,OAAO,KAAK,IAAI,EAAE,SAAS,EAAG,SAAQ,KAAK,IAAI;AAAA,EACrD;AAEA,QAAM,UAAU,QAAQ,QAAQ,OAAO,CAAC,QAAQ;AAC9C,UAAM,UAAU,KAAK,IAAI,IAAI,EAAE;AAC/B,QAAI,QAAS,WAAU;AACvB,WAAO,CAAC;AAAA,EACV,CAAC;AAED,QAAM,UAAU,QAAQ,QAAQ,OAAO,CAAC,UAAU;AAChD,UAAM,UAAU,CAAC,KAAK,IAAI,KAAK;AAC/B,QAAI,QAAS,WAAU;AACvB,WAAO,CAAC;AAAA,EACV,CAAC;AAED,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,EAAE,SAAS,SAAS,QAAQ;AACrC;;;AD5JU,SAEE,OAAAC,OAFF,QAAAC,cAAA;AAlXV,IAAM,yBAAmD,CAAC;AAI1D,IAAM,qBAAqB;AAE3B,SAAS,QAAQ,OAAe,UAA0B;AACxD,SAAO,GAAG,KAAK,GAAG,kBAAkB,GAAG,QAAQ;AACjD;AAEA,IAAM,kBAAkB,oBAAI,IAAI,CAAC,WAAW,aAAa,aAAa,cAAc,QAAQ,KAAK,CAAC;AAElG,SAAS,MAAM,OAAe,KAAqB;AACjD,MAAI,QAAQ,EAAG,QAAO;AACtB,MAAI,QAAQ,IAAK,QAAO;AACxB,SAAO;AACT;AAEA,SAAS,eAAe,QAAkC;AACxD,QAAM,QAAQ,OAAO,UAAU,OAAO,SAAS,YAAY,OAAO,SAAS,aAAa,UAAU;AAClG,SAAO,UAAU,UAAU,eAAe;AAC5C;AAKA,SAAS,aACP,SAC8D;AAC9D,QAAM,SAAuE,CAAC;AAC9E,aAAW,UAAU,SAAS;AAC5B,UAAM,QAAQ,OAAO,SAAS;AAC9B,UAAM,WAAW,OAAO,KAAK,CAAC,UAAU,MAAM,UAAU,KAAK;AAC7D,QAAI,SAAU,UAAS,QAAQ,KAAK,MAAM;AAAA,QACrC,QAAO,KAAK,EAAE,OAAO,SAAS,CAAC,MAAM,EAAE,CAAC;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,IAAM,cACJ;AAEF,IAAMC,eAAqD;AAAA,EACzD,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU;AAAA,EACV,UAAU;AACZ;AAEA,IAAM,eAAsD;AAAA,EAC1D,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU;AAAA,EACV,UAAU;AACZ;AAOO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB;AACF,GAAoB;AAClB,QAAM,cAAcC,OAAM;AAC1B,QAAM,CAAC,SAAS,UAAU,IAAIC,WAA4B,yBAAyB;AACnF,QAAM,CAAC,SAAS,eAAe,IAAIA,WAAmE,IAAI;AAC1G,QAAM,CAAC,YAAY,aAAa,IAAIA,WAA2C,CAAC,CAAC;AACjF,QAAM,CAAC,WAAW,YAAY,IAAIA,WAA2C,CAAC,CAAC;AAC/E,QAAM,CAAC,aAAa,cAAc,IAAIA,WAAyC,CAAC,CAAC;AACjF,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAqD,IAAI;AACnF,QAAM,CAAC,YAAY,aAAa,IAAIA,WAAwB,IAAI;AAChE,QAAM,CAAC,eAAe,gBAAgB,IAAIA,WAAwB,IAAI;AACtE,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAAS,KAAK;AAC1C,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAA0C,EAAE,GAAI,kBAAkB,CAAC,EAAG,CAAC;AACjG,QAAM,CAAC,aAAa,cAAc,IAAIA,WAA2C,CAAC,CAAC;AACnF,QAAM,CAAC,YAAY,aAAa,IAAIA,WAAwB,IAAI;AAChE,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAS,KAAK;AAE9C,QAAM,WAAWC,QAAO,oBAAI,IAAgC,CAAC;AAC7D,QAAM,WAAWA,QAAO,KAAK;AAC7B,QAAM,eAAeA,QAAO,CAAC;AAG7B,QAAM,aAAaA,QAAiE,IAAI;AAExF,QAAM,aAAaC,aAAY,CAAC,SAAmE;AACjG,eAAW,UAAU;AACrB,oBAAgB,IAAI;AAAA,EACtB,GAAG,CAAC,CAAC;AAKL,QAAM,aAAa,MAAM,WAAW,WAAW,MAAM,WAAW,UAAU,MAAM,QAAQ;AAIxF,EAAAC,YAAU,MAAM;AACd,eAAW,CAAC,YAAY,uBAAuB,YAAY,OAAO,CAAC;AAAA,EACrE,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,cAAcC,SAAQ,MAAM,sBAAsB,YAAY,OAAO,GAAG,CAAC,YAAY,OAAO,CAAC;AAEnG,QAAM,cAAcA,SAAQ,MAAM;AAChC,QAAI,UAAU,KAAM,QAAO;AAC3B,QAAI,CAAC,YAAY,KAAK,CAAC,QAAQ,IAAI,OAAO,MAAM,KAAK,EAAG,QAAO;AAC/D,QAAI,CAAC,QAAQ,KAAK,CAAC,WAAW,OAAO,OAAO,MAAM,QAAQ,EAAG,QAAO;AACpE,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,OAAO,WAAW,CAAC;AAEhC,QAAM,eAAeF,aAAY,CAAC,KAAa,YAA2B;AACxE,kBAAc,CAAC,YAAY;AACzB,UAAI,YAAY,MAAM;AACpB,YAAI,EAAE,OAAO,SAAU,QAAO;AAC9B,cAAM,OAAO,EAAE,GAAG,QAAQ;AAC1B,eAAO,KAAK,GAAG;AACf,eAAO;AAAA,MACT;AACA,UAAI,QAAQ,GAAG,MAAM,QAAS,QAAO;AACrC,aAAO,EAAE,GAAG,SAAS,CAAC,GAAG,GAAG,QAAQ;AAAA,IACtC,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,cAAcA,aAAY,CAAC,OAAe,YAA2B;AACzE,iBAAa,CAAC,YAAY;AACxB,UAAI,YAAY,MAAM;AACpB,YAAI,EAAE,SAAS,SAAU,QAAO;AAChC,cAAM,OAAO,EAAE,GAAG,QAAQ;AAC1B,eAAO,KAAK,KAAK;AACjB,eAAO;AAAA,MACT;AACA,aAAO,EAAE,GAAG,SAAS,CAAC,KAAK,GAAG,QAAQ;AAAA,IACxC,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgBA,aAAY,CAAC,OAAe,YAAqB;AACrE,mBAAe,CAAC,YAAY;AAC1B,UAAI,QAAS,QAAO,SAAS,UAAU,UAAU,EAAE,GAAG,SAAS,CAAC,KAAK,GAAG,KAAK;AAC7E,UAAI,EAAE,SAAS,SAAU,QAAO;AAChC,YAAM,OAAO,EAAE,GAAG,QAAQ;AAC1B,aAAO,KAAK,KAAK;AACjB,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,YAAYA,aAAY,CAAC,OAAe,aAAqB;AACjE,aAAS,EAAE,OAAO,SAAS,CAAC;AAC5B,aAAS,QAAQ,IAAI,QAAQ,OAAO,QAAQ,CAAC,GAAG,MAAM;AAAA,EACxD,GAAG,CAAC,CAAC;AAEL,QAAM,YAAYA;AAAA,IAChB,CAAC,KAAoB,WAA6B;AAGhD,mBAAa,QAAQ,IAAI,IAAI,OAAO,EAAE,GAAG,IAAI;AAC7C,iBAAW;AAAA,QACT,OAAO,IAAI;AAAA,QACX,UAAU,OAAO;AAAA,QACjB,MAAM,qBAAqB,QAAQ,IAAI,OAAO,OAAO,EAAE,KAAK,IAAI;AAAA,MAClE,CAAC;AAAA,IACH;AAAA,IACA,CAAC,cAAc,UAAU;AAAA,EAC3B;AAIA,QAAM,iBAAiBA;AAAA,IACrB,OAAO,KAAoB,QAA0B,UAA2B;AAC9E,UAAI,CAAC,SAAU;AACf,YAAM,SAAS,EAAE,GAAG,IAAI,QAAQ,CAAC,OAAO,EAAE,GAAG,MAAM;AACnD,iBAAW,CAAC,YAAY,qBAAqB,SAAS,IAAI,IAAI,OAAO,IAAI,KAAK,CAAC;AAC/E,kBAAY,IAAI,IAAI,IAAI;AACxB,oBAAc,IAAI,IAAI,IAAI;AAE1B,UAAI;AACJ,UAAI;AACF,kBAAU,MAAM,SAAS,EAAE,KAAK,UAAU,OAAO,IAAI,OAAO,OAAO,CAAC;AAAA,MACtE,SAAS,OAAO;AACd,kBAAU,EAAE,WAAW,OAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE;AAAA,MAC9F;AAEA,oBAAc,IAAI,IAAI,KAAK;AAC3B,UAAI,QAAQ,WAAW;AACrB,cAAM,YAAY,QAAQ;AAC1B,YAAI,UAAW,YAAW,CAAC,YAAY,wBAAwB,SAAS,IAAI,IAAI,SAAS,CAAC;AAC1F;AAAA,MACF;AACA,iBAAW,CAAC,YAAY,wBAAwB,SAAS,IAAI,IAAI,OAAO,EAAE,CAAC;AAC3E,YAAM,WAAW,sBAAsB,QAAQ,OAAO,MAAM;AAC5D;AAAA,QACE,IAAI;AAAA,QACJ,aAAa,KACT,kBAAkB,OAAO,MAAM,KAAK,QAAQ,KAAK,KACjD,kBAAkB,OAAO,MAAM,OAAO,QAAQ,KAAK,QAAQ,KAAK;AAAA,MACtE;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,UAAU,aAAa,aAAa;AAAA,EAC/C;AAEA,QAAM,aAAaA;AAAA,IACjB,OAAO,KAAoB,QAA0B,SAAiB;AACpE,YAAM,OAAO,WAAW;AACxB,UAAI,SAAS,QAAQ,KAAK,UAAU,IAAI,MAAM,KAAK,aAAa,OAAO,GAAI;AAC3E,UAAI,SAAS,QAAS;AACtB,eAAS,UAAU;AACnB,UAAI;AACF,cAAM,MAAM,QAAQ,IAAI,IAAI,OAAO,EAAE;AACrC,cAAM,SAAS,mBAAmB,QAAQ,IAAI;AAC9C,YAAI,CAAC,OAAO,WAAW;AAGrB,uBAAa,KAAK,OAAO,KAAK;AAC9B,qBAAW,EAAE,OAAO,IAAI,IAAI,UAAU,OAAO,IAAI,KAAK,CAAC;AACvD;AAAA,QACF;AACA,qBAAa,KAAK,IAAI;AACtB,mBAAW,IAAI;AACf,YAAI,oBAAoB,IAAI,OAAO,OAAO,EAAE,GAAG,OAAO,KAAK,EAAG;AAC9D,cAAM,eAAe,KAAK,QAAQ,OAAO,KAAK;AAAA,MAChD,UAAE;AACA,iBAAS,UAAU;AAAA,MACrB;AAAA,IACF;AAAA,IACA,CAAC,gBAAgB,cAAc,UAAU;AAAA,EAC3C;AAEA,QAAM,aAAaA;AAAA,IACjB,CAAC,KAAoB,WAA6B;AAChD,mBAAa,QAAQ,IAAI,IAAI,OAAO,EAAE,GAAG,IAAI;AAC7C,iBAAW,IAAI;AACf,gBAAU,IAAI,IAAI,OAAO,EAAE;AAAA,IAC7B;AAAA,IACA,CAAC,WAAW,cAAc,UAAU;AAAA,EACtC;AAEA,QAAM,gBAAgBA;AAAA,IACpB,OAAO,QAAuB;AAC5B,UAAI,CAAC,SAAU;AACf,uBAAiB,IAAI;AACrB,kBAAY,IAAI,IAAI,IAAI;AACxB,iBAAW,CAAC,YAAY,sBAAsB,SAAS,IAAI,EAAE,CAAC;AAE9D,UAAI;AACJ,UAAI;AACF,kBAAU,MAAM,SAAS,GAAG;AAAA,MAC9B,SAAS,OAAO;AACd,kBAAU,EAAE,WAAW,OAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE;AAAA,MAC9F;AACA,UAAI,QAAQ,UAAW;AACvB,iBAAW,CAAC,YAAY,yBAAyB,SAAS,IAAI,EAAE,CAAC;AACjE,kBAAY,IAAI,IAAI,oBAAoB,mBAAmB,SAAS,GAAG,CAAC,KAAK,QAAQ,KAAK,EAAE;AAAA,IAC9F;AAAA,IACA,CAAC,SAAS,UAAU,WAAW;AAAA,EACjC;AAEA,QAAM,aAAaA,aAAY,MAAM;AACnC,aAAS,EAAE,GAAI,kBAAkB,CAAC,EAAG,CAAC;AACtC,mBAAe,CAAC,CAAC;AACjB,kBAAc,IAAI;AAAA,EACpB,GAAG,CAAC,cAAc,CAAC;AAEnB,QAAM,UAAUA,aAAY,MAAM;AAChC,eAAW;AACX,cAAU,IAAI;AAAA,EAChB,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,cAAcA,aAAY,YAAY;AAC1C,QAAI,CAAC,SAAU;AACf,UAAM,YAAY,sBAAsB,SAAS,KAAK;AACtD,QAAI,CAAC,UAAU,WAAW;AACxB,qBAAe,UAAU,UAAU;AACnC,oBAAc,UAAU,KAAK;AAC7B;AAAA,IACF;AACA,mBAAe,CAAC,CAAC;AACjB,kBAAc,IAAI;AAElB,iBAAa,WAAW;AACxB,UAAM,UAAU,GAAG,WAAW,UAAU,aAAa,OAAO;AAC5D,eAAW,CAAC,YAAY,sBAAsB,SAAS,EAAE,IAAI,SAAS,QAAQ,UAAU,MAAM,CAAC,CAAC;AAChG,gBAAY,IAAI;AAEhB,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,SAAS,UAAU,KAAK;AAAA,IAC1C,SAAS,OAAO;AACd,gBAAU,EAAE,WAAW,OAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE;AAAA,IAC9F;AAEA,gBAAY,KAAK;AACjB,QAAI,QAAQ,WAAW;AACrB,iBAAW,CAAC,YAAY,wBAAwB,SAAS,SAAS,QAAQ,KAAK,CAAC;AAChF,gBAAU,KAAK;AACf,iBAAW;AACX;AAAA,IACF;AAGA,eAAW,CAAC,YAAY,yBAAyB,SAAS,OAAO,CAAC;AAClE,kBAAc,QAAQ,KAAK;AAAA,EAC7B,GAAG,CAAC,SAAS,OAAO,aAAa,UAAU,UAAU,CAAC;AAEtD,QAAM,oBAAoBA;AAAA,IACxB,CAAC,UAA2C;AAC1C,UAAI,YAAY,KAAM;AACtB,YAAM,SAAS,MAAM;AACrB,YAAM,QAAQ,OAAO,SAAS;AAC9B,YAAM,WAAW,OAAO,SAAS;AACjC,UAAI,UAAU,UAAa,aAAa,OAAW;AACnD,YAAM,WAAW,YAAY,UAAU,CAAC,QAAQ,IAAI,OAAO,KAAK;AAChE,YAAM,cAAc,QAAQ,UAAU,CAAC,WAAW,OAAO,OAAO,QAAQ;AACxE,UAAI,WAAW,KAAK,cAAc,EAAG;AAErC,UAAI,MAAM,QAAQ,SAAS;AACzB,cAAM,MAAM,YAAY,QAAQ;AAChC,cAAM,SAAS,QAAQ,WAAW;AAClC,YAAI,CAAC,OAAO,CAAC,OAAQ;AACrB,YAAI,CAAC,YAAY,OAAO,aAAa,SAAS,IAAI,aAAa,KAAM;AACrE,YAAI,OAAO,SAAS,UAAW;AAC/B,YAAI,CAAC,2BAA2B,QAAQ,IAAI,MAAM,EAAG;AACrD,cAAM,eAAe;AACrB,kBAAU,KAAK,MAAM;AACrB;AAAA,MACF;AACA,UAAI,CAAC,gBAAgB,IAAI,MAAM,GAAG,EAAG;AACrC,YAAM,eAAe;AAErB,UAAI,UAAU;AACd,UAAI,aAAa;AACjB,UAAI,MAAM,QAAQ,UAAW,WAAU,MAAM,WAAW,GAAG,YAAY,SAAS,CAAC;AACjF,UAAI,MAAM,QAAQ,YAAa,WAAU,MAAM,WAAW,GAAG,YAAY,SAAS,CAAC;AACnF,UAAI,MAAM,QAAQ,YAAa,cAAa,MAAM,cAAc,GAAG,QAAQ,SAAS,CAAC;AACrF,UAAI,MAAM,QAAQ,aAAc,cAAa,MAAM,cAAc,GAAG,QAAQ,SAAS,CAAC;AACtF,UAAI,MAAM,QAAQ,OAAQ,cAAa;AACvC,UAAI,MAAM,QAAQ,MAAO,cAAa,QAAQ,SAAS;AAEvD,YAAM,iBAAiB,YAAY,OAAO;AAC1C,YAAM,oBAAoB,QAAQ,UAAU;AAC5C,UAAI,CAAC,kBAAkB,CAAC,kBAAmB;AAC3C,gBAAU,eAAe,IAAI,kBAAkB,EAAE;AAAA,IACnD;AAAA,IACA,CAAC,WAAW,SAAS,SAAS,WAAW,UAAU,WAAW;AAAA,EAChE;AAKA,MAAI,MAAM,WAAW,UAAU,MAAM,WAAW,WAAW;AACzD,WACE,gBAAAL,OAAC,SAAI,WAAW,aAAa,aAAa,EAAE,IACzC;AAAA;AAAA,MACD,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,aAAU;AAAA,UACV,aAAU;AAAA,UACV,WAAU;AAAA,UAEV;AAAA,4BAAAA,OAAC,UAAK,WAAU,WAAU;AAAA;AAAA,cAAS;AAAA,eAAQ;AAAA,YAC1C,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,eAAe,EAAE,GAAG,CAAC,GAAG,UACxD,gBAAAD,MAAC,SAAgB,WAAU,6CAA4C,eAAW,QAAxE,KAAyE,CACpF;AAAA;AAAA;AAAA,MACH;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,MAAM,WAAW,SAAS;AAC5B,WACE,gBAAAC,OAAC,SAAI,WAAW,aAAa,aAAa,EAAE,IACzC;AAAA;AAAA,MACD,gBAAAA,OAAC,SAAI,MAAK,SAAQ,WAAU,uEAC1B;AAAA,wBAAAD,MAAC,OAAE,WAAU,wCAAwC,gBAAM,SAAQ;AAAA,QACnE,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,MAAM;AAAA,YACf,WAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA,SACF;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,UACJ,UAAU,WACR,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,MAAM;AAAA,MACN,OAAO;AAAA,MACP;AAAA,MACA,UAAU,MAAM,KAAK,YAAY;AAAA,MACjC,UAAU,MAAM;AACd,kBAAU,KAAK;AACf,mBAAW;AAAA,MACb;AAAA;AAAA,EACF,IACE;AAEN,MAAI,YAAY,WAAW,GAAG;AAC5B,WACE,gBAAAC,OAAC,SAAI,WAAW,aAAa,aAAa,EAAE,IACzC;AAAA;AAAA,MACA,WACC,gBAAAA,OAAC,SAAI,WAAU,wEACb;AAAA,wBAAAD,MAAC,OAAE,WAAU,uCAAuC,gBAAM,OAAM;AAAA,QAC/D,MAAM,eACL,gBAAAA,MAAC,OAAE,WAAU,uDAAuD,gBAAM,aAAY;AAAA,QAExF,gBAAAC,OAAC,SAAI,WAAU,yDACZ;AAAA,gBAAM,WACJ,eAAe,MAAM,MAAM,IAC1B,MAAM,SAEN,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAU,MAAM,OAA4B;AAAA,cAC5C,WAAU;AAAA,cAER,gBAAM,OAA4B;AAAA;AAAA,UACtC;AAAA,UAEH,YACC,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,WAAU;AAAA,cAET;AAAA;AAAA,UACH;AAAA,WAEJ;AAAA,SACF;AAAA,OAEJ;AAAA,EAEJ;AAEA,QAAM,YAAY,QAAQ,KAAK,CAAC,WAAW,OAAO,gBAAgB,MAAS;AAC3E,QAAM,aAAa,QAAQ,UAAU,WAAW,IAAI;AAEpD,SACE,gBAAAC,OAAC,SAAI,WAAW,aAAa,aAAa,EAAE,IACzC;AAAA;AAAA,IACD,gBAAAD,MAAC,SAAI,WAAU,8DACb,0BAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,WAAU;AAAA,QACV,WAAW;AAAA,QAEX;AAAA,0BAAAD,MAAC,WACC,0BAAAC,OAAC,QAAG,MAAK,OAAM,WAAU,oFACtB;AAAA,oBAAQ,IAAI,CAAC,WACZ,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBAEC,MAAK;AAAA,gBACL,OAAM;AAAA,gBACN,WAAW,yBAAyB,eAAe,MAAM,CAAC;AAAA,gBAEzD,iBAAO;AAAA;AAAA,cALH,OAAO;AAAA,YAMd,CACD;AAAA,YACA,YACC,gBAAAA,MAAC,QAAG,MAAK,gBAAe,OAAM,OAAM,WAAU,8BAC5C,0BAAAA,MAAC,UAAK,WAAU,WAAU,yBAAW,GACvC;AAAA,aAEJ,GACF;AAAA,UACA,gBAAAA,MAAC,WACE,sBAAY,IAAI,CAAC,QAAQ;AACxB,kBAAM,WAAW,mBAAmB,SAAS,GAAG;AAChD,kBAAM,UAAU,IAAI,MAAM;AAC1B,kBAAM,WAAW,UAAU,IAAI,EAAE;AACjC,mBACE,gBAAAC,OAACQ,WAAA,EACC;AAAA,8BAAAR,OAAC,QAAG,MAAK,OAAM,aAAW,SAAS,WAAW,0BAA0B,UAAU,eAAe,EAAE,IAChG;AAAA,wBAAQ,IAAI,CAAC,WAAW;AACvB,wBAAM,MAAM,QAAQ,IAAI,IAAI,OAAO,EAAE;AACrC,wBAAM,aAAa,2BAA2B,QAAQ,IAAI,MAAM;AAChE,wBAAM,WACJ,aAAa,UAAa,OAAO,aAAa,SAAS,IAAI,aAAa,QAAQ;AAClF,wBAAM,QAAQ,IAAI,OAAO,OAAO,EAAE,KAAK;AACvC,wBAAM,YAAY,SAAS,UAAU,IAAI,MAAM,QAAQ,aAAa,OAAO;AAC3E,wBAAM,YAAY,WAAW,GAAG;AAChC,wBAAM,SACJ,gBAAgB,OACZ,IAAI,OAAO,YAAY,CAAC,GAAG,MAAM,OAAO,OAAO,QAAQ,CAAC,GAAG,KAC3D,YAAY,UAAU,IAAI,MAAM,YAAY,aAAa,OAAO;AACtE,wBAAM,SAAS,IAAI,UAAU,OAAO,EAAE;AACtC,wBAAM,UAAU,GAAG,WAAW,eAAe,IAAI,EAAE,IAAI,OAAO,EAAE;AAEhE,sBAAI,aAAa,UAAU;AACzB,2BACE,gBAAAA,OAAC,QAAmB,MAAK,YAAW,WAAW,eAAe,eAAe,MAAM,CAAC,IAClF;AAAA,sCAAAD;AAAA,wBAAC;AAAA;AAAA,0BACC;AAAA,0BACA;AAAA,0BACA,MAAM,QAAQ;AAAA,0BACd,SAAS,cAAc;AAAA,0BACvB,aAAa,cAAc,SAAY,SAAY;AAAA,0BACnD,QAAQ,CAAC,SAAS,WAAW,EAAE,OAAO,IAAI,IAAI,UAAU,OAAO,IAAI,KAAK,CAAC;AAAA,0BACzE,UAAU,CAAC,SAAS,KAAK,WAAW,KAAK,QAAQ,IAAI;AAAA,0BACrD,UAAU,MAAM,WAAW,KAAK,MAAM;AAAA;AAAA,sBACxC;AAAA,sBACC,cAAc,UACb,gBAAAA,MAAC,OAAE,IAAI,SAAS,MAAK,SAAQ,WAAU,kDACpC,qBACH;AAAA,yBAdK,OAAO,EAgBhB;AAAA,kBAEJ;AAEA,sBAAI,OAAO,SAAS,aAAa,UAAU;AACzC,2BACE,gBAAAA,MAAC,QAAmB,MAAK,YAAW,WAAW,aAAa,eAAe,MAAM,CAAC,IAChF,0BAAAA;AAAA,sBAAC;AAAA;AAAA,wBACC,MAAK;AAAA,wBACL,SAAS,UAAU;AAAA,wBACnB,cAAY,GAAG,OAAO,MAAM,KAAK,QAAQ;AAAA,wBACzC,wBAAsB,IAAI;AAAA,wBAC1B,2BAAyB,OAAO;AAAA,wBAChC,UAAU,SAAS,IAAI;AAAA,wBACvB,KAAK,CAAC,SAAS;AACb,mCAAS,QAAQ,IAAI,KAAK,IAAI;AAAA,wBAChC;AAAA,wBACA,SAAS,MAAM,SAAS,EAAE,OAAO,IAAI,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,wBAC9D,UAAU,CAAC,UAAU,KAAK,eAAe,KAAK,QAAQ,MAAM,OAAO,OAAO;AAAA,wBAC1E,WAAU;AAAA;AAAA,oBACZ,KAdO,OAAO,EAehB;AAAA,kBAEJ;AAEA,wBAAM,UAAU,aAAa,sBAAsB,QAAQ,OAAO,MAAM,IAAI;AAC5E,yBACE,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBAEC,MAAK;AAAA,sBACL,iBAAe,WAAW,SAAY;AAAA,sBACtC,wBAAsB,IAAI;AAAA,sBAC1B,2BAAyB,OAAO;AAAA,sBAChC,UAAU,SAAS,IAAI;AAAA,sBACvB,KAAK,CAAC,SAAS;AACb,iCAAS,QAAQ,IAAI,KAAK,IAAI;AAAA,sBAChC;AAAA,sBACA,SAAS,MAAM,SAAS,EAAE,OAAO,IAAI,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,sBAC9D,SAAS,MAAM;AACb,4BAAI,SAAU,WAAU,KAAK,MAAM;AAAA,sBACrC;AAAA,sBACA,WAAW,8EAA8E;AAAA,wBACvF;AAAA,sBACF,CAAC,IAAI,WAAW,gBAAgB,EAAE;AAAA,sBAElC,0BAAAC,OAAC,UAAK,WAAU,+CACd;AAAA,wCAAAD,MAAC,UAAK,WAAW,YAAY,KAAK,0BAA0B,4BACzD,sBAAY,KAAM,aAAa,WAAM,QAAS,SACjD;AAAA,wBACC,UACC,gBAAAA;AAAA,0BAAC;AAAA;AAAA,4BACC,SAAS,GAAG,WAAW,WAAW,IAAI,EAAE,IAAI,OAAO,EAAE;AAAA,4BACrD,cAAc,OAAO;AAAA,4BACrB;AAAA,4BACA;AAAA,4BACA,MAAM,eAAe;AAAA,4BACrB,UAAU,MAAM,cAAc,CAAC,YAAa,YAAY,MAAM,OAAO,GAAI;AAAA;AAAA,wBAC3E;AAAA,yBAEJ;AAAA;AAAA,oBA/BK,OAAO;AAAA,kBAgCd;AAAA,gBAEJ,CAAC;AAAA,gBACA,YACC,gBAAAA,MAAC,QAAG,MAAK,YAAW,WAAU,wBAC3B,cAAI,aAAa,OAAO,OAAO,kBAAkB,IAAI,KACpD,gBAAAC,OAAC,UAAK,WAAU,oCACd;AAAA,kCAAAD;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,cAAY,kBAAkB,QAAQ;AAAA,sBACtC,SAAS,MAAM,KAAK,cAAc,GAAG;AAAA,sBACrC,WAAU;AAAA,sBACX;AAAA;AAAA,kBAED;AAAA,kBACA,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,cAAY,QAAQ,QAAQ;AAAA,sBAC5B,SAAS,MAAM,iBAAiB,IAAI;AAAA,sBACpC,WAAU;AAAA,sBACX;AAAA;AAAA,kBAED;AAAA,mBACF,IAEA,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,cAAY,UAAU,QAAQ;AAAA,oBAC9B,SAAS,MAAM,iBAAiB,IAAI,EAAE;AAAA,oBACtC,WAAU;AAAA,oBAEV,0BAAAC;AAAA,sBAAC;AAAA;AAAA,wBACC,SAAQ;AAAA,wBACR,WAAU;AAAA,wBACV,MAAK;AAAA,wBACL,QAAO;AAAA,wBACP,aAAY;AAAA,wBACZ,eAAc;AAAA,wBACd,gBAAe;AAAA,wBACf,eAAW;AAAA,wBAEX;AAAA,0CAAAD,MAAC,cAAS,QAAO,gBAAe;AAAA,0BAChC,gBAAAA,MAAC,UAAK,GAAE,kFAAiF;AAAA;AAAA;AAAA,oBAC3F;AAAA;AAAA,gBACF,GAEJ;AAAA,iBAEJ;AAAA,cACC,aAAa,UACZ,gBAAAA,MAAC,QAAG,MAAK,OAAM,WAAU,0BACvB,0BAAAA,MAAC,QAAG,MAAK,YAAW,SAAS,YAAY,WAAU,aACjD,0BAAAA,MAAC,OAAE,MAAK,SAAQ,WAAU,uEACvB,oBACH,GACF,GACF;AAAA,iBAvJW,IAAI,EAyJnB;AAAA,UAEJ,CAAC,GACH;AAAA,UACC,aACC,gBAAAA,MAAC,WACC,0BAAAC,OAAC,QAAG,MAAK,OAAM,WAAU,4BACtB;AAAA,oBAAQ,IAAI,CAAC,WACZ,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBAEC,MAAK;AAAA,gBACL,WAAW,mDAAmD,eAAe,MAAM,CAAC;AAAA,gBAEnF,iBAAO,cAAc,sBAAsB,QAAQ,OAAO,YAAY,WAAW,GAAG,MAAM,IAAI;AAAA;AAAA,cAJ1F,OAAO;AAAA,YAKd,CACD;AAAA,YACA,YAAY,gBAAAA,MAAC,QAAG,MAAK,YAAW;AAAA,aACnC,GACF;AAAA;AAAA;AAAA,IAEJ,GACF;AAAA,IAEC,aACE,WACC,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,WAAU;AAAA,QAEV;AAAA,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,WAAU;AAAA,cACV,MAAK;AAAA,cACL,QAAO;AAAA,cACP,aAAY;AAAA,cACZ,eAAc;AAAA,cACd,gBAAe;AAAA,cACf,eAAW;AAAA,cAEX;AAAA,gCAAAD,MAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,gBACrC,gBAAAA,MAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA;AAAA;AAAA,UACvC;AAAA,UACC;AAAA;AAAA;AAAA,IACH;AAAA,KAEN;AAEJ;AAeA,SAAS,WAAW,EAAE,QAAQ,UAAU,MAAM,SAAS,aAAa,QAAQ,UAAU,SAAS,GAAoB;AACjH,QAAM,SAAS;AAAA,IACb,cAAc,GAAG,OAAO,MAAM,KAAK,QAAQ;AAAA,IAC3C,gBAAgB,UAAU,OAAO;AAAA,IACjC,oBAAoB;AAAA,IACpB,WAAW;AAAA,IACX,WAAW;AAAA,EACb;AAEA,MAAI,OAAO,SAAS,UAAU;AAC5B,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,OAAO;AAAA,QACP,UAAU,CAAC,UAAU;AACnB,iBAAO,MAAM,OAAO,KAAK;AACzB,mBAAS,MAAM,OAAO,KAAK;AAAA,QAC7B;AAAA,QACA,WAAW,CAAC,UAAU;AACpB,cAAI,MAAM,QAAQ,UAAU;AAC1B,kBAAM,eAAe;AACrB,qBAAS;AAAA,UACX;AAAA,QACF;AAAA,QACA,QAAQ,MAAM,SAAS,IAAI;AAAA,QAE3B;AAAA,0BAAAD,MAAC,YAAO,OAAM,IAAG,oBAAC;AAAA,UACjB,OAAO,QAAQ,IAAI,CAAC,WACnB,gBAAAA,MAAC,YAA0B,OAAO,OAAO,OACtC,iBAAO,SADG,OAAO,KAEpB,CACD;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,QAAM,UAAU,CAAC,UAAiE;AAChF,UAAM,YAAY,OAAO,SAAS,UAAU,OAAO,cAAc;AACjE,QAAI,MAAM,QAAQ,WAAW,CAAC,WAAW;AACvC,YAAM,eAAe;AACrB,eAAS,IAAI;AACb;AAAA,IACF;AACA,QAAI,MAAM,QAAQ,UAAU;AAC1B,YAAM,eAAe;AACrB,eAAS;AAAA,IACX;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,UAAU,OAAO,cAAc,MAAM;AACvD,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,MAAM;AAAA,QACN,OAAO;AAAA,QACP,UAAU,CAAC,UAAU,OAAO,MAAM,OAAO,KAAK;AAAA,QAC9C,WAAW;AAAA,QACX,QAAQ,MAAM,SAAS,IAAI;AAAA;AAAA,IAC7B;AAAA,EAEJ;AAEA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,MAAM,OAAO,SAAS,SAAS,SAAS;AAAA,MACxC,WAAW,OAAO,SAAS,YAAY,OAAO,SAAS,aAAa,YAAY;AAAA,MAChF,OAAO;AAAA,MACP,UAAU,CAAC,UAAU,OAAO,MAAM,OAAO,KAAK;AAAA,MAC9C,WAAW;AAAA,MACX,QAAQ,MAAM,SAAS,IAAI;AAAA;AAAA,EAC7B;AAEJ;AA2BA,SAAS,aAAa,EAAE,SAAS,cAAc,UAAU,QAAQ,MAAM,SAAS,GAAsB;AAOpG,QAAM,QAA+B,OAAO,SAAS;AACrD,QAAM,UAAUM;AAAA,IACd,CAAC,SAAkB;AACjB,UAAI,CAAC,KAAM,UAAS;AAAA,IACtB;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AACA,QAAM,EAAE,cAAc,YAAY,UAAU,aAAa,IAAI,WAAW,MAAM,OAAO;AACrF,SACE,gBAAAL,OAAC,UAAK,KAAK,cAAc,WAAU,wBACjC;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACJ,GAAG;AAAA,QACJ,cAAY,cAAc,YAAY,KAAK,QAAQ;AAAA,QACnD,iBAAe,OAAO,UAAU;AAAA,QAChC,OAAO,aAAa,KAAK;AAAA,QACzB,SAAS,CAAC,UAAU;AAClB,gBAAM,gBAAgB;AACtB,mBAAS;AAAA,QACX;AAAA,QACA,WAAW,gFAAgFE,aAAY,KAAK,CAAC;AAAA,QAE7G,0BAAAF;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,MAAK;AAAA,YACL,QAAO;AAAA,YACP,aAAY;AAAA,YACZ,eAAc;AAAA,YACd,eAAW;AAAA,YAEX,0BAAAA,MAAC,UAAK,GAAE,wBAAuB;AAAA;AAAA,QACjC;AAAA;AAAA,IACF;AAAA,IACA,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,IAAI;AAAA,QACJ,MAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA,WAAW,oEAAoE,cAAc;AAAA,QAE5F;AAAA,iBAAO,SACN,gBAAAA,OAAC,UAAK,WAAU,uFAAsF;AAAA;AAAA,YAClG,OAAO;AAAA,YAAM;AAAA,aACjB;AAAA,UAEF,gBAAAA,OAAC,UAAK,WAAU,gDACb;AAAA,mBAAO,SAAS;AAAA,YAChB,OAAO,UAAU,SAAM,OAAO,OAAO,KAAK;AAAA,YAC1C,SAAM,aAAa,KAAK,CAAC;AAAA,aAC5B;AAAA,UACC,OAAO,QACN,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACC,MAAM,OAAO;AAAA,cACb,QAAO;AAAA,cACP,KAAI;AAAA,cACJ,SAAS,CAAC,UAAU,MAAM,gBAAgB;AAAA,cAC1C,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA;AAAA;AAAA,IAEJ;AAAA,KACF;AAEJ;AAkBA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAuB;AACrB,QAAM,SAASQ,SAAQ,MAAM,aAAa,OAAO,GAAG,CAAC,OAAO,CAAC;AAE7D,SACE,gBAAAP;AAAA,IAAC;AAAA;AAAA,MACC,YAAU;AAAA,MACV,cAAY;AAAA,MACZ,UAAU,CAAC,UAAU;AACnB,cAAM,eAAe;AACrB,iBAAS;AAAA,MACX;AAAA,MACA,WAAU;AAAA,MAEV;AAAA,wBAAAD,MAAC,QAAG,WAAU,yCAAyC,iBAAM;AAAA,QAC5D,cAAc,QACb,gBAAAA,MAAC,OAAE,MAAK,SAAQ,WAAU,mEACvB,qBACH;AAAA,QAED,OAAO,IAAI,CAAC,UAAU;AACrB,gBAAM,SAAS,MAAM,QAAQ,OAAO,CAAC,WAAW,2BAA2B,QAAQ,KAAK,CAAC;AACzF,cAAI,OAAO,WAAW,EAAG,QAAO;AAChC,iBACE,gBAAAC;AAAA,YAAC;AAAA;AAAA,cAEC,WAAW,MAAM,UAAU,OAAO,YAAY;AAAA,cAE7C;AAAA,sBAAM,UAAU,QACf,gBAAAD,MAAC,YAAO,WAAU,kDAAkD,gBAAM,OAAM;AAAA,gBAElF,gBAAAA,MAAC,SAAI,WAAU,6BACZ,iBAAO,IAAI,CAAC,WAAW;AACtB,wBAAM,UAAU,GAAG,WAAW,IAAI,OAAO,EAAE;AAC3C,wBAAM,UAAU,GAAG,OAAO;AAC1B,wBAAM,UAAU,OAAO,OAAO,EAAE;AAChC,yBACE,gBAAAC;AAAA,oBAAC;AAAA;AAAA,sBAEC,WAAW,OAAO,SAAS,UAAU,OAAO,cAAc,OAAO,kBAAkB;AAAA,sBAEnF;AAAA,wCAAAA,OAAC,WAAM,SAAS,SAAS,WAAU,wDAChC;AAAA,iCAAO;AAAA,0BACP,OAAO,aAAa,QAAQ,gBAAAD,MAAC,UAAK,WAAU,2BAA0B,eAAC;AAAA,2BAC1E;AAAA,wBACA,gBAAAA;AAAA,0BAAC;AAAA;AAAA,4BACC;AAAA,4BACA,IAAI;AAAA,4BACJ,OAAO,MAAM,OAAO,EAAE,KAAK;AAAA,4BAC3B,SAAS,YAAY;AAAA,4BACrB,aAAa,YAAY,SAAY,SAAY;AAAA,4BACjD,SAAS,CAAC,SAAS,SAAS,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC;AAAA;AAAA,wBAC7D;AAAA,wBACC,OAAO,QAAQ,gBAAAA,MAAC,OAAE,WAAU,0CAA0C,iBAAO,MAAK;AAAA,wBAClF,YAAY,UACX,gBAAAA,MAAC,OAAE,IAAI,SAAS,MAAK,SAAQ,WAAU,qCACpC,mBACH;AAAA;AAAA;AAAA,oBAnBG,OAAO;AAAA,kBAqBd;AAAA,gBAEJ,CAAC,GACH;AAAA;AAAA;AAAA,YArCK,MAAM,SAAS;AAAA,UAsCtB;AAAA,QAEJ,CAAC;AAAA,QACD,gBAAAC,OAAC,SAAI,WAAU,2BACb;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,UAAU;AAAA,cACV,WAAU;AAAA,cAET,iBAAO,iBAAY;AAAA;AAAA,UACtB;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAcA,SAAS,WAAW,EAAE,QAAQ,IAAI,OAAO,SAAS,aAAa,QAAQ,GAAoB;AACzF,QAAM,SAAS;AAAA,IACb;AAAA,IACA,gBAAgB,UAAU,OAAO;AAAA,IACjC,oBAAoB;AAAA,EACtB;AAEA,MAAI,OAAO,SAAS,WAAW;AAC7B,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,MAAK;AAAA,QACL,SAAS,UAAU;AAAA,QACnB,UAAU,CAAC,UAAU,QAAQ,MAAM,OAAO,OAAO;AAAA,QACjD,WAAU;AAAA;AAAA,IACZ;AAAA,EAEJ;AAEA,MAAI,OAAO,SAAS,UAAU;AAC5B,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,WAAW;AAAA,QACX,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,QAC3C,UAAU,CAAC,UAAU,QAAQ,MAAM,OAAO,UAAU,KAAK,OAAO,MAAM,OAAO,KAAK;AAAA,QAElF;AAAA,0BAAAD,MAAC,YAAO,OAAM,IAAG,oBAAC;AAAA,UACjB,OAAO,QAAQ,IAAI,CAAC,WACnB,gBAAAA,MAAC,YAA0B,OAAO,OAAO,OACtC,iBAAO,SADG,OAAO,KAEpB,CACD;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,OAAO,SAAS,UAAU,OAAO,cAAc,MAAM;AACvD,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,WAAW;AAAA,QACX,MAAM;AAAA,QACN,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,QAC3C,UAAU,CAAC,UAAU,QAAQ,MAAM,OAAO,UAAU,KAAK,OAAO,MAAM,OAAO,KAAK;AAAA;AAAA,IACpF;AAAA,EAEJ;AAEA,MAAI,OAAO,SAAS,YAAY,OAAO,SAAS,YAAY;AAC1D,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,WAAW;AAAA,QACX,MAAK;AAAA,QACL,WAAU;AAAA,QACV,OAAO,UAAU,OAAO,KAAK,OAAO,KAAK;AAAA,QACzC,UAAU,CAAC,UAAU;AACnB,gBAAM,MAAM,MAAM,OAAO;AACzB,cAAI,IAAI,KAAK,MAAM,IAAI;AACrB,oBAAQ,IAAI;AACZ;AAAA,UACF;AACA,gBAAM,SAAS,mBAAmB,QAAQ,GAAG;AAC7C,kBAAQ,OAAO,YAAY,OAAO,QAAQ,GAAG;AAAA,QAC/C;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,WAAW;AAAA,MACX,MAAM,OAAO,SAAS,SAAS,SAAS;AAAA,MACxC,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,MAC3C,UAAU,CAAC,UAAU,QAAQ,MAAM,OAAO,UAAU,KAAK,OAAO,MAAM,OAAO,KAAK;AAAA;AAAA,EACpF;AAEJ;;;ArB/iCQ,SA8hBE,YAAAU,WA9hBF,OAAAC,OAKA,QAAAC,cALA;AArDD,SAAS,gBAAgB,KAAyB,QAAuC;AAC9F,MAAI,IAAI,gBAAgB,QAAQ,IAAI,oBAAoB,KAAM,QAAO;AACrE,QAAM,UAAU,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,IAAI,SAAS,GAAG;AAC5D,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,QACH,IAAI,gBAAgB,KAAK,OAAO,QAAQ,UAAU,CAAC,KACnD,IAAI,oBAAoB,KAAK,OAAO,QAAQ,cAAc,CAAC;AAC9D,MAAI,CAAC,SAAS,IAAI,KAAK,QAAQ,EAAG,QAAO;AACzC,SAAO,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,KAAK,IAAI,KAAK,QAAQ,CAAC,CAAC;AAClE;AAGO,SAAS,sBAAsB,KAAwC;AAC5E,MAAI,IAAI,oBAAoB,QAAQ,CAAC,IAAI,WAAY,QAAO;AAC5D,SAAO,GAAG,KAAK,MAAM,IAAI,oBAAoB,IAAI,aAAa,IAAK,CAAC;AACtE;AAkCO,SAAS,WAAW,EAAE,KAAK,QAAQ,GAAoB;AAC5D,SACE,gBAAAA,OAAC,SAAI,WAAW,wGAAwG,cAAc,IACpI;AAAA,oBAAAA,OAAC,SAAI,WAAU,4DACb;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,iCACT,IAAI,WAAW,YAAY,eAAe,IAAI,WAAW,UAAU,mBAAmB,YACxF;AAAA;AAAA,MACF;AAAA,MACA,gBAAAC,OAAC,SAAI,WAAU,kBACb;AAAA,wBAAAD,MAAC,OAAE,WAAU,kCAAkC,cAAI,OAAM;AAAA,QACzD,gBAAAA,MAAC,OAAE,WAAU,wDAAwD,cAAI,UAAS;AAAA,SACpF;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,cAAW;AAAA,UACX,WAAU;AAAA,UAEV,0BAAAA,MAAC,SAAI,WAAU,WAAU,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,eAAW,MAC9H,0BAAAA,MAAC,UAAK,GAAE,wBAAuB,GACjC;AAAA;AAAA,MACF;AAAA,OACF;AAAA,IACA,gBAAAC,OAAC,SAAI,WAAU,wCACZ;AAAA,UAAI,MAAM,WAAW,KACpB,gBAAAD,MAAC,OAAE,WAAU,iCAAgC,oCAAsB;AAAA,MAEpE,IAAI,MAAM,IAAI,CAAC,MAAM,MACpB,gBAAAC,OAAC,SAAY,WAAU,8CACrB;AAAA,wBAAAA,OAAC,SAAI,WAAU,gEACb;AAAA,0BAAAD,MAAC,UAAK,WAAW,yBAAyB,KAAK,WAAW,UAAU,qBAAqB,uBAAuB,IAC7G,eAAK,WAAW,UAAU,WAAM,KACnC;AAAA,UACA,gBAAAA,MAAC,UAAK,WAAU,6CAA6C,eAAK,OAAM;AAAA,UACxE,gBAAAA,MAAC,UAAK,WAAU,8CACb,cAAI,KAAK,KAAK,EAAE,EAAE,mBAAmB,GACxC;AAAA,WACF;AAAA,QACC,KAAK,UACJ,gBAAAA,MAAC,SAAI,WAAU,oHACZ,eAAK,QACR;AAAA,WAbM,CAeV,CACD;AAAA,OACH;AAAA,IACA,gBAAAA,MAAC,OAAE,WAAU,sEAAqE,4DAElF;AAAA,KACF;AAEJ;AAmBO,SAAS,kBAAkB,MAAuD;AACvF,QAAM,UAAU,KAAK;AACrB,MAAI,CAAC,SAAS,MAAM,QAAQ,QAAQ,WAAW,yBAAyB,CAAC,QAAQ,OAAO,WAAY,QAAO;AAC3G,SAAO,EAAE,YAAY,QAAQ,OAAO,WAAW;AACjD;AAsHO,SAAS,eAAe;AAAA,EAC7B,cAAc;AAAA,EACd,WAAW;AAAA,EACX,UAAU;AAAA,EACV;AACF,GAAwB;AACtB,SACE,gBAAAC,OAAC,SAAI,WAAU,uFACb;AAAA,oBAAAD,MAAC,UAAK,WAAU,2GACd,0BAAAA,MAAC,aAAU,MAAM,IAAI,WAAU,YAAW,GAC5C;AAAA,IACA,gBAAAA,MAAC,OAAE,WAAU,+EAA+E,uBAAY;AAAA,IACxG,gBAAAA,MAAC,QAAG,WAAU,2FACX,oBACH;AAAA,IACC,WAAW,gBAAAA,MAAC,OAAE,WAAU,mEAAmE,mBAAQ;AAAA,IACnG,SAAS,MAAM,SAAS,KACvB,gBAAAA,MAAC,SAAI,WAAU,2CACZ,gBAAM,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,MAC5B,gBAAAC;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,SAAS,KAAK;AAAA,QACd,WAAU;AAAA,QAEV;AAAA,0BAAAD,MAAC,UAAK,WAAU,yCAAyC,eAAK,OAAM;AAAA,UACnE,KAAK,eACJ,gBAAAA,MAAC,UAAK,WAAU,yDAAyD,eAAK,aAAY;AAAA;AAAA;AAAA,MAPvF;AAAA,IASP,CACD,GACH;AAAA,KAEJ;AAEJ;AAeA,SAAS,UAAU,EAAE,MAAM,UAAU,GAAyC;AAC5E,MAAI,KAAK,WAAW,UAAU,GAAG;AAC/B,WACE,gBAAAC,OAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ;AAAA,sBAAAD,MAAC,cAAS,QAAO,kBAAiB;AAAA,MAClC,gBAAAA,MAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,OACxC;AAAA,EAEJ;AACA,MAAI,SAAS,mBAAmB;AAC9B,WACE,gBAAAC,OAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ;AAAA,sBAAAD,MAAC,UAAK,GAAE,8DAA6D;AAAA,MACrE,gBAAAA,MAAC,UAAK,GAAE,0BAAyB;AAAA,OACnC;AAAA,EAEJ;AACA,MAAI,SAAS,qBAAqB;AAChC,WACE,gBAAAC,OAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,eAAW,MAChI;AAAA,sBAAAD,MAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,MAC9B,gBAAAA,MAAC,UAAK,GAAE,eAAc;AAAA,OACxB;AAAA,EAEJ;AACA,SACE,gBAAAC,OAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ;AAAA,oBAAAD,MAAC,UAAK,GAAE,gCAA+B;AAAA,IACvC,gBAAAA,MAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,KAChC;AAEJ;AAEA,SAAS,cAAc,MAA0G;AAC/H,SAAO,KAAK;AACd;AAKA,SAAS,eAAe,MAAiC;AACvD,SAAO,KAAK,WAAW,WAAW,cAAc,IAAI,GAAG,OAAO;AAChE;AAWO,SAAS,iBAAiB,MAAkC;AACjE,QAAM,SAAS,eAAe,IAAI;AAClC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,IAAI,KAAK;AAAA,IACT,MAAM,KAAK,SAAS,wBAAwB,SAAS,KAAK;AAAA,IAC1D,OAAO;AAAA,MACL,QAAQ,KAAK,WAAW,YAAY,YAAY,SAAS,UAAU;AAAA,MACnE,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,OAAO,SAAU,cAAc,IAAI,GAAG,WAAW,gBAAiB;AAAA,IACpE;AAAA,EACF;AACF;AASA,SAAS,YAAY,MAAmC;AACtD,MAAI,KAAK,SAAS,kBAAmB,QAAO;AAC5C,MAAI,KAAK,SAAS,oBAAqB,QAAO;AAC9C,MAAI,KAAK,KAAK,WAAW,UAAU,EAAG,QAAO;AAC7C,SAAO;AACT;AAOA,SAAS,iBAAiB,MAAsB;AAC9C,QAAM,QAAQ,KACX,QAAQ,sBAAsB,OAAO,EACrC,QAAQ,UAAU,GAAG,EACrB,KAAK;AACR,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,OAAO,CAAC,EAAE,YAAY,IAAI,MAAM,MAAM,CAAC;AACtD;AAMA,SAAS,kBAAkB,MAAgC;AACzD,QAAM,IAAI,KAAK,QAAQ,CAAC;AACxB,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,aAAO,EAAE,QAAQ,YAAY,OAAO,EAAE,KAAK,CAAC,MAAM;AAAA,IACpD,KAAK;AACH,aAAO,oBAAoB,OAAO,EAAE,eAAe,WAAW,CAAC;AAAA,IACjE,KAAK;AACH,aAAO,OAAO,OAAO,EAAE,WAAW,SAAS,CAAC;AAAA,IAC9C,KAAK;AACH,aAAO,qBAAqB,OAAO,EAAE,cAAc,EAAE,CAAC;AAAA,IACxD,KAAK;AACH,aAAO,cAAc,OAAO,EAAE,SAAS,WAAW,CAAC;AAAA,IACrD,KAAK;AACH,aAAO,sBAAmB,OAAO,EAAE,SAAS,EAAE,CAAC;AAAA,IACjD,KAAK;AACH,aAAO,SAAS,OAAO,EAAE,QAAQ,EAAE,CAAC;AAAA,IACtC;AACE,aAAO,iBAAiB,KAAK,IAAI;AAAA,EACrC;AACF;AAQA,SAAS,gBAAgB,MAAoE;AAC3F,QAAM,IAAK,KAAK,QAAQ,CAAC;AACzB,QAAM,WAAW,CAAC,MAChB,OAAO,MAAM,YAAY,EAAE,KAAK,IAAI,EAAE,KAAK,IAAI;AACjD,QAAM,SAAS,CAAC,MACd,MAAM,QAAQ,CAAC,IACX,EAAE,IAAI,CAAC,MAAO,OAAO,MAAM,WAAW,IAAI,IAAK,EAAE,OAAO,CAAC,MAAmB,CAAC,CAAC,CAAC,IAC/E,SAAS,CAAC,IACR,CAAC,SAAS,CAAC,CAAW,IACtB,CAAC;AAGT,QAAM,aACJ,SAAS,EAAE,OAAO,KAClB,SAAS,EAAE,WAAW,MACrB,SAAS,EAAE,IAAI,IACZ,GAAG,OAAO,EAAE,IAAI,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,SAAS,EAAE,KAAK,IAAI,KAAK,SAAS,EAAE,KAAK,CAAC,KAAK,EAAE,KACxF;AAEN,QAAM,eAAe;AAAA,IACnB,GAAG,OAAO,EAAE,YAAY;AAAA,IACxB,GAAG,OAAO,EAAE,QAAQ;AAAA,IACpB,GAAG,OAAO,EAAE,OAAO;AAAA,IACnB,GAAG,OAAO,EAAE,SAAS;AAAA,EACvB;AACA,QAAM,OAAO,aAAa,SAAS,OAAO,aAAa,KAAK,OAAO,CAAC,KAAK;AACzE,QAAM,UAAU,aAAa,GAAG,UAAU,GAAG,IAAI,KAAK,aAAa,SAAS,cAAc,aAAa,KAAK,OAAO,CAAC,KAAK;AAGzH,QAAM,OAAiB,CAAC;AACxB,QAAM,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE;AACpC,MAAI,OAAO,SAAS,YAAY,OAAO,EAAG,MAAK,KAAK,KAAK,OAAO,OAAO,KAAK,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,EAAE;AAAA,WACjG,SAAS,IAAI,EAAG,MAAK,KAAK,SAAS,IAAI,CAAW;AAC3D,QAAM,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE;AACzC,MAAI,OAAO,UAAU,YAAY,QAAQ,EAAG,MAAK,KAAK,YAAY,MAAM,eAAe,CAAC,EAAE;AAAA,WACjF,SAAS,KAAK,EAAG,MAAK,KAAK,SAAS,KAAK,CAAW;AAE7D,SAAO,EAAE,SAAS,KAAK;AACzB;AAEA,SAAS,SAAS,GAAY,MAAM,KAAa;AAC/C,QAAM,IAAI,OAAO,MAAM,WAAW,IAAI,KAAK,UAAU,CAAC;AAKtD,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,SAAO,EAAE,SAAS,MAAM,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,WAAM;AAClD;AAEA,SAAS,OAAO,EAAE,KAAK,GAAsC;AAC3D,QAAM,UAAU,OAAO,QAAQ,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,UAAa,MAAM,QAAQ,MAAM,EAAE;AAChG,MAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,SACE,gBAAAA,MAAC,QAAG,WAAU,6CACX,kBAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MACjB,gBAAAC,OAAC,SAAY,WAAU,YACrB;AAAA,oBAAAD,MAAC,QAAG,WAAU,+CAA+C,aAAE;AAAA,IAC/D,gBAAAA,MAAC,QAAG,WAAU,uFACX,mBAAS,CAAC,GACb;AAAA,OAJQ,CAKV,CACD,GACH;AAEJ;AAGA,SAAS,YAAY,EAAE,KAAK,GAA+B;AACzD,QAAM,UAAU,cAAc,IAAI;AAClC,QAAM,IAAK,SAAS,UAAU,CAAC;AAC/B,SACE,gBAAAC,OAAC,SAAI,WAAU,gFACb;AAAA,oBAAAA,OAAC,SAAI,WAAU,mDACb;AAAA,sBAAAD,MAAC,UAAK,WAAU,6BAA4B,eAAC;AAAA,MAC7C,gBAAAA,MAAC,UAAK,WAAU,yCAAyC,iBAAO,KAAK,MAAM,WAAW,EAAE,GAAE;AAAA,MACzF,EAAE,YAAY,QACb,gBAAAC,OAAC,UAAK,WAAW,EAAE,aAAa,IAAI,iBAAiB,oBAAoB;AAAA;AAAA,QAAM,EAAE;AAAA,SAAS;AAAA,OAE9F;AAAA,IACA,gBAAAD,MAAC,SAAI,WAAU,+EACZ,mBAAS,OAAO,QAAS,QAAQ,WAAW,WAAY,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,KAAK,eAC9G;AAAA,KACF;AAEJ;AAGA,SAAS,kBAAkB,EAAE,KAAK,GAA+B;AAK/D,QAAM,SAAkB,KAAK;AAC7B,QAAM,WACJ,OAAO,WAAW,YAAY,WAAW,OACpC,SACD;AACN,SACE,gBAAAC,OAAC,SAAI,WAAU,aACZ;AAAA,SAAK,QAAQ,OAAO,KAAK,KAAK,IAAI,EAAE,SAAS,KAC5C,gBAAAA,OAAC,SACC;AAAA,sBAAAD,MAAC,OAAE,WAAU,gFAA+E,yBAAW;AAAA,MACvG,gBAAAA,MAAC,UAAO,MAAM,KAAK,MAAM;AAAA,OAC3B;AAAA,IAED,WACC,gBAAAC,OAAC,SACC;AAAA,sBAAAD,MAAC,OAAE,WAAU,gFACV,mBAAS,OAAO,QAAQ,WAAW,UACtC;AAAA,MACC,SAAS,OAAO,QACf,gBAAAA,MAAC,OAAE,WAAU,4BAA4B,mBAAS,WAAW,eAAc,IACzE,SAAS,UAAU,OAAO,SAAS,WAAW,WAChD,gBAAAA,MAAC,UAAO,MAAM,SAAS,QAAmC,IACxD,SAAS,UAAU,OACrB,gBAAAA,MAAC,OAAE,WAAU,+CAA+C,mBAAS,SAAS,MAAM,GAAE,IACpF;AAAA,OACN,IACE,UAAU,OACZ,gBAAAC,OAAC,SACC;AAAA,sBAAAD,MAAC,OAAE,WAAU,gFAA+E,oBAAM;AAAA,MAClG,gBAAAA,MAAC,OAAE,WAAU,+CAA+C,mBAAS,MAAM,GAAE;AAAA,OAC/E,IACE;AAAA,KACN;AAEJ;AAOA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,CAAC,UAAU,WAAW,IAAIE,WAAS,KAAK;AAC9C,QAAM,EAAE,SAAS,KAAK,IAAI,gBAAgB,IAAI;AAC9C,QAAM,SAAS,YAAY,KAAK,IAAI,IAAI,MAAM,OAAO;AACrD,QAAM,EAAE,SAAS,UAAU,KAAK,OAAO,IAAI,WAAW;AAEtD,SACE,gBAAAD,OAAC,SAAI,WAAU,oHACb;AAAA,oBAAAA,OAAC,SAAI,WAAU,wCACb;AAAA,sBAAAD,MAAC,UAAK,WAAU,2GACd,0BAAAA,MAAC,aAAU,MAAM,KAAK,MAAM,WAAU,eAAc,GACtD;AAAA,MACA,gBAAAC,OAAC,SAAI,WAAU,kBACb;AAAA,wBAAAD,MAAC,OAAE,WAAU,0EAAyE,iCAAmB;AAAA,QACzG,gBAAAA,MAAC,OAAE,WAAU,iEAAiE,4BAAkB,IAAI,GAAE;AAAA,QACrG,WAAW,gBAAAA,MAAC,OAAE,WAAU,0DAA0D,mBAAQ;AAAA,QAC1F,KAAK,SAAS,KACb,gBAAAA,MAAC,SAAI,WAAU,8CACZ,eAAK,IAAI,CAAC,GAAG,MACZ,gBAAAA,MAAC,UAAa,WAAU,uFACrB,eADQ,CAEX,CACD,GACH;AAAA,SAEJ;AAAA,OACF;AAAA,IACA,gBAAAC,OAAC,SAAI,WAAU,sDACZ;AAAA,iBACC,gBAAAA,OAAAF,WAAA,EACE;AAAA,wBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,UAAU;AAAA,YACV,SAAS,MAAM,OAAO,MAAM,SAAS,UAAU,QAAQ,YAAY,KAAK,EAAE,CAAC;AAAA,YAC3E,WAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,UAAU;AAAA,YACV,SAAS,MAAM,OAAO,MAAM,SAAS,SAAS,QAAQ,YAAY,KAAK,EAAE,CAAC;AAAA,YAC1E,WAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA,SACF,IAEA,gBAAAA,MAAC,UAAK,WAAU,iDAAgD,qCAAkB;AAAA,MAEpF,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;AAAA,UACpC,iBAAe;AAAA,UACf,WAAU;AAAA,UAET;AAAA,uBAAW,iBAAiB;AAAA,YAC7B,gBAAAD,MAAC,eAAY,WAAW,gCAAgC,WAAW,eAAe,EAAE,IAAI;AAAA;AAAA;AAAA,MAC1F;AAAA,OACF;AAAA,IACC,YACC,gBAAAA,MAAC,SAAI,WAAU,gDACZ,oBAAU,gBAAAA,MAAC,qBAAkB,MAAY,GAC5C;AAAA,KAEJ;AAEJ;AAOA,SAAS,aAAa,EAAE,KAAK,GAA+B;AAC1D,QAAM,IAAK,KAAK,QAAQ,CAAC;AACzB,QAAM,OAAO,OAAO,EAAE,SAAS,WAAW,EAAE,OAAO,OAAO,EAAE,OAAO,WAAW,EAAE,KAAK,OAAO,EAAE,aAAa,WAAW,EAAE,WAAW;AACnI,SACE,gBAAAA,MAAC,SAAI,WAAU,0BACb,0BAAAA,MAAC,SAAI,WAAU,oIACb,0BAAAC,OAAC,SAAI,WAAU,8CACb;AAAA,oBAAAD,MAAC,UAAK,WAAU,oIACd,0BAAAA,MAAC,aAAU,MAAM,KAAK,MAAM,WAAU,eAAc,GACtD;AAAA,IACA,gBAAAA,MAAC,UAAK,WAAU,kEAAkE,4BAAkB,IAAI,GAAE;AAAA,IACzG,QACC,gBAAAA,MAAC,UAAK,WAAU,oFAAoF,gBAAK;AAAA,KAE7G,GACF,GACF;AAEJ;AAIA,SAAS,aAAa,MAAgC;AACpD,MAAI,KAAK,SAAS,sBAAuB,QAAO;AAChD,SAAO,kBAAkB,IAAI;AAC/B;AAKA,SAAS,mBAAmB,MAA4C;AACtE,MAAI,KAAK,SAAS,sBAAuB,QAAO;AAChD,QAAM,UAAU,KAAK,MAAM;AAC3B,SAAO,OAAO,YAAY,YAAY,UAAU,UAAU;AAC5D;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,UAAU,KAAK,WAAW,SAAS,kBAAkB,IAAI,IAAI;AACnE,QAAM,OAAO,YAAY,IAAI;AAC7B,QAAM,SAAS,eAAe,IAAI;AAIlC,MAAI,SAAS;AACX,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF;AAAA,EAEJ;AAGA,MAAI,SAAS,cAAc,CAAC,QAAQ;AAClC,WAAO,gBAAAA,MAAC,gBAAa,MAAY;AAAA,EACnC;AAQA,QAAM,SAAS,YAAY,KAAK,IAAI,IAAI,MAAM,OAAO;AACrD,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,iBAAiB,IAAI;AAAA,MAC3B,OAAO,aAAa,IAAI;AAAA,MACxB,aAAa,mBAAmB,IAAI;AAAA,MACpC,kBAAkB,MAChB,WACC,KAAK,SAAS,wBAAwB,gBAAAA,MAAC,eAAY,MAAY,IAAK,gBAAAA,MAAC,qBAAkB,MAAY;AAAA,MAEtG,SACE,aAAa,KAAK,KAAK,WAAW,UAAU,IAC1C,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,UAAU,MAAM,OAAO;AAAA,UACtC,WAAU;AAAA,UACX;AAAA;AAAA,MAED,IACE;AAAA;AAAA,EAER;AAEJ;AAKA,SAAS,iBAAiB;AACxB,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,eAAW;AAAA;AAAA,EACb;AAEJ;AAMA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,OAAO,cAAc,SAAS,SAAS;AAC7C,QAAM,OAAOG,SAAQ,MAAM,WAAW,IAAI,GAAG,CAAC,YAAY,IAAI,CAAC;AAK/D,MAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,UAAW,QAAO;AAC1C,SACE,gBAAAF,OAAC,SAAI,WAAW,kBACb;AAAA;AAAA,IAGA,aAAa,gBAAAD,MAAC,kBAAe;AAAA,KAChC;AAEJ;AAKA,IAAM,uBAAuB;AAQ7B,SAAS,gBAAgB,MAAiC;AACxD,SACE,KAAK,WAAW,aAChB,eAAe,IAAI,KACnB,kBAAkB,IAAI,MAAM;AAEhC;AAQA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASG;AACD,QAAM,YAAY,SAAS,SAAS;AACpC,QAAM,iBAAiB,IAAI;AAAA,IACzB,SAAS,QAAQ,CAAC,MAAO,EAAE,SAAS,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAE;AAAA,EAChE;AACA,QAAM,qBAAqB,IAAI,aAAa,CAAC,GAAG;AAAA,IAC9C,CAAC,OAAO,CAAC,eAAe,IAAI,GAAG,EAAE;AAAA,EACnC;AACA,QAAM,iBAAiB,CAAC,SACtB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MAEC;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA,WAAW;AAAA,MACX,WAAW;AAAA;AAAA,IALN,QAAQ,KAAK,EAAE;AAAA,EAMtB;AAQF,QAAM,SAGF,CAAC;AACL,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAM,MAAM,SAAS,CAAC;AACtB,QAAI,CAAC,IAAK;AACV,QAAI,IAAI,SAAS,QAAQ;AACvB,aAAO,KAAK,EAAE,MAAM,QAAQ,OAAO,GAAG,SAAS,IAAI,QAAQ,CAAC;AAAA,IAC9D,OAAO;AACL,YAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,UAAI,QAAQ,KAAK,SAAS,QAAS,MAAK,MAAM,KAAK,IAAI,IAAI;AAAA,UACtD,QAAO,KAAK,EAAE,MAAM,SAAS,OAAO,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;AAAA,IACjE;AAAA,EACF;AAEA,SACE,gBAAAC,OAAC,SAAI,WAAU,uBACZ;AAAA,WAAO;AAAA,MAAI,CAAC,MACX,EAAE,SAAS,SACT,gBAAAD;AAAA,QAAC;AAAA;AAAA,UAKC,SAAS,EAAE;AAAA,UAEX,WAAW,aAAa,EAAE,UAAU;AAAA,UACpC,WAAW,aAAa,EAAE,UAAU;AAAA,UACpC;AAAA,UACA;AAAA;AAAA,QANK,QAAQ,EAAE,KAAK;AAAA,MAOtB,IACE,CAAC,aACH,EAAE,MAAM,UAAU,wBAClB,CAAC,EAAE,MAAM,KAAK,eAAe;AAAA;AAAA;AAAA,QAG7B,gBAAAC,OAAC,aACC;AAAA,0BAAAA,OAAC,aAAQ,WAAU,uIAAsI;AAAA;AAAA,YACvI,EAAE,MAAM;AAAA,YAAO;AAAA,aACjC;AAAA,UACA,gBAAAD,MAAC,SAAI,WAAU,gCACZ,YAAE,MAAM,IAAI,cAAc,GAC7B;AAAA,aANY,SAAS,EAAE,KAAK,EAO9B;AAAA,UAEA,gBAAAA,MAAC,SAA6B,WAAU,uBACrC,YAAE,MAAM,IAAI,cAAc,KADnB,SAAS,EAAE,KAAK,EAE1B;AAAA,IAEJ;AAAA,IACC,kBAAkB,IAAI,cAAc;AAAA,IACpC,aAAa,SAAS,SAAS,GAAG,SAAS,UAAU,gBAAAA,MAAC,kBAAe;AAAA,KACxE;AAEJ;AAQA,IAAM,wBACJ;AAIF,SAAS,WAAW,KAA4B;AAC9C,QAAM,WAAW,IAAI,UAAU,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,KAAK,CAAC;AACpE,MAAI,SAAS,SAAS,EAAG,QAAO,SAAS,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,MAAM;AAC1E,SAAO,IAAI;AACb;AAIA,SAAS,kBAAkB,EAAE,KAAK,GAAqB;AACrD,QAAM,CAAC,QAAQ,SAAS,IAAIE,WAAS,KAAK;AAC1C,QAAM,WAAWE,SAA6C,IAAI;AAClE,EAAAC;AAAA,IACE,MAAM,MAAM;AACV,UAAI,SAAS,YAAY,KAAM,cAAa,SAAS,OAAO;AAAA,IAC9D;AAAA,IACA,CAAC;AAAA,EACH;AACA,QAAM,OAAO,MAAM;AACjB,UAAM,YAAY,UAAU;AAC5B,QAAI,CAAC,UAAW;AAChB,SAAK,UAAU,UAAU,IAAI,EAAE;AAAA,MAC7B,MAAM;AACJ,kBAAU,IAAI;AACd,YAAI,SAAS,YAAY,KAAM,cAAa,SAAS,OAAO;AAC5D,iBAAS,UAAU,WAAW,MAAM,UAAU,KAAK,GAAG,IAAI;AAAA,MAC5D;AAAA,MACA,MAAM;AAAA,MAAC;AAAA,IACT;AAAA,EACF;AACA,SACE,gBAAAL;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS;AAAA,MACT,cAAW;AAAA,MACX,OAAM;AAAA,MACN,WAAU;AAAA,MAET,mBACC,gBAAAA,MAAC,SAAI,WAAU,eAAc,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACzJ,0BAAAA,MAAC,cAAS,QAAO,kBAAiB,GACpC,IAEA,gBAAAC,OAAC,SAAI,WAAU,eAAc,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACzJ;AAAA,wBAAAD,MAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,QAChD,gBAAAA,MAAC,UAAK,GAAE,2DAA0D;AAAA,SACpE;AAAA;AAAA,EAEJ;AAEJ;AAEA,SAAS,qBAAqB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAeG;AAKD,QAAM,UAAU,cAAc,IAAI,SAAS,SAAS;AACpD,QAAM,YAAY,cAAc,IAAI,aAAa,IAAI,SAAS;AAK9D,QAAM,OAAOG,SAAQ,MAAM,WAAW,OAAO,GAAG,CAAC,YAAY,OAAO,CAAC;AAGrE,QAAM,WAAW,IAAI;AAMrB,QAAM,gBACJ,YAAY,OACX,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,QAAQ,KAAK,MAAM,EAAE,KACjE;AACJ,QAAM,qBAAqBC,SAAuB,IAAI;AAEtD,QAAM,gBAAgBA,SAAsB,IAAI;AAChD,QAAM,aAAaA,SAAsB,IAAI;AAC7C,MAAI,aAAa,aAAa,CAAC,iBAAiB,cAAc,YAAY,MAAM;AAC9E,kBAAc,UAAU,YAAY,IAAI;AAAA,EAC1C;AACA,MACE,iBACA,cAAc,YAAY,QAC1B,WAAW,YAAY,MACvB;AACA,eAAW,UAAU,YAAY,IAAI,IAAI,cAAc;AAAA,EACzD;AACA,EAAAC,YAAU,MAAM;AACd,UAAM,KAAK,mBAAmB;AAC9B,QAAI,MAAM,aAAa,CAAC,cAAe,IAAG,YAAY,GAAG;AAAA,EAC3D,GAAG,CAAC,WAAW,WAAW,aAAa,CAAC;AAGxC,QAAM,kBAAkB;AAAA,IACtB,aAAa,CAAC,CAAC,aAAa,CAAC;AAAA,EAC/B;AAEA,QAAM,QAAQ,WAAW;AACzB,SACE,gBAAAJ,OAAC,SAAI,WAAW,iCAAiC,QAAQ,oBAAoB,MAAM,IAChF;AAAA,KAAC,SACA,gBAAAA,OAAC,SAAI,WAAU,kFACb;AAAA,sBAAAD,MAAC,UAAK,WAAU,2BAA2B,sBAAW;AAAA,MACrD,IAAI,aAAa,gBAAAA,MAAC,UAAK,WAAU,yBAAyB,cAAI,WAAU;AAAA,MACxE,sBAAsB,GAAG,KAAK,gBAAAA,MAAC,UAAM,gCAAsB,GAAG,GAAE;AAAA,MAChE,gBAAgB,KAAK,MAAM,KAAK,gBAAAA,MAAC,UAAM,0BAAgB,KAAK,MAAM,GAAE;AAAA,OACvE;AAAA,IAED,aACC,gBAAAC,OAAC,aAAQ,WAAU,mEAAkE,MAAM,CAAC,eAC1F;AAAA,sBAAAD,MAAC,aAAQ,WAAU,wEAChB,WAAC,gBACA,gBAAAC,OAAC,UAAK,WAAU,iBAAgB;AAAA;AAAA,QACrB,mBAAmB,IAAI,SAAM,eAAe,MAAM;AAAA,SAC7D,IACE,WAAW,WAAW,OACxB,eAAe,KAAK,IAAI,GAAG,KAAK,MAAM,WAAW,UAAU,GAAI,CAAC,CAAC,MAEjE,mBAEJ;AAAA,MACA,gBAAAD,MAAC,SAAI,KAAK,oBAAoB,WAAU,uGACrC,qBACH;AAAA,OACF;AAAA,IAED,YAAY,SAAS,SAAS,IAC7B,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF,IAEA,gBAAAC,OAAAF,WAAA,EACE;AAAA,sBAAAE,OAAC,SAAI,WAAW,kBACb;AAAA;AAAA,QACA,aAAa,WAAW,CAAC,IAAI,WAAW,UAAU,gBAAAD,MAAC,kBAAe;AAAA,SACrE;AAAA,MACC,IAAI,aAAa,IAAI,UAAU,SAAS,KACvC,gBAAAA,MAAC,SAAI,WAAU,8BACZ,cAAI,UAAU,IAAI,CAAC,OAClB,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAEC,MAAM;AAAA,UACN,SAAS;AAAA,UACT;AAAA,UACA,WAAW;AAAA,UACX,WAAW;AAAA;AAAA,QALN,GAAG;AAAA,MAMV,CACD,GACH;AAAA,OAEJ;AAAA,IAED,gBAAgB,IAAI,SACnB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,OAAO,IAAI;AAAA,QACX,gBAAgB;AAAA,QAChB,WAAU;AAAA;AAAA,IACZ;AAAA,IAED,oBACC,iCAAiC,IAAI,KAAK,EAAE,IAAI,CAAC,SAC/C,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEC;AAAA,QACA,QAAQ,iBAAiB;AAAA,QACzB,WAAU;AAAA;AAAA,MAHL,GAAG,KAAK,IAAI,EAAE,IAAI,KAAK,IAAI,OAAO;AAAA,IAIzC,CACD;AAAA,IACF,eAAe,GAAG;AAAA,IAClB,wBAAwB,gCAAgC,IAAI,KAAK,EAAE,SAAS,KAC3E,gBAAAA,MAAC,SAAI,WAAU,QACb,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,gCAAgC,IAAI,KAAK;AAAA,QAChD,gBAAgB;AAAA,QAChB,SAAQ;AAAA;AAAA,IACV,GACF;AAAA,IAED,SACC,gBAAAC,OAAC,SAAI,eAAY,qBAAoB,WAAW,uBAC9C;AAAA,sBAAAD,MAAC,qBAAkB,MAAM,WAAW,GAAG,GAAG;AAAA,MACzC,IAAI,aAAa,gBAAAA,MAAC,UAAK,WAAU,aAAa,cAAI,WAAU;AAAA,MAC5D,sBAAsB,GAAG,KAAK,gBAAAA,MAAC,UAAM,gCAAsB,GAAG,GAAE;AAAA,MAChE,gBAAgB,KAAK,MAAM,KAAK,gBAAAA,MAAC,UAAM,0BAAgB,KAAK,MAAM,GAAE;AAAA,OACvE;AAAA,KAEJ;AAEJ;AASA,IAAM,mBAAmB,KAAK,oBAAoB;AAM3C,SAAS,mBAAmB,QAAyB;AAC1D,QAAM,CAAC,SAAS,UAAU,IAAIE,WAAS,CAAC;AACxC,EAAAG,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AAGb,eAAW,CAAC;AACZ,UAAM,KAAK,YAAY,MAAM,WAAW,CAAC,MAAM,IAAI,CAAC,GAAG,GAAI;AAC3D,WAAO,MAAM,cAAc,EAAE;AAAA,EAC/B,GAAG,CAAC,MAAM,CAAC;AACX,SAAO;AACT;AAEA,SAAS,YAAY,EAAE,YAAY,SAAS,UAAU,GAAyD;AAC7G,QAAM,UAAU,mBAAmB,IAAI;AACvC,SACE,gBAAAJ,OAAC,SAAI,WAAU,sCACZ;AAAA,eAAW,WACV,gBAAAD,MAAC,OAAE,WAAU,gFAAgF,sBAAW;AAAA,IAE1G,gBAAAC,OAAC,SAAI,WAAU,2DACb;AAAA,sBAAAD,MAAC,SAAI,WAAU,wBAAuB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAW,MACrH,0BAAAA,MAAC,UAAK,GAAE,+BAA8B,eAAc,SAAQ,GAC9D;AAAA,MAAM;AAAA,MACG,WAAW,IAAI,SAAM,OAAO,MAAM;AAAA,OAC7C;AAAA,KACF;AAEJ;AAIA,SAAS,eAAe,EAAE,SAAS,QAAQ,GAA8C;AACvF,SACE,gBAAAA,MAAC,SAAI,WAAU,sCACb,0BAAAC,OAAC,SAAI,MAAK,SAAQ,WAAU,0HAC1B;AAAA,oBAAAA,OAAC,SAAI,WAAU,2BAA0B,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACrK;AAAA,sBAAAD,MAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,MAC9B,gBAAAA,MAAC,UAAK,GAAE,mBAAkB;AAAA,OAC5B;AAAA,IACA,gBAAAA,MAAC,UAAK,WAAU,8BAA8B,mBAAQ;AAAA,IACrD,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,WAAW,iJAAiJ,oBAAoB;AAAA,QACjL;AAAA;AAAA,IAED;AAAA,KAEJ,GACF;AAEJ;AASO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA,cAAc;AAAA,EACd,SAAS;AAAA,EACT,SAAS,CAAC;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAsB;AACpB,QAAM,mBACJ,gBAAgB,UACZ,sDACA;AAKN,QAAM,aAAaG;AAAA,IACjB,MAAM,mBAAmB,CAAC,YAAoB,gBAAAH,MAAC,OAAE,WAAU,uBAAuB,mBAAQ;AAAA,IAC1F,CAAC,cAAc;AAAA,EACjB;AACA,QAAM,aAAa,SAAS,SAAS,SAAS,CAAC,GAAG,SAAS;AAC3D,QAAM,QAAQ,WAAW;AACzB,MAAI,SAAS,WAAW,KAAK,CAAC,WAAW,CAAC,OAAO;AAG/C,UAAM,QAAQ,cAAc,YAAY,IAAI,gBAAAA,MAAC,kBAAgB,GAAG,YAAY;AAC5E,WACE,gBAAAC,OAAAF,WAAA,EACG;AAAA;AAAA,MACA;AAAA,OACH;AAAA,EAEJ;AACA,SACE,gBAAAE,OAAAF,WAAA,EACG;AAAA;AAAA,IACA,SAAS;AAAA,MAAI,CAAC,QACb,IAAI,SAAS,SACX,gBAAAE,OAAC,SAAiB,WAAW,iCAAiC,QAAQ,oBAAoB,MAAM,IAC9F;AAAA,wBAAAA,OAAC,SAAI,WAAW,iBAAiB,QAAQ,gBAAgB,aAAa,IACnE;AAAA,WAAC,SACA,gBAAAD,MAAC,OAAE,WAAU,2FACV,qBACH;AAAA,UAEF,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WACE,QACI,oGAAoG,gBAAgB,KACpH,uDAAuD,gBAAgB;AAAA,cAG7E,0BAAAA,MAAC,OAAE,WAAU,uBAAuB,cAAI,SAAQ;AAAA;AAAA,UAClD;AAAA,UACC,wBAAwB,gCAAgC,IAAI,KAAK,EAAE,SAAS,KAC3E,gBAAAA,MAAC,SAAI,WAAU,UACb,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO,gCAAgC,IAAI,KAAK;AAAA,cAChD,gBAAgB;AAAA,cAChB,SAAQ;AAAA;AAAA,UACV,GACF;AAAA,WAEJ;AAAA,QACC,SACC,gBAAAA,MAAC,SAAI,eAAY,qBAAoB,WAAW,GAAG,qBAAqB,gBACtE,0BAAAA,MAAC,qBAAkB,MAAM,IAAI,SAAS,GACxC;AAAA,WA7BM,IAAI,EA+Bd,IAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA,WAAW,CAAC,CAAC,WAAW,IAAI,OAAO,SAAS,SAAS,SAAS,CAAC,GAAG;AAAA,UAClE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,QAdK,IAAI;AAAA,MAeX;AAAA,IAEJ;AAAA,IACC,WAAW,cAAc,gBAAAA,MAAC,eAAY,YAAwB,QAAgB;AAAA,IAC9E,SAAS,CAAC,WAAW,gBAAAA,MAAC,kBAAe,SAAS,OAAO,SAAkB;AAAA,KAC1E;AAEJ;","names":["useEffect","useMemo","useRef","useState","useEffect","useState","useEffect","useRef","useState","jsx","useState","useRef","useEffect","jsx","jsxs","useState","useEffect","useMemo","useRef","useState","jsx","jsxs","CheckGlyph","STATUS_LABELS","TERMINAL_NOTES","useState","useRef","useMemo","jsx","useEffect","useState","jsx","jsxs","useState","useEffect","parsed","useCallback","useEffect","useRef","useState","Fragment","jsx","jsxs","useCallback","useEffect","useRef","useState","useCallback","useMemo","useState","next","useState","useCallback","useMemo","useCallback","useMemo","useRef","useState","useCallback","useEffect","useState","Fragment","jsx","jsxs","useState","useCallback","useEffect","useCallback","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useCallback","useEffect","Fragment","jsx","jsxs","CheckGlyph","useCallback","useEffect","useId","useMemo","useRef","useState","Fragment","jsx","jsxs","useState","useCallback","useRef","useEffect","useMemo","useId","Fragment","useCallback","useEffect","useId","useMemo","useRef","useState","custom","jsx","jsxs","BASIS_TONES","useId","useState","useRef","useCallback","useEffect","useMemo","Fragment","Fragment","jsx","jsxs","useState","useMemo","useRef","useEffect"]}
|